Прошу прощения, но я выставил свой вопрос на google_and_ Мой вопрос такой сложный?
Для меня да.
У меня есть два столбца в таблице в базе данных SQL Server.
Я проверил, что (int)Logicial_Value
остается в [0;2]
по
Логическое_значение МЕЖДУ 0 И 2
мне нужно проверить, если
Int_Value < 5000, КОГДА Logical_Value = 0
Int_Value > 9999, КОГДА Logical_Value = 2
(Подарок: я позволяю вам угадать, что должно означать Logical_Value = 1)
Мое выражение ограничения проверки:
CASE
WHEN Logical_Value = 0 THEN Int_Value < 5000
WHEN Logical_Value = 1 THEN Int_Value > 4999 AND Int_Value < 10000
WHEN Logical_Value = 2 THEN Int_Value > 9999
END
Черт, это не работает. Это просто позволяет любое значение для Int_Value
в каждом случае.
Обратите внимание, что SQL Server Management Studio выдает ошибку проверки ограничения «foo».
Теперь мой вопрос: почему он позволяет значения (он не может проверить ограничение, дорогой капитан), но почему он не может проверить, и, следовательно, каков правильный синтаксис?
Я чувствую, что у меня уже есть RTFM, да.
Вы не понимаете выражение case - оно возвращает одно скалярное значение, оно не выполняет управление потоком или логическую логику.
Никогда (даже в диалектах SQL, поддерживающих логические значения) не используйте выражение case
для вычисления логических значений на основе некоторых условий (других логических значений). Гораздо проще, логически правильно и читабельно выразить это булевыми условиями и операторами (и, или, не)
@astentx Я думаю, что PostgreSQL правильно ведет себя с логическими предикатами ... во всех комбинациях CHECK и CASE, AND, OR и т. д.
@TheImpaler Без сомнения, но зачем писать case
вместо and
для логических значений? Если вы хотите, чтобы A и B были истинными одновременно, тогда A and B
понятно и работает одинаково во всех СУБД, а case when A then B end
— нет. Единственным возможным случаем может быть применение некоторых условий, которые в противном случае будут оцениваться как ошибка (например, when data_type = 'int' then value = 5 when data_type = 'date' then value = date '1970-01-01' end
)
Вам нужно перефразировать ограничение проверки с помощью логического предиката, который не возвращает false для недопустимых комбинаций значений. Например:
check (logical_value = 0 and int_value < 5000
or logical_value = 1 and int_value between 5000 and 9999
or logical_value = 2 and int_value > 9999)
Я всегда нервничаю, когда AND
и OR
смешиваются без круглых скобок, чтобы указать приоритет, даже в тех случаях, когда это оказывается правильным. Я видел слишком много неудачных запросов из-за того, что кто-то случайно добавил предложение туда, куда оно не должно было попасть, и задался вопросом, почему они возвращают все строки или не возвращают их вовсе.
@nbk Я думаю, это должно работать правильно. Есть ли пропущенные скобки?
Подтверждено, а объяснение @JeroenMostert похоже на рай!
@nbk здесь скобки не нужны, и мне кажется, что это очень чисто.
Скобки ясно указывают на исходное намерение, в то время как отсутствующие скобки не позволяют отличить логическую ошибку от требования.
@TheImpaler да, это правильно, но со скобками было бы яснее и понятнее,
Разработчик программного обеспечения, который не может понять приоритет здесь, должен получить новую работу.
Больше скобок? Это SQL, а не LISP.
Удобочитаемость — это то, насколько легко или сложно что-то читать.
CASE
так не работает. СинтаксисCASE WHEN <boolean expression> THEN <value> ELSE <value> END
. Примечательно, что булевы выражения в T-SQL разрешены только в определенных контекстах и нигде больше (настоящего независимого логического типа не существует), поэтому вы вообще не можете использоватьCASE
для указания условия (если только вы искусственно не сравниваете с1
или0
или подобным ). Вам нужно переписать это, используяAND
иOR
, например.(Logical_Value = 0 AND Int_Value < 5000) OR (Logical_Value = 1 AND ...)
.