我有一个表,其中我有多个位列,如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
由于
答案 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 |
+----+------+------+------+