Объединяясь с в STUFF не работает - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть следующий код:

SELECT id, displayname = 
    STUFF((SELECT DISTINCT ', ' + displayname
           FROM #t b 
           WHERE b.id = a.id 
          FOR XML PATH('')), 1, 2, '')
FROM #t a
GROUP BY id

вместо ',' Я хотел бы иметь тег <br/> в STUFF. возможно ли иметь тег HTML непосредственно в команде STUFF?

Ответы [ 3 ]

2 голосов
/ 13 февраля 2020

Добавить к важному замечанию Гордона:

DECLARE @tbl TABLE(id INT, displayname VARCHAR(100));
INSERT INTO @tbl VALUES(1,'value 1.1'),(1,'value 1.2')
                      ,(2,'value 2.1'),(2,'value 2.2.'),(2,'value 2.3 with special characters $<>')
                      ,(3,'value 3.1');

- запрос

SELECT id, displayname = 
       STUFF((SELECT DISTINCT '<br/>, ' + displayname
              FROM @tbl b 
              WHERE b.id = a.id 
              FOR XML PATH, TYPE
             ).value('.[1]', 'nvarchar(max)'), 1, 7, '')
FROM @tbl a
GROUP BY id;

Важно знать, что любой текст в пределах XML должен быть экранирован правильно. Включение специальных символов не проблема, но вы должны использовать TYPE и .value() для чтения из XML с неявным повторным экранированием.

Результат (внимательно посмотрите на вторую строку!):

value 1.1<br/>, value 1.2
value 2.1<br/>, value 2.2.<br/>, value 2.3 with special characters $<>
value 3.1

Проблема теперь в следующем: это может привести к поломке HTML ...

Мое предложение: придерживайтесь X HTML и старайтесь избегать любого строкового кодирования

DECLARE @tbl TABLE(id INT, displayname VARCHAR(100));
INSERT INTO @tbl VALUES(1,'value 1.1'),(1,'value 1.2')
                      ,(2,'value 2.1'),(2,'value 2.2.'),(2,'value 2.3 with special characters $<>')
                      ,(3,'value 3.1');

SELECT id
     , displayname = (SELECT displayname AS [*]
                      FROM @tbl b 
                      WHERE b.id = a.id 
                      FOR XML PATH('line'),TYPE).query('for $l in /line
                                                        return
                                                        ($l/text(),<br/>)
                                                       ')
FROM @tbl a
GROUP BY id;

Результат XML напечатан и может быть помещен в другие X HTML, не думая о сбежавших сущностях:

value 1.1<br />value 1.2<br />
value 2.1<br />value 2.2.<br />value 2.3 with special characters $&lt;&gt;<br />
value 3.1<br />

Подсказка: ответ GMB тоже будет работать

В ответе GMB TYPE с .value() не используется (как было рекомендовано в нормальных случаях). Вы можете безопасно использовать этот подход, если имеете дело со строками. Но имейте в виду, что смешивать XML и строковые подходы очень опасно из-за неявного экранирования ...

2 голосов
/ 13 февраля 2020

Это должно сделать это:

SELECT id, displayname = 
    REPLACE(
        STUFF(
            (
                SELECT DISTINCT '§§§§§' + displayname 
                FROM #t b 
                WHERE b.id = a.id 
                FOR XML PATH('')
            ), 1, 5,  ''
        ), '§§§§§', '<br/>'
    )
FROM #t a
GROUP BY id

Это предполагает, что ни один из ваших dislayname s не содержит последовательность символов '§§§§§'.

На всякий случай: если вы работаете SQL Server 2017, вы можете использовать STRING_AGG(), недавно (наконец!) Добавленную функцию агрегирования строк:

SELECT id, STRING_AGG(displayname, '<br/>') displayname
FROM #t a
GROUP BY id
1 голос
/ 13 февраля 2020

Да, но вы должны быть осторожны со специальными символами:

Отредактировано Shnu go: добавлено пропущенное закрытие ) после .value() ...

SELECT id, displayname = 
       STUFF((SELECT DISTINCT ', ' + displayname
              FROM #t b 
              WHERE b.id = a.id 
              FOR XML PATH, TYPE
             ).value('.[1]', 'nvarchar(max)'), 1, 2, '')
FROM #t a
GROUP BY id;

Затем вы можете безопасно добавлять теги, такие как <br>, в любое место.

...