SQL Server CTE 查询 - 行到单分隔字符串字段

标签 sql sql-server

我在 SQL Server 中有以下数据:

数据创建:

-- First we create some test data.
CREATE TABLE E
(
     [Epinum] VARCHAR(9), 
     [RTyp] VARCHAR(120), 
     [Date] DATETIME
);
GO

INSERT INTO E ([Epinum], [RTyp], [Date])
VALUES ('1', '', CONVERT(datetime, '2002-11-26 14:18:00', 20)),
       ('2', '', CONVERT(datetime, '2002-11-24 15:15:00', 20)),
       ('3', '', CONVERT(datetime, '2002-12-17 11:12:00', 20)),
       ('4', '', CONVERT(datetime, '2002-12-09 19:57:00', 20)),
       ('5', '', CONVERT(datetime, '2002-12-11 06:00:00', 20)),
       ('6', '', CONVERT(datetime, '2002-12-19 12:31:00', 20)),
       ('7', '', CONVERT(datetime, '2002-12-15 08:39:00', 20)),
       ('8', '', CONVERT(datetime, '2002-12-20 08:39:00', 20)),
       ('9', '', CONVERT(datetime, '2002-12-13 08:39:00', 20)),
       ('10', '', CONVERT(datetime, '2002-12-16 08:39:00', 20)),
       ('11', '', CONVERT(datetime, '2002-12-14 08:39:00', 20));
GO

CREATE TABLE UJ
(
    [Epinum] VARCHAR(9), 
    [RTyp] VARCHAR(3)
);
GO

INSERT INTO UJ ([Epinum], [RTyp])
VALUES ('1', '111'), ('1', '222'), ('1', '333'), ('1', '444'),
       ('2', '111'),
       ('3', '111'), ('3', '222'), ('3', '333'),
       ('4', '111'),
       ('5', '111'), ('5', '222'), ('5', '333'), ('5', '444'), 
       ('5', '555'), ('5', '666'), ('5', '777'), ('5', '888'),
       ('7', '111'),
       ('8', '111'),
       ('9', '111'), ('9', '222');
GO

T-SQL 查询:

-- Now build a query that will create the data we want. 
;WITH Tmp AS
(
    SELECT 
        *, 
        ROW_NUMBER() OVER (PARTITION BY Epinum ORDER BY Epinum) AS rownum
    FROM 
        UJ 
) 
SELECT DISTINCT 
    Epinum, 
    (SELECT 
         RTyp + CASE 
                   WHEN t.rownum = (SELECT MAX(rownum) FROM Tmp WHERE Epinum = s.Epinum) 
                      THEN '' 
                      ELSE '|' 
                END 
     FROM Tmp AS t
     WHERE t.Epinum = s.Epinum 
     FOR XML PATH(''), TYPE).value('(.)[1]', 'VARCHAR(MAX)') AS Piped 
FROM 
    Tmp AS s;
GO

-- Great. Now we update the E table, joining on Epinum. 
;WITH Tmp AS
(
    SELECT 
        *, ROW_NUMBER() OVER (PARTITION BY Epinum ORDER BY Epinum) AS rownum
    FROM
        UJ 
) 
UPDATE E
SET e.RTyp = q.Piped 
FROM 
    (SELECT DISTINCT 
         Epinum, 
         (SELECT RTyp + CASE 
                           WHEN t.rownum = (SELECT MAX(rownum) FROM Tmp WHERE Epinum = s.Epinum) 
                              THEN '' 
                              ELSE '|' 
                        END 
          FROM Tmp AS t
          WHERE t.Epinum = s.Epinum 
          FOR XML PATH(''), TYPE).value('(.)[1]', 'VARCHAR(MAX)') AS Piped 
      FROM 
          Tmp AS s) AS q 
INNER JOIN 
    E AS e ON q.Epinum = e.Epinum;
GO

这会获取特定 Epinum 的所有 RTyp 列,然后对它们进行管道分隔并更新表 E 中的 RTyp。它效果很好,但问题是,生产中的表 E 约为 2.3M 行,UJ 约为 900k (两者都有更多的列)并且此查询执行更新所需的时间太长。

如何使该查询更加高效?

最佳答案

UPDATE E 
SET e.RTyp = q.Piped 
FROM (
    SELECT Epinum, Piped = STUFF(
        (SELECT '|' + RTyp 
         FROM UJ 
         WHERE Epinum = t.Epinum 
         FOR XML PATH ('')), 1, 1, '') 
    FROM UJ AS t 
    GROUP BY Epinum) AS q INNER JOIN E AS e 
        ON q.Epinum = e.Epinum;
GO

关于SQL Server CTE 查询 - 行到单分隔字符串字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53321743/

相关文章:

mysql - 使用 mysql 连接列

sql - 批量删除大量行

sql-server - 无法使用 Kerberos 从 RHEL 服务器 7.4 连接到 SQL 服务器

sql - 当您 DROP USER 但未指定 CASCADE 时,模式对象会发生什么情况?

mysql - 使用 LIKE 搜索所有列

php - SQL 将 ORDER BY 结果作为数组返回

sql - 使用联合优化 sql

sql - 在 SQL Server 6.5 中选择 TOP 1

sql-server - 在没有 SqlDependency 的情况下根据查询通知运行存储过程

java - 将 SQL 更改为条件或 HQL