我要我们假设您总共有 5 张桌子。我将调用这些Document、Tag、Employee,然后是DocumentTag 和DocumentEmployee。因此,要获得解决方案,您需要 2 种不同类型的聚合,标签的字符串聚合和员工的数据透视。
--Base tables
CREATE TABLE dbo.Document (DocumentID int, DocumentTitle nvarchar(50));
CREATE TABLE dbo.Employee (EmployeeID int, EmployeeName nvarchar(50));
CREATE TABLE dbo.Tag (TagID int, TagName nvarchar(50));
GO
--Link tables
CREATE TABLE dbo.DocumentTag (DocumentID int, TagID int);
CREATE TABLE dbo.DocumentEmployee (DocumentID int, EmployeeID int);
GO
--Sample data
INSERT INTO dbo.Document
VALUES(2,N'Important Doc'),(3,N'New Doc');
INSERT INTO dbo.Employee
VALUES(1,N'John'),
(2,N'Mary'),
(3,N'Patricia'),
(4,N'Paul');
INSERT INTO dbo.Tag
VALUES(1,N'Classified'),
(2,N'Finance'),
(3,N'Warehouse');
GO
--Link Data
INSERT INTO dbo.DocumentTag
VALUES(1,1),(1,2),(2,3);
INSERT INTO dbo.DocumentEmployee
VALUES(1,1),(1,2),(1,3),(2,2),(2,4);
如果不需要动态数据透视,那么您的 SQL 将如下所示:
SELECT D.DocumentID,
D.DocumentTitle,
STUFF((SELECT N' ' + T.TagName
FROM dbo.DocumentTag DT
JOIN dbo.Tag T ON DT.TagID = T.TagID
WHERE DT.DocumentID = D.DocumentID
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,1,N'') AS Tags,
MAX(CASE E.EmployeeName WHEN N'John' THEN 1 ELSE 0 END) AS John,
MAX(CASE E.EmployeeName WHEN N'Mary' THEN 1 ELSE 0 END) AS Mary,
MAX(CASE E.EmployeeName WHEN N'Patricia' THEN 1 ELSE 0 END) AS Patricia,
MAX(CASE E.EmployeeName WHEN N'Paul' THEN 1 ELSE 0 END) AS Paul
FROM dbo.Document D
JOIN dbo.DocumentEmployee DE ON D.DocumentID = DE.EmployeeID
JOIN dbo.Employee E ON DE.EmployeeID = E.EmployeeID
GROUP BY D.DocumentID,
D.DocumentTitle;
但是,由于您需要在添加员工时扩展数据集,因此您需要动态 SQL 来执行此操作。因此,要使用上述解决方案实现这一点,您可以执行以下操作:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET @SQL = N'SELECT D.DocumentID,' + @CRLF +
N' D.DocumentTitle,' + @CRLF +
N' STUFF((SELECT N'' '' + T.TagName' + @CRLF +
N' FROM dbo.DocumentTag DT' + @CRLF +
N' JOIN dbo.Tag T ON DT.TagID = T.TagID' + @CRLF +
N' WHERE DT.DocumentID = D.DocumentID' + @CRLF +
N' FOR XML PATH(N''''),TYPE).value(''.'',''nvarchar(MAX)''),1,1,N'''') AS Tags,' + @CRLF +
STUFF((SELECT N',' + @CRLF +
N' MAX(CASE E.EmployeeName WHEN N' + QUOTENAME(E.EmployeeName,'''') + N' THEN 1 ELSE 0 END) AS ' + QUOTENAME(E.EmployeeName)
FROM dbo.Employee E
ORDER BY E.EmployeeID ASC
FOR XML PATH(''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + @CRLF +
N'FROM dbo.Document D' + @CRLF +
N' JOIN dbo.DocumentEmployee DE ON D.DocumentID = DE.EmployeeID' + @CRLF +
N' JOIN dbo.Employee E ON DE.EmployeeID = E.EmployeeID' + @CRLF +
N'GROUP BY D.DocumentID,' + @CRLF +
N' D.DocumentTitle;';
--PRINT @SQL; --YOur debugging friend
EXEC sys.sp_executesql @SQL;
DB<>Fiddle