【问题标题】:Concatenating columns using CTE in SQL Server 2008在 SQL Server 2008 中使用 CTE 连接列
【发布时间】:2013-06-11 12:15:40
【问题描述】:

我有一张这样的桌子

TABLEX-

+------+------------+
| NAME | TABLE_NAME |
+------+------------+
| X1   | X001       |
| X2   | X002       |
+------+------------+

这个表包含一个 name 列,它只是描述和一个 table_name 列,它实际上是一个已经存在于数据库中的表。

X001 表中有 X1_A, X1_B 之类的列
X002 表中有 X2_A, X2_B 之类的列

现在我想以逗号分隔的字符串连接TABLE_NAME 列中实际表中的所有列,并将其显示为一列。

+------+------------+------------+
| NAME | TABLE_NAME |  COLUMNS   |
+------+------------+------------+
| X1   | X001       | X1_A, X1_B |
| X2   | X002       | X2_A, X2_B |
+------+------------+------------+

现在可以使用 CTE 来实现。我已经使用STUFFXML PATH 成功创建了查询,但是我遇到了性能问题,因为我在上面显示的表中有大约 200 行奇数行,并且每个链接的后续表每个都有 100 列.

编辑 -

SELECT 
P.NAME,
P.TABLE_NAME,
[COLUMNS]=(SELECT STUFF((SELECT ',' + NAME FROM sys.syscolumns WHERE ID = OBJECT_ID(P.TABLE_NAME) ORDER BY colorder FOR XML PATH('') ), 1, 1,''))
FROM TABLEX P 

TABLEX 是上面发布的表格。

【问题讨论】:

  • 你能发布你现有的代码吗?为什么需要连接 100 列数据?
  • @bluefeet 我认为他们只想要一个以逗号分隔的列名列表。
  • @wagregg 包含表名列表的表有 200 行。我会避开INFORMATION_SCHEMA.COLUMNS 并使用sys.columns 以获得更好的性能。
  • @MartinSmith 可能是真的,这就是为什么我要求查看他们的实际代码,以便清楚他们连接的内容。
  • 每个表中有 200 个表和 100 个列,for xml 查询在我的计算机上需要 100 毫秒,而在 SQL Fiddle 中需要将近 1 秒。这可能是什么原因让你执行得这么慢? sys.syscolumns 中有多少行?

标签: sql-server tsql sql-server-2008-r2 common-table-expression


【解决方案1】:

试试这个 -

DDL:

IF OBJECT_ID (N'dbo.TABLEX') IS NOT NULL
   DROP TABLE TABLEX

IF OBJECT_ID (N'dbo.X001') IS NOT NULL
   DROP TABLE X001

IF OBJECT_ID (N'dbo.X002') IS NOT NULL
   DROP TABLE X002

CREATE TABLE dbo.TABLEX (NAME VARCHAR(50), TABLE_NAME VARCHAR(50))
INSERT INTO dbo.TABLEX (NAME, TABLE_NAME)
VALUES ('X1', 'X001'), ('X2', 'X002')

CREATE TABLE dbo.X001 (X1_A VARCHAR(50), X1_B VARCHAR(50))
CREATE TABLE dbo.X002 (X2_A VARCHAR(50), X2_B VARCHAR(50))

查询:

;WITH cte AS
(
     SELECT 
            NAME
          , TABLE_NAME
          , [COLUMN] = CAST('' AS VARCHAR(1024))
          , POS = 1
     FROM TABLEX t

     UNION ALL

     SELECT 
            t.NAME
          , t.TABLE_NAME
          , CAST([COLUMN] + ', ' + c.name AS VARCHAR(1024))
          , POS + 1
     FROM cte t
     JOIN sys.columns c ON 
                 OBJECT_ID('dbo.' + t.TABLE_NAME) = c.[object_id] 
               AND 
                 t.POS = c.column_id
)
SELECT 
       NAME
     , TABLE_NAME
     , [COLUMNS] = STUFF([COLUMN], 1, 2, '')
FROM (
     SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY POS DESC)
     FROM cte
) t
WHERE t.rn = 1

结果:

NAME   TABLE_NAME    COLUMNS
------ ------------- -------------
X1     X001          X1_A, X1_B
X2     X002          X2_A, X2_B

查询费用:

统计:

    Query Presenter  Scans  Logical Reads
-------------------  -----  -------------
                XML      5              9
                CTE      3             48

【讨论】:

  • 不知何故,在我的服务器上,CTE 的性能更好,但需要更多时间。我不知道为什么。你能对此有所了解吗?我还必须包含 OPTION(MAXRECURSION 150) 才能包含所有列。
  • 这可能有不同的结果顺序,因为这里没有包含order by colorder。这就是为什么它也有更好的性能,在原始查询中删除order by colorder,您将获得相同的性能。
  • @SohamDasgupta 查询计划中的成本是在实际执行查询之前完成的估计。需要衡量您对查询的性能,如果您在 CTE 版本上有更长的执行时间,我会声称 CTE 不如 XML 版本快。
  • @Justicator 我明白了。但是现在不可能在已回答的查询中包含Order By colorder 是吗?
  • @SohamDasgupta 我不认为 CTE 版本更快。也许在某些情况下它可能会更快,但我还没有看到。
猜你喜欢
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-11
  • 2016-11-22
  • 1970-01-01
  • 2017-01-17
  • 2011-07-17
  • 2010-10-22
相关资源
最近更新 更多