【问题标题】:Row concatenation with FOR XML, but with multiple columns?使用 FOR XML 进行行连接,但使用多列?
【发布时间】:2011-10-13 03:09:50
【问题描述】:

我经常使用这样的查询:

SELECT *
FROM   ThisTable
       OUTER APPLY (SELECT (SELECT SomeField + ' ' AS [data()]
                            FROM   SomeTable
                            WHERE  SomeTable.ID = ThisTable.ID
                            FOR XML PATH ('')) AS ConcatenatedSomeField) A 

我经常想从该表中获取多个连接的连接字段,而不仅仅是一个。我可以在逻辑上这样做:

SELECT *
FROM   ThisTable
       OUTER APPLY (SELECT (SELECT SomeField + ' ' AS [data()]
                            FROM   SomeTable
                            WHERE  SomeTable.ID = ThisTable.ID
                            FOR XML PATH ('')) AS ConcatenatedSomeField) A
       OUTER APPLY (SELECT (SELECT SomeField2 + ' ' AS [data()]
                            FROM   SomeTable
                            WHERE  SomeTable.ID = ThisTable.ID
                            FOR XML PATH ('')) AS ConcatenatedSomeField2) B
       OUTER APPLY (SELECT (SELECT SomeField3 + ' ' AS [data()]
                            FROM   SomeTable
                            WHERE  SomeTable.ID = ThisTable.ID
                            FOR XML PATH ('')) AS ConcatenatedSomeField3) C 

但是当需要更新任何内容时,它看起来很糟糕且容易出错; SomeTable 通常是一个很长的连接表列表,因此它也可能对性能产生影响,一遍又一遍地获取相同的表。

有没有更好的方法来做到这一点?

谢谢。

【问题讨论】:

    标签: tsql sql-server-2008


    【解决方案1】:

    你可以做这样的事情。此查询不是立即将 XML 值发送到字符串,而是使用 TYPE 关键字返回一个 xml 类型对象,然后可以对其进行查询。这三个查询函数在 xml 对象中搜索 Somefield 元素的所有实例,并返回一个仅包含这些值的新 xml 对象。然后 value 函数将值周围的 xml 标签去掉,并将它们传递给 varchar(max)

    SELECT  ThisTable.ID
           ,[A].query('/Somefield').value('/', 'varchar(max)') AS [SomeField_Combined]
           ,[A].query('/Somefield2').value('/', 'varchar(max)') AS [SomeField2_Combined]
           ,[A].query('/Somefield3').value('/', 'varchar(max)') AS [SomeField3_Combined]
    FROM    ThisTable
            OUTER APPLY (
                         SELECT (
                                 SELECT SomeField + ' ' AS [SomeField]
                                       ,SomeField2 + ' ' AS [SomeField2]
                                       ,SomeField3 + ' ' AS [SomeField3]
                                 FROM   SomeTable
                                 WHERE  SomeTable.ID = ThisTable.ID
                                FOR
                                 XML PATH('')
                                    ,TYPE
                                ) AS [A]
                        ) [A]
    

    【讨论】:

      【解决方案2】:

      您可以创建一个 CLR User-Defined Aggregate Function 来为您进行连接。

      您的代码将改为如下所示。

      select S.ID,
             dbo.Concat(S.SomeField1), 
             dbo.Concat(S.SomeField2),
             dbo.Concat(S.SomeField3)
      from SomeTable as S
      group by S.ID
      

      【讨论】:

        【解决方案3】:

        这与我在这里给出的答案相同:https://dba.stackexchange.com/questions/125771/multiple-column-concatenation/

        该问题的 OP 引用了此处给出的答案。您可以在下面看到,有时最简单的答案可能是最好的。如果 SomeTable 是多个表,那么我会继续将其放入 CTE 以避免多次使用相同的复杂代码。

        我使用超过 600 万行进行了一些测试。在 ID 列上有一个索引。

        这是我想出的。

        您的初始查询:

        SELECT * FROM (
            SELECT t.id,
                    stuff([M].query('/name').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined1],
                    stuff([M].query('/car').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined2]
            FROM dbo.test t
            OUTER APPLY(SELECT (
                            SELECT id, ','+name AS name
                            ,','+car AS car
                            FROM test WHERE test.id=t.id
                            FOR XML PATH('') ,type)
                         AS  M) 
                    M ) S
        GROUP BY id, SomeField_Combined1, SomeField_Combined2 
        

        这个跑了大约 23 分钟。

        我运行了这个版本,这是我第一次学习的版本。在某些方面,它看起来应该需要更长的时间,但事实并非如此。

        SELECT test.id,
            STUFF((SELECT ', ' + name
                    FROM   test ThisTable
                    WHERE  test.id = ThisTable.id
                    FOR XML PATH ('')),1,2,'') AS ConcatenatedSomeField,
            STUFF((SELECT ', ' + car
                    FROM   test ThisTable
                    WHERE  test.id = ThisTable.id
                    FOR XML PATH ('')),1,2,'') AS ConcatenatedSomeField2
        FROM test 
        GROUP BY id
        

        这个版本只用了 2 多分钟。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-07
          相关资源
          最近更新 更多