SQL - 逗号在其自己的列中定界多列的子集结果

时间:2017-11-02 14:46:07

标签: sql-server tsql

我有一个联合所有表的视图,一个人可能属于一个或多个表。 我如何创建一个将添加';'列的查询在该人所属的地方划定,该ID是每人独一无二的。 这是示例

--table1
PID  fName  tableMem
1    test   group1
2    test2  group1

--table2
PID  fName  tableMem
1    test   group2
3    test3  group2

--table3
PID  fName  tableMem
1    test   group3
3    test3  group3

这是我想要的输出

--compiled table after union of all the 3 tables
PID  fname  tableMem 
1    test   group1;group2;group3
2    test2  group1
3    test3  group2;group3

以下是我在过去2天阅读时构建的查询。我正在使用STUFF和分区,因为我需要将行分开,此查询将作为视图运行。

SELECT * 
FROM
    (SELECT 
         *,
         ROW_NUMBER() OVER(PARTITION BY PIP ORDER BY Fname) AS rownum
     FROM 
         (SELECT 
              *,
              STUFF((SELECT ';'+ di.tablemem
                     FROM DPI di  <<-- alias table from union
                     WHERE DPI.PID = di.PID
                     FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') tablemem
          FROM
              (SELECT * 
               FROM
                   (--table1
                    SELECT 'group1' AS tableMem, * FROM table1
                    UNION ALL
                    --table2
                    SELECT 'group2' AS tableMem, * FROM table2
                    UNION ALL
                    --table3
                    SELECT 'group3' AS tableMem, * FROM table3) AS DPI <<--alias table name
              ) AS innertable
         ) AS distinctTable 
    ) AS outerTable
WHERE
    rownum = 1

我错过了什么或查询有什么问题。我猜它是因为我使用了union sub select的派生表名。有什么解决方法吗?

提前谢谢

4 个答案:

答案 0 :(得分:1)

GROUP BY需要PID, fName个数据,使用FOR XML聚合

WITH DPI AS (
    --table1
    Select 'group1' as tableMem,* from table1

    UNION ALL

    --table2
    Select 'group2' as tableMem,* from table2

    UNION ALL

    --table3
    Select 'group3' as tableMem,* from table3
)
SELECT PID, fName
    , STUFF((
            SELECT ';'+ di.tablemem
            FROM DPI di  
            WHERE di.PID = di1.PID
            FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'') tablemem
FROM DPI di1
GROUP BY PID, fName;

答案 1 :(得分:1)

以下是使用CTE的可能解决方案:

;with cte as (
    select * from @tbl1
    union all
    select * from @tbl2
    union all
    select * from @tbl3
)
select distinct
    pid
    ,fname
    ,stuff(
        (select '; ' + tableMem
        from cte
        where pid = a.pid
            and fname = a.fname
        FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'') as tableMem 
from cte a

答案 2 :(得分:0)

鉴于您拥有有限数量的表,我认为我发现这更简单:

select p.pid, p.fname,
       trim(';' from
             (case when t1.pid is not null then 'group1;' else '' end) +
             (case when t2.pid is not null then 'group2;' else '' end) +
             (case when t3.pid is not null then 'group3;' else '' end)
           ) as groups
from (select pid, fname from table1 union  -- on purpose to remove duplicates
      select pid, fname from table2 union
      select pid, fname from table3
     ) p left join
     table1 t1
     on t1.pid = p.pid left join
     table2 t2
     on t2.pid = p.pid left join
     table3 t3
     on t3.pid = p.pid;

最新版本的SQL Server支持string_agg(),这会使这更简单。

答案 3 :(得分:0)

试试这个:

DECLARE @table1 TABLE
(
    [PID] TINYINT
   ,[fname] VARCHAR(12)
   ,[tableMem] VARCHAR(12)
);

DECLARE @table2 TABLE
(
    [PID] TINYINT
   ,[fname] VARCHAR(12)
   ,[tableMem] VARCHAR(12)
);

DECLARE @table3 TABLE
(
    [PID] TINYINT
   ,[fname] VARCHAR(12)
   ,[tableMem] VARCHAR(12)
);

INSERT INTO @table1 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group1')
      ,(2, 'test2', 'group1');

INSERT INTO @table2 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group2')
      ,(3, 'test3  ', 'group2');

INSERT INTO @table3 ([PID], [fname], [tableMem])
VALUES (1, 'test', 'group3')
      ,(3, 'test3  ', 'group3');


WITH DataSource AS
(
    SELECT *
    FROM @table1
    UNION ALL
    SELECT *
    FROM @table2
    UNION ALL
    SELECT *
    FROM @table3
)
SELECT DISTINCT DS.[PID]
               ,DS.fname
               ,CSVvalue.[tableMem]
FROM DataSource DS
CROSS APPLY
(   
    SELECT STUFF
    (
        (
            SELECT ',' + DS1.[tableMem]
            FROM DataSource DS1
            WHERE DS.[PID] = DS1.[PID]
                AND DS.[fname] = DS1.[fname]
            ORDER BY DS1.[tableMem]
            FOR XML PATH(''), TYPE
        ).value('.', 'VARCHAR(MAX)')
        ,1
        ,1
        ,''
    )
) CSVvalue ([tableMem]);