SQL: удалить, только если подзапрос (содержащий 0, 1 или более строк) равен скалярному значению

#sql #h2

#sql #h2

Вопрос:

Описание

Я пытаюсь сделать что-то вроде:

 DELETE FROM ...
-- `<my_id>` is any given long scalar value
WHERE <my_id> = (SELECT id FROM ... WHERE ...);
  

Этот синтаксис не совсем корректен. Если подзапрос select содержит более одной строки, то мы получаем ошибку типа:

Скалярный подзапрос содержит более одной строки

Однако моя предполагаемая цель действительно:

  • если подзапрос возвращает ровно 1 значение, равное скалярному значению ( <my_id> ) ==> удалить
  • остальное (0, или 2 или более значений, или 1 неравное значение) ==> не удалять (игнорировать)

Вопрос

Я не хочу ни IN того, ни EXISTS другого. Мне нужно что-то вроде «equals», которое может сравнивать скалярное значение с возможно многозначными строками.

Какой синтаксис в SQL для этого?

Стек

В частности, я тестирую это с помощью H2.

Комментарии:

1. Я удалил несовместимые теги базы данных. Пожалуйста, помечайте только ту базу данных, которую вы действительно используете.

2. Спасибо, Гордон 👍

Ответ №1:

Один из методов:

 DELETE FROM ...
WHERE <my_id> IN (SELECT id FROM ... WHERE ...) AND
      (SELECT COUNT(*) FROM . . . WHERE . . .) = 1;
  

Однако это проще записать как:

 DELETE FROM ...
WHERE <my_id> = (SELECT MAX(id)
                 FROM . . . 
                 WHERE . .  
                 HAVING COUNT(*) = 1
                ) ;
  

Если счетчик не 1 равен, то подзапрос ничего не возвращает и совпадения нет (поэтому ничего не удаляется).

Комментарии:

1. Спасибо, Гордон! HAVING В моем словаре SQL не хватало. Поскольку мы проверяем, что у нас есть только одна строка с HAVING COUNT(*) = 1 , я думаю, использование MAX — это просто своего рода трюк. Нам просто нужна некоторая функция агрегирования, и, например MIN , в этом случае она будет работать точно так же, как MAX … верно?

2. @juanmirocks . . . Точно. Если имеется одна строка, то MIN() и MAX() возвращает то же значение.