SQL Server - разделитель STRING_AGG как условное выражение - PullRequest
0 голосов
/ 10 февраля 2019

Мне нужно объединить строки, используя разные разделители на основе произвольной логики.Например:

CREATE TABLE t(i INT, c VARCHAR(10));
INSERT INTO t(i,c) VALUES(1, 'a'),(2, 'b'),(3, 'c'),(4, 'd'),(5, 'e');

SELECT STRING_AGG(c,(CASE WHEN i%2=0 THEN ' OR ' ELSE ' AND ' END)) 
       WITHIN GROUP (ORDER BY i) AS r
FROM t;

db <> fiddle demo

И заканчивается ошибка:

Параметр разделителя для STRING_AGG должен представлять собой строковый литерал или переменную .

Моя конечная цель - получить: a OR b AND c OR d AND e как в: db <> fiddle demo


Примечания: мне известно о XML + STUFF или @var = @var + ....

Я ищу "обходные пути"в STRING_AGG.


РЕДАКТИРОВАТЬ: я добавил его как sugestion на Обратная связь Azure

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

Вы почти у цели.Просто измените порядок и используйте материал, и вы можете избавиться от необходимости использовать cte и большинство строковых функций:

SELECT STUFF(
           STRING_AGG(
               (IIF(i % 2 = 0, ' OR ', ' AND '))+c
           , '') WITHIN GROUP (ORDER BY i)
           , 1, 5, '') AS r
FROM t;

Результаты: a OR b AND c OR d AND e

дБ<> fiddle demo

Поскольку первая строка i % 2 равна 1, вы знаете, что результат string_agg всегда начинается с and: and a or b... Тогда все, что вы делаетеудалите первые 5 символов из этого, используя stuff, и вы свободны дома.

Я также позволил себе заменить выражение CASE на более короткое IIF

Обновление

Что ж, в случае, если выбранный разделитель заранее неизвестен, я не смог придумать решение для одного запроса, но все же думаю, что нашел более простое решение, чемВы опубликовали - разделяя мое первоначальное решение на cte с помощью string_agg и выбор из него с помощью stuff, определяя длину разделителя путем повторения условия:

WITH CTE AS
(
SELECT MIN(i) As firstI,
       STRING_AGG(
               (IIF(i % 2 = 0, ' OR ', ' AND '))+c
           , '') WITHIN GROUP (ORDER BY i)
       AS r
FROM t
)

SELECT STUFF(r, 1, IIF(firstI % 2 = 0, 4, 5), '') AS r
FROM CTE;

db <> fiddle demo # 2

0 голосов
/ 10 февраля 2019

Одним из возможных решений (не идеальным) является перемещение разделителя в основное выражение и установка разделителя как пустого:

-- removing last separator
WITH cte AS (
SELECT STRING_AGG(c+(CASE WHEN i%2=0 THEN ' OR ' ELSE ' AND ' END), '')
    WITHIN GROUP (ORDER BY i)AS r
FROM t
)
SELECT r, REPLACE(REPLACE(r+'$', ' OR $', ''), ' AND $', '') AS r
    ,STUFF(r,
           LEN(r)-CHARINDEX(' ', REVERSE(TRIM(r)))+1, 
           CHARINDEX(' ', REVERSE(TRIM(r)))+1,
           '') AS r
FROM cte;

db <> fiddle demo

...