使用sql填充函数折叠行

时间:2019-05-22 06:51:30

标签: sql sql-server sql-server-2014

我的sql数据库中有三个表,我正尝试使用3个表中的填充函数折叠sql server中的行

我尝试进行内部联接,但尝试进行外部联接,但未获得预期的结果 我的代码在下面:

select T1.Id, 
       T1.Name,
       T2.Id,
       T2.T1_Id,
       T2.Name,
       stuff(
       (
           select ','+T3.Name 
           from Test3 T3 
           where T3.Id=T2.T3_Id for xml path('')
       ),1,1,'') as Test5
from Test1 T1,Test2 T2 
where T1.Id=T2.T1_Id

我得到了类似的结果

Id  Name    Id  T1_Id   Name    Test5
----------------------------------------------
1   Test1   1    1      ASD      BAAN
1   Test1   2    1      ASD      KAAL

预期

Id  Name    Id  T1_Id   Name    Test5
1   Test1   1     1      ASD  BAAN,KAAL

我的表脚本和示例数据是,我正在使用sql server 2014

   CREATE TABLE [dbo].[Test1](
        [Id] [int] NULL,
        [Name] [varchar](50) NULL
    ) ON [PRIMARY]
    GO

   INSERT INTO [dbo].[Test1]
           ([Id]
           ,[Name])
     VALUES
           (1
           ,'Test1')
           GO

    CREATE TABLE [dbo].[Test2](
        [Id] [int] NOT NULL,
        [T1_Id] [int] NOT NULL,
        [T3_Id] [int] NOT NULL,
        [Name] [varchar](50) NULL
    ) ON [PRIMARY]


    INSERT INTO [dbo].[Test2]
           ([Id]
           ,[T1_Id]
           ,[T3_Id]
           ,[Name])
     VALUES
           (1
           ,1
           ,1
           ,'ASD'),(2,1,2,'ASD')
           GO


    CREATE TABLE [dbo].[Test3](
        [Id] [int] NULL,
        [Name] [varchar](50) NULL
    ) ON [PRIMARY]

    GO

   INSERT INTO [dbo].[Test3]
           ([Id]
           ,[Name])
     VALUES
           (1
           ,'KAAL'),(2,'BAAL')
           Go

4 个答案:

答案 0 :(得分:2)

SQL语言中没有“ COLLAPSE”。您发布的内容将显示分组和汇总。对于字符串,唯一有意义的聚合是MIN,MAX和字符串串联。

SQL Server 2017通过STRING_AGG函数提供字符串连接。其他数据库产品使用不同的名称,例如GROUP_CONCAT。在早期的SQL Server版本中,使用了各种技术来执行相同的操作。您发布的是XML技术。

查询中没有GROUP BY子句,这就是为什么返回多行的原因。

在SQL Server 2017中,查询将如下所示:

select T1.Id, 
       T1.Name,
       MIN(T2.Id) as T2_ID,
       MIN(T2.T1_Id) as T1_ID,
       MIN(T2.Name) as T2_Name,
       STRING_AGG(T3.Name,', ') as Test5
from @Test1 T1 
    inner join @Test2 T2 on T1.Id=T2.T1_Id
    inner join @Test3 T3 on T3.Id=T2.T3_Id 
GROUP BY T1.ID,T1.Name

在早期版本中执行相同操作比较麻烦。 FOR XML查询只能与GROUP BY子句中出现的列相关:

select T1.Id, 
       T1.Name,
       MIN(T2.Id),
       MIN(T2.T1_Id),
       MIN(T2.Name),
       stuff(
       (
           SELECT ','+T3.Name 
           FROM @Test3 T3 
              inner join @Test2 TT2 on T3.Id=TT2.T3_Id
           WHERE TT2.T1_ID=T1.Id 
           FOR XML PATH('')
       ),1,1,'') as Test5
from @Test1 T1 
    inner join @Test2 T2 on T1.Id=T2.T1_Id
GROUP BY T1.ID,T1.Name

将整个STUFF(... FOR XML)..部分作为单个函数考虑,该函数以WHERE子句中分组列之一作为参数,搜索一些表并连接字符串结果。

这意味着相关子句

WHERE TT2.T1_ID=T1.Id 

只能引用外部查询中的分组列。我们需要在那里加入T2,因为我们无法直接从T3进入T1.ID

如果您不关心T2列,则可以摆脱外部查询中的JOIN:

select T1.Id, 
       T1.Name,
       stuff(
       (
           select ','+T3.Name 
           from @Test3 T3 
              inner join @Test2 TT2 on T3.Id=TT2.T3_Id
              where TT2.T1_ID=T1.Id for xml path('')
       ),1,1,'') as Test5
from @Test1 T1 
GROUP BY T1.ID,T1.Name

答案 1 :(得分:1)

尝试一下

;WITH CTE AS 
(
SELECT T1.Id AS T1_Id,
       T1.Name AS T1_Name,
       T2.Id  AS  T2_Id,
       T2.T1_Id AS T2_T1_Id,
       T2.Name AS T2_Name, 
       T3.Name AS Test5
FROM [Test2] t2
    INNER JOIN [Test1] t1
ON t1.Id = t2.T1_Id
    INNER JOIN [Test3] t3
ON t3.id = t2.T3_Id
)
SELECT  T1_Id,  
        T1_Name,            
        T2_T1_Id,   
        T2_Name,    
        STUFF((SELECT  ', '+Test5 
                FROM CTE i WHERE i.T1_Id = o.T1_Id 
                FOR XML PATH ('')),1,1,'') AS Test5
FROM CTE o
GROUP BY T1_Id, 
        T1_Name,            
        T2_T1_Id,   
        T2_Name

答案 2 :(得分:1)

如果您不关心Test2.Name,则可以得到如下结果:

WITH tblMain as (SELECT T1.Id,T1.Name, T3.Name T3Name
                 FROM Test2 T2 LEFT OUTER JOIN
                 Test1 T1 on T2.T1_Id = T1.Id LEFT OUTER JOIN
                 Test3 T3 on T2.T3_Id = T3.Id)

SELECT Id, Name, 
    STUFF((SELECT ', ' + T3Name
           FROM tblMain b 
           WHERE b.Id = a.Id AND b.Name = a.Name 
           FOR XML PATH('')), 1, 2, '') as Test5
FROM tblMain a
GROUP BY Id, Name

否则,如果要从Test2中获取其他列,也应将它们添加到GROUP BY子句中。

答案 3 :(得分:0)

尝试以下脚本。

注意:您必须避免从Test2和Test3获得ID,否则您不能为STUFF应用GROUP BY,因为它们在ID列中具有不同的值。

SELECT *,
STUFF
(
    (
        SELECT ',' + Name 
        FROM
        (
            SELECT T3.Name
            FROM Test1 T1 
            INNER JOIN Test2 T2 ON T1.Id = T2.T1_Id
            INNER JOIN Test3 T3 ON T2.T3_Id = T3.ID
        ) B
        FOR XML PATH ('')
    ), 1, 1, ''
) Test5
FROM
(
    SELECT T1.Id,T1.Name T1_Name,T2.Name T2_Name
    FROM Test1 T1 
    INNER JOIN Test2 T2 ON T1.Id = T2.T1_Id
)A  
GROUP BY A.Id,A.T1_Name,A.T2_Name