Выйти из запроса в регистре?

8

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

SELECT TOP(1) @dateA=a.someDate
FROM a
ORDER BY DESC;
SELECT TOP(1) @dateB=b.someDate
FROM b
ORDER BY DESC;

CASE WHEN @dateA=@dateB THEN raiseerror('dates equal',20,-1) with log;

Insert statements;

Любая помощь будет очень признательна.

thejoker34
источник
Некоторые другие варианты SQL имеют как выражение, так и оператор с именем CASE- SQL Server имеет только CASEвыражение.
RDFozz
3
Вы действительно хотите поднять ошибку? Или это просто попытка выхода?
Кевин

Ответы:

16

CASE является выражением (не выражением) и не может использоваться для управления потоком подобным образом - не вызывать команды, не возвращать более одного столбца / значения, не использоваться в качестве отдельной команды.

Мне кажется, вы можете просто использовать, IFчтобы поднять ошибку, когда даты равны, иначе запустите вставки.

IF @dateA = @dateB 
BEGIN
  raiseerror('dates equal',20,-1) with log;
END
ELSE -- maybe you don't need a batch-aborting, logging error level
BEGIN
  INSERT ...
END

Вы также можете сделать это по-другому. Запускайте вставки, только если даты не совпадают , иначе выведите ошибку:

IF @dateA <> @dateB
BEGIN
  INSERT ...
END
ELSE
BEGIN
  raiserror ...
END

Если вы думали использовать ошибку только с целью получения из запуска вставок, то вы можете просто удалить все из ELSEпуха, так как единственный способ вставки будет работать, когда @dateAи @dateBявляется не равно :

IF @dateA <> @dateB
BEGIN
  INSERT ...
END

Я сократил путь назад к тому, чтобы быть педантичным по отношению к таким вещам, как строки (против «записей») и столбцов (против «полей»), но целое выражение и операторная вещь - очень важное различие, именно по этой причине. Смотрите « Грязные секреты выражения CASE ».

Аарон Бертран
источник
В основном хороший ответ, за исключением одного случая: использование оператора <> не очень хорошо работает со значениями NULL. Если одно из ваших значений даты равно NULL, оператор «не равно» вернет неожиданные результаты. Попробуйте это «ВЫБЕРИТЕ СЛУЧАЙ КОГДА (1 <> NULL) THEN '! =' ELSE '==' END"
user5151179
1
@ user5151179 Я уверен, что Аарон знает разницу. Также проверьте, что ОП в вопросе говорит, что он хочет делать, когда две даты равны и что, когда они не равны. Он вообще не упоминает, что они хотят делать, когда один или оба из них NULL. Это все еще хорошее наблюдение, что две версии, которые предоставляет Аарон, будут делать разные вещи в этом случае.
ypercubeᵀᴹ
6

Используйте IFвместоCASE

 IF @dateA=@dateB 
    raiseerror('dates equal',20,-1) with log;
 ELSE
    BEGIN
        Insert statements;
    END

Это, конечно, предполагает, что вы действительно хотите вызвать ошибку. Другой вариант будет:

 IF @dateA<>@dateB 
    BEGIN
        Insert statements;
    END

Теперь обратите внимание на BEGINи END. Это будет важно. IFутверждение (а ELSE) влияет только на правильную команду под ним. Если вам нужно более одной команды, вам нужно начать и закончить .

Кеннет Фишер
источник
2

В других ответах указывалось, что CASE является выражением , а не утверждением, и поэтому не может само по себе охватывать утверждения (как RAISEERRORи любые другие). Если условий не так много, особенно если это всего лишь одно условие, утверждение IF является идеальным выбором для того, что вы пытаетесь сделать, как уже упоминалось.

Тем не менее, в зависимости от вашего сценария, выражение CASE все еще может использоваться, но не совсем так, как вы показали. В частности, если нужно проверить много условий, когда совпадение должно приводить к одному и тому же набору действий (например, вызвать исключение и завершить сценарий), вы можете использовать выражение CASE в операторе присваивания, хранящем результат CASE, а затем выполнить это с помощью IF, проверяющего сохраненный результат и выполняющего необходимые действия, если необходимо, например, так:

DECLARE @ErrorMessage varchar(1000);

SET @ErrorMessage =
  CASE WHEN @dateA = @dateB THEN
    'Dates equal'
  CASE WHEN ... /* some other condition */ THEN
    'Some other message'
  .
  .
  .
  ELSE
    ''  -- no message if nothing is wrong;
        -- you can also omit the ELSE branch entirely,
        -- which means the same as ELSE NULL
  END
;

IF @ErrorMessage <> ''
BEGIN
  RAISERROR (@ErrorMessage, 20, -1) WITH LOG;
END;

... /* continue the script */

В этом случае необходимое действие вызывает исключение, но сообщение, возвращаемое с исключением, должно зависеть от того, какое условие было проверено первым. Оператор присваивания использует выражение CASE, чтобы выбрать, какое сообщение хранить в @ErrorMessageпеременной.

Вы также можете видеть, что ошибка возникает только условно - только если переменная действительно содержит сообщение для показа. Если значение является пустой строкой или пустым, сценарий будет продолжаться без прерывания.

Андрей М
источник
0

Вам нужны переменные?

declare @D1 table (dt date);
declare @D2 table (dt date);
insert into @D1 values ('2000-01-01'), ('2000-02-01');
insert into @D2 values ('2000-01-01'), ('2000-02-01');
if (select max(dt) from @D1) = (select max(dt) from @D2)
begin 
   select 'match'
end
else 
begin 
   select 'no match'
end
папараццо
источник