在SQL中,如何将逗号分隔键字符串的列转换为逗号分隔值字符串

In SQL, how to convert a column of a comma separated key string to a comma separated value string

我有一个数据库 table (table A) 在 SQL Server 2016 中看起来像这样:

表A:

TaskID - TaskName  -  AssignedTo
-------------------------------
1        Task 1       1,4
2        Task 2       3
3        Task 3       2,3
4        Task 4       2,4,5

我还有一个 TableB,它是 AssignedTo 的查找 table,如下所示:

表B:

AssigneeID - Name
-------------------------------
1            John Smith
2            Janet Wright
3            Tom Morgan
4            Kevin Warren
5            Mike Taylor

我想编写一个查询以生成以下内容 report/table:

TaskID - TaskName  -  NameAssignedTo
------------------------------------------------------------
1        Task 1       John Smith,Kevin Warren
2        Task 2       Tom Morgan
3        Task 3       Janet Wright,Tom Morgan
4        Task 4       Janet Wright,Kevin Warren,Mike Taylor

如果可以通过编写 SQL 查询来实现,那就太好了。任何人都可以帮忙吗?非常感谢!

下次您需要提供##1-4。 并从这个答案中了解它的含义,即一个最小的可重现示例。 您将它复制到 SSMS 并在那里启动它。

以下是如何在 SQL Server 2016 中实现它:

  • STRING_SPLIT() 将其分解,每行一个 AssignedTo
  • SELECT ... FOR XML ... 将每个任务恢复为一​​行。

SQL

-- DDL and sample data population, start
DECLARE @tblA TABLE (TaskID INT PRIMARY KEY, TaskName VARCHAR(100), AssignedTo VARCHAR(30));
INSERT INTO @tblA (TaskID, TaskName, AssignedTo) VALUES
(1, 'Task 1', '1,4'),
(2, 'Task 2', '3'),
(3, 'Task 3', '2,3'),
(4, 'Task 4', '2,4,5');

DECLARE @tblB TABLE (AssigneeID INT PRIMARY KEY, [Name] VARCHAR(30));
INSERT INTO @tblB (AssigneeID, [Name]) VALUES
(1, 'John Smith'),
(2, 'Janet Wright'),
(3, 'Tom Morgan'),
(4, 'Kevin Warren'),
(5, 'Mike Taylor')
-- DDL and sample data population, end

DECLARE @separator CHAR(1) = ',';

;WITH cte AS
(
    SELECT * FROM @tblA
        CROSS APPLY (SELECT value FROM STRING_SPLIT(AssignedTo, @separator)) AS x
        INNER JOIN @tblB AS b ON x.value = b.AssigneeID
)
SELECT p.TaskID, p.TaskName
    , STUFF((SELECT DISTINCT
                     CONCAT(@separator, c.Name)
                     FROM cte AS c
                     WHERE c.TaskID = p.TaskID
                     FOR XML PATH ('')),
             1, 1, '') AS NameAssignedTo
FROM cte AS p
GROUP BY p.TaskID, p.TaskName;

输出

+--------+----------+---------------------------------------+
| TaskID | TaskName |            NameAssignedTo             |
+--------+----------+---------------------------------------+
|      1 | Task 1   | John Smith,Kevin Warren               |
|      2 | Task 2   | Tom Morgan                            |
|      3 | Task 3   | Janet Wright,Tom Morgan               |
|      4 | Task 4   | Janet Wright,Kevin Warren,Mike Taylor |
+--------+----------+---------------------------------------+

您的架构基本上已损坏。你真的想要一个额外的table来表达TaskAssignments这样的:

TaskID Assignee
1 1
1 4
2 3
3 2
3 3
4 2
4 4
4 5

您可以找到其他解决方案来为您提供此查询的结果,但这会使它更容易编写,它的性能会好几个数量级,并且它也更适合回答您甚至没有想过要问的问题(查询)。

此处的一般经验法则:人类更喜欢更少、更宽的 tables,但 计算机 越多越好,更窄 tables。所以我们设计数据库存储来安抚计算机,并编写报告来为人类显示组合数据。