Я собираюсь, мы предположим, у вас всего 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);
Если вам не нужен динамический свод c, то ваш 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;
Поскольку вам нужно масштабировать набор данных при добавлении сотрудников, вам понадобится динамический c 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