Проблема преобразования столбца SQL в CSV через XML - PullRequest
0 голосов
/ 08 января 2019

Я заменяю разделенное запятыми поле в приложении отчетов SQL Server отношением «многие ко многим». Код приложения пока не может быть заменен, поэтому мне нужно получить тот же столбец CSV, который он ожидает в настоящее время. В прошлом я использовал трюк FOR XML PATH, и похоже, что это быстрое решение на основе множеств, которое должно легко реализовываться.

Мой текущий запрос выглядит так:

SELECT   
    Report = rr.Report_ID, 
    RoleList = STUFF((SELECT   ', ' + r.[Name] AS [text()] 
                      FROM [dbo].[Role] r 
                      WHERE r.Role_ID = rr.Role_ID
                      FOR XML PATH ('')), 1, 1, '') 
FROM     
    [dbo].ReportRole rr
ORDER BY 
    rr.Report_ID;

Что я ожидаю, так это:

Report   RoleList
--------------------------------------------------------------------
  2      Senior Application Developer
  3      Senior Application Developer, Manager Information Systems

Но вместо этого я получаю следующее:

Report   RoleList
--------------------------------------
  2      Senior Application Developer
  3      Senior Application Developer
  3      Manager Information Systems

Я использую SQL Server 2017. Разве эта версия не поддерживает взлом XML-CSV из предыдущих версий?

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Вы отметили свой вопрос как SQL-Server 2017 и спрашиваете:

Разве эта версия не поддерживает хакер XML-to-CSV из предыдущих версий?

Да, это так (как сказал ответ Пауриана), но это даже лучше: Эта версия поддерживает STRING_AGG():

Не зная ваших таблиц, я настроил мини-макет для имитации вашей проблемы (в соответствии с вашим Таблицы нормализованы, и таблица соединений представляет собой простую карту «многие ко многим» ):

Две таблицы с таблицей отображения m:n между

DECLARE @mockupA TABLE(ID INT,SomeValue VARCHAR(10));
INSERT INTO @mockupA VALUES(1,'A1'),(2,'A2');

DECLARE @mockupB TABLE(ID INT,SomeValue VARCHAR(10));
INSERT INTO @mockupB VALUES(1,'B1'),(2,'B2');

DECLARE @mockupMapping TABLE(ID_A INT,ID_B INT);
INSERT INTO @mockupMapping VALUES(1,1),(1,2),(2,2);

- запрос просто объединит эти таблицы, а затем будет использовать GROUP BY вместе с STRING_AGG(). Предложение WITHIN GROUP позволяет определить порядок сортировки объединенной строки.

SELECT a.ID,a.SomeValue
      ,STRING_AGG(b.SomeValue,', ') WITHIN GROUP(ORDER BY b.ID) AS B_Values
FROM @mockupA a
INNER JOIN @mockupMapping m ON a.ID=m.ID_A
INNER JOIN @mockupB b ON b.ID=m.ID_B
GROUP BY a.ID,a.SomeValue;

Результат

ID  SomeValue   B_Values
1   A1          B1, B2
2   A2          B2
0 голосов
/ 08 января 2019

Наличие таблицы с именем «ReportRole» означает таблицу связи между отчетом и ролью в вашем случае. Если это так, вы можете сделать таблицу ReportRole частью вашего внутреннего запроса и сохранить свои идентификаторы отчетов во внешнем запросе:

SELECT   
    Report = rpt.Report_ID, 
    RoleList = STUFF((SELECT   ', ' + r.[Name] AS [text()] 
                      FROM [dbo].[Role] r
                           JOIN [dbo].ReportRole rr
                             ON r.Role_ID = rr.Role_ID
                      WHERE rr.Report_ID = rpt.Report_ID
                      FOR XML PATH ('')), 1, 1, '') 
FROM     
    [dbo].Report rpt
ORDER BY 
    rpt.Report_ID;
...