Я постоянно получаю сообщение «Неверный синтаксис рядом с ключевым словом «КОГДА».» Ошибка в моем SQL-запросе

Мой SQL-запрос выглядит следующим образом:

IF OBJECT_ID('tempdb..#OutputIds') IS NOT NULL DROP TABLE #OutputIds;
CREATE TABLE #OutputIds (Action NVARCHAR(10), ChildId NVARCHAR(MAX));

MERGE INTO LeadShirts AS target
USING (VALUES ('abc', 'abc'), ('abc', 'abc')) AS source (ParentId, ChildId)
ON (target.Lead = source.ParentId AND target.Shirts = source.ChildId)
WHEN MATCHED AND target.Deleted = 1 THEN
    UPDATE SET UpdatedOn = GETDATE(), Deleted = 0  -- Re-activate deleted records
    OUTPUT 'Edited', source.ChildId INTO #OutputIds (Action, ChildId)
WHEN NOT MATCHED BY TARGET THEN
    INSERT (Lead, Shirts, Deleted, CreatedOn)
    VALUES (source.ParentId, source.ChildId, 0, GETDATE())
    OUTPUT 'Added', source.ChildId INTO #OutputIds (Action, ChildId);

INSERT INTO #OutputIds (Action, ChildId)
SELECT 'Skipped', ChildId
FROM (VALUES ('abc', 'abc'), ('abc', 'abc')) AS V(ParentId, ChildId)
WHERE EXISTS (SELECT 1 FROM LeadShirts AS T WHERE T.Lead = V.ParentId AND T.Shirts = V.ChildId AND T.Deleted IS NULL);

SELECT Action, ChildId FROM #OutputIds;

И я продолжаю получать эту ошибку, когда запускаю ее на SQL Server:

Сообщение 156, уровень 15, состояние 1, строка 11
Неправильный синтаксис рядом с ключевым словом «WHEN».

Любое решение будет высоко оценено.

У вас может быть только одно предложение OUTPUT .. INTO, и оно находится в определенном месте. Ни одного за действие

Martin Smith 15.06.2024 14:46

Синтаксис (VALUES( ... ) ) AS alias ( colA, colB ) ISO SQL достаточно неуклюж сам по себе, поэтому использование его внутри оператора MERGE просто вызывает раздражение... Я предлагаю вам перенести их либо в table-variables/temp-tables, либо в CTE.

Dai 15.06.2024 15:19

@Дай - я не согласен. Его использование в MERGE — одно из наименее раздражающих мест. Если вы переместите его в CTE, это станет более раздражающим, поскольку вы не можете просто использовать его непосредственно в качестве определения выражения CTE, но вам нужно добавить из него SELECT.

Martin Smith 15.06.2024 15:36

Postgres позволяет использовать его прямо здесь dbfiddle.uk/lSmUNsPz

Martin Smith 15.06.2024 15:53
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
4
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как указано в комментарии @martin-smith, MERGE имеет только одно предложение OUTPUT в конце выражения: <output_clause>

Ошибка, с которой вы столкнулись, связана с тем, что SQL запутан: если OUTPUT стоит только в конце, то что пытается сделать следующее ключевое слово WHEN? Ответ от SQL правильный, incorrect syntax near the keyword 'WHEN'

Вместо этого это должно сработать, хотя в выводе меньше деталей:

IF OBJECT_ID('tempdb..#OutputIds') IS NOT NULL DROP TABLE #OutputIds;
    
CREATE TABLE #OutputIds (Action NVARCHAR(10), ChildId NVARCHAR(MAX));

MERGE INTO LeadShirts AS target
USING (VALUES ('abc', 'abc'), ('abc', 'abc')) AS source (ParentId, ChildId)
    ON (target.Lead = source.ParentId AND target.Shirts = source.ChildId)
WHEN MATCHED AND target.Deleted = 1 THEN
    UPDATE SET UpdatedOn = GETDATE(), Deleted = 0  -- Re-activate deleted records
WHEN NOT MATCHED BY TARGET THEN
    INSERT (Lead, Shirts, Deleted, CreatedOn)
    VALUES (source.ParentId, source.ChildId, 0, GETDATE())
OUTPUT $action, source.ChildId INTO #OutputIds (Action, ChildId);

-- Change the action message for deleted
UPDATE #OutputIds
SET Action = 'Edited'
WHERE Action = 'DELETE';

-- Change the action message for inserted
UPDATE #OutputIds
SET Action = 'Added'
WHERE Action = 'INSERT';

INSERT INTO #OutputIds (Action, ChildId)
SELECT 'Skipped', ChildId FROM (VALUES ('abc', 'abc'), ('abc', 'abc')) AS V(ParentId, ChildId)
WHERE EXISTS (SELECT 1 FROM LeadShirts AS T WHERE T.Lead = V.ParentId AND T.Shirts = V.ChildId AND T.Deleted IS NULL);

SELECT Action, ChildId FROM #OutputIds;

Надеюсь, это поможет объяснить, как работает MERGE и как можно манипулировать выводом, чтобы он соответствовал вашим критериям, если это действительно так важно;)

Не забывайте об обязательном ОБЪЕДИНЕНИИ HOLDLOCK ;)

Dai 15.06.2024 15:22

@Дай, это хороший совет, хотя я не хочу добавлять его сюда, он немного не по теме, и я не хочу торчать и объяснять, почему он полезен и когда вы не будете его использовать. Однако этот чат должен посеять идею ;)

Chris Schaller 15.06.2024 15:27

Кажется предпочтительнее использовать CASE $action WHEN 'UPDATE' THEN 'Edited' WHEN 'INSERT' THEN 'Added' END, чтобы вставить нужную строку напрямую, а не вставлять нежелательную, а затем обновлять ее.

Martin Smith 15.06.2024 15:32

Абсолютно, если нужно внести лишь небольшое количество изменений, я бы принял этот пиар;) Я только демонстрировал, что это можно сделать, поэтому выбрал подход первых принципов. Если у ОП возникают проблемы с документацией по MERGE, я не хочу вводить слишком много концепций.

Chris Schaller 16.06.2024 01:02

Другие вопросы по теме