在sql select query中根据多位值得到逗号分隔的字符串

时间:2017-01-11 07:05:55

标签: sql sql-server sql-server-2008

我有一个表,其中我有多个位列,如LH1,LH2,LH3,RH1, RH2,RH3。 (这只是示例,在原始数据库中我有20位以上的列.LH表示左手,RH表示右手。同样的方式我有右眼,左眼,右脚,左脚等)

现在根据这些比特值,我想得到一个逗号分隔的字符串。

For Exapmle iF LH1,RH1,RH2 and LH3 are true then I want '1,3' as LH and '1,2' as RH.

IF LH3,RH1,RH2 and RH3 are true then I want '1' as LH and '1,2,3' as RH.

我查看了以下链接,但在我的情况下它没有用

https://dba.stackexchange.com/questions/112408/join-with-comma-separated-values-in-sql-server

由于

2 个答案:

答案 0 :(得分:1)

你的设计并不好......每当你发现需要添加像<{1}}这样的编号的列时,这就会呼唤相关的子表!但是,您可以动态创建适当的语句:

此表模拟你的表

LH1, LH2,LH3

你需要的陈述是:

CREATE TABLE Dummy(ID INT IDENTITY,ControlString VARCHAR(100),LH1 BIT,LH2 BIT,LH3 BIT,RH1 BIT,RH2 BIT);
INSERT INTO Dummy VALUES
 ('All True',1,1,1,1,1) 
,('All LH True',1,1,1,0,0) 
,('All RH True',0,0,0,1,1)
,('LH1 and RH1',1,0,0,1,0)
,('LH2,3 and RH1,2',0,1,1,1,1);
GO

- 我将使用元数据查找所有列的名称并在字符串基础上创建语句:

SELECT ID
      ,ControlString
      ,CASE WHEN LH1=1 THEN ',1' ELSE '' END+CASE WHEN LH2=1 THEN ',2' ELSE '' END+CASE WHEN LH3=1 THEN ',3' ELSE '' END AS [LH]
      ,CASE WHEN RH1=1 THEN ',1' ELSE '' END+CASE WHEN RH2=1 THEN ',2' ELSE '' END AS [RH] 
FROM Dummy

- 清理

DECLARE @cmd AS VARCHAR(MAX);
WITH AllColumns AS
(
    SELECT LEFT(COLUMN_NAME,2) AS Location
          ,SUBSTRING(COLUMN_NAME,3,1000) AS Indx
          ,COLUMN_NAME
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='Dummy' AND LEN(COLUMN_NAME)=3
)
SELECT @cmd='SELECT ID,ControlString,' + STUFF(
(
     SELECT ',' + STUFF(
                        ((SELECT '+CASE WHEN ' + grp.COLUMN_NAME + '=1 THEN '',' + grp.Indx + ''' ELSE '''' END' 
                          FROM AllColumns AS grp 
                          WHERE grp.Location=AllColumns.Location 
                          FOR XML PATH('')) + ' AS ' + QUOTENAME(Location)
                        ),1,1,''
                       )
     FROM AllColumns
     GROUP BY Location
     FOR XML PATH('')
    ),1,1,''
) + ' FROM Dummy';

EXEC( @cmd);
GO

结果

DROP TABLE Dummy; 

答案 1 :(得分:0)

您的数据结构ID“反规范化”(或“旋转”),这使得后续处理更加困难。因此,第一步是“规范化”(或“忽略”)数据,这使得后续步骤更简单。

没有必要使用“unpivot”命令来执行此操作:在SQL Server中,我更喜欢使用CROSS APPLY和VALUES来实现第一部分(在下面的CTE中)。然后是使用“FOR XML PATH”和STUFF()来实现逗号分隔的字符串。

来自以下示例数据:

CREATE TABLE Table1
    ([id] int, [lh1] bit, [lh2] bit, [lh3] bit, [lh4] bit, [rh1] bit, [rh2] bit, [rh3] bit, [rh4] bit)
;

INSERT INTO Table1
    ([id], [lh1], [lh2], [lh3], [lh4], [rh1], [rh2], [rh3], [rh4])
VALUES
    (1001, 1, 0, 0, 0, 0, 0, 1, 0),
    (1002, 0, 1, 0, 0, 1, 0, 0, 0),
    (1003, 0, 0, 1, 0, 0, 1, 0, 0),
    (1004, 0, 1, 0, 1, 0, 0, 1, 0),
    (1005, 1, 0, 1, 0, 0, 1, 0, 1),
    (1006, 0, 0, 0, 0, 1, 0, 1, 0),
    (1007, 1, 0, 0, 1, 0, 0, 0, 0),
    (1008, 0, 1, 1, 0, 1, 0, 0, 1)
;

然后是这个查询:

;with CTE as (
        select
                id, ca.colname, colvalue
        from table1
        cross apply (
              values
                    ('lh1',case when lh1 = 1 then 1 end)
                  , ('lh2',case when lh2 = 1 then 2 end)
                  , ('lh3',case when lh3 = 1 then 3 end)
                  , ('lh4',case when lh4 = 1 then 4 end)
                  , ('rh1',case when rh1 = 1 then 1 end)
                  , ('rh2',case when rh2 = 1 then 2 end)
                  , ('rh3',case when rh3 = 1 then 3 end)
                  , ('rh4',case when rh4 = 1 then 4 end)
             ) ca (colname, colvalue)
         where ca.colvalue IS NOT NULL
        ) 
SELECT
  t.id, l.h as lh, r.h as rh
FROM table1 t
CROSS APPLY (SELECT
      STUFF((SELECT
        ',' + CAST(cte.colvalue AS char(1))
      FROM cte
      WHERE t.id = cte.id
      AND cte.colname like 'lh%'
      ORDER BY cte.colname
      FOR xml PATH (''))
      , 1, 1, '')) AS l (h) 
CROSS APPLY (SELECT
      STUFF((SELECT
        ',' + CAST(cte.colvalue AS char(1))
      FROM cte
      WHERE t.id = cte.id
      AND cte.colname like 'rh%'
      ORDER BY cte.colname
      FOR xml PATH (''))
      , 1, 1, '')) AS r (h) 


         select
                id, ca.colname, colvalue
        from table1
        cross apply (
              values
                    ('lh1',case when lh1 = 1 then 1 end)
                  , ('lh2',case when lh2 = 1 then 2 end)
                  , ('lh3',case when lh3 = 1 then 3 end)
                  , ('lh4',case when lh4 = 1 then 4 end)
                  , ('rh1',case when rh1 = 1 then 1 end)
                  , ('rh2',case when rh2 = 1 then 2 end)
                  , ('rh3',case when rh3 = 1 then 3 end)
                  , ('rh4',case when rh4 = 1 then 4 end)
             ) ca (colname, colvalue)
         where ca.colvalue IS NOT NULL
         order by id, colname, colvalue

你得到这个结果:

+----+------+------+------+
|    |  id  |  lh  |  rh  |
+----+------+------+------+
|  1 | 1001 | 1    | 3    |
|  2 | 1002 | 2    | 1    |
|  3 | 1003 | 3    | 2    |
|  4 | 1004 | 2,4  | 3    |
|  5 | 1005 | 1,3  | 2,4  |
|  6 | 1006 | NULL | 1,3  |
|  7 | 1007 | 1,4  | NULL |
|  8 | 1008 | 2,3  | 1,4  |
+----+------+------+------+