Мне нужен эквивалент этого Count с Case для базы данных Firebird 3. Я получаю сообщение об ошибке при попытке:
SQL error code = -104.
Invalid usage of boolean expression.
Я только недавно познакомился с командой Case и, кажется, не могу переделать ее сам. Мне удалось заставить его нормально работать с SQLite.
Намерение состоит в том, чтобы выполнить операцию И, где нельзя выполнить И, потому что ключевые слова находятся в строках.
SELECT Count((CASE WHEN keywords.keyword LIKE '%purchased%'
THEN 1 END) AND
(CASE WHEN keywords.keyword LIKE '%item%'
THEN 1 END)) AS TRows
FROM products
LEFT OUTER JOIN keywords_products ON
products.product_rec_id = keywords_products.product_rec_id
LEFT OUTER JOIN keywords ON
keywords_products.keyword_rec_id = keywords.keyword_rec_id
WHERE (keywords.keyword LIKE '%purchased%' OR
keywords.keyword LIKE '%item%')
У меня есть три таблицы SQLite, таблица продуктов, таблица keywords_products и таблица ключевых слов.
CREATE TABLE products (
product_rec_id INTEGER PRIMARY KEY NOT NULL,
name VARCHAR (100) NOT NULL
);
CREATE TABLE keywords_products (
keyword_rec_id INTEGER NOT NULL,
product_rec_id INTEGER NOT NULL
);
CREATE TABLE keywords (
keyword_rec_id INTEGER PRIMARY KEY NOT NULL,
keyword VARCHAR (50) NOT NULL UNIQUE
);
Таблица ключевые слова_продукты содержит идентификатор записи продукта и идентификатор записи ключевого слова. Каждому продукту можно присвоить несколько ключевых слов в таблице ключевые слова.
Таблица ключевое слово выглядит так:
keyword_rec_id keyword
-------------- -----------
60 melee
43 scifi
87 water
Таблица ключевые слова_продукты выглядит так (одно ключевое слово может быть назначено многим товарам):
keyword_rec_id product_rec_id
-------------- --------------
43 1
60 1
43 2
87 3
Таблица товаров выглядит так:
product_rec_id name
-------------- --------------
1 Scifi Melee Weapons
2 Scifi Ray Weapon
3 Lake House
@MarkRotteveel использование plus не имеет смысла также и w.r.t. Совокупный COUNT для NULL+1 = NULL. Я думаю, здесь есть случай XYZ.
@ Arioch'The Это зависит от обстоятельств. Если намерение состоит в том, чтобы считать, когда оба условия истинны, тогда он будет вести себя одинаково, предполагая, что SQLite переводит 1 в истину при использовании AND и имеет правильное нулевое поведение (или если count не будет считать false). Учитывая отсутствие объяснения предполагаемого поведения, это просто предположение.
@MarkRotteveel, поскольку все, что ему нужно, это просто подсчет, он должен полностью отказаться от CASE и вместо этого использовать правильный WHERE. Вот почему я подозреваю случай XYZ. TS кажется повсюду видит гвозди, потому что он привык обращаться с молотком. Когда в данном конкретном случае, я думаю, ему это не нужно. Также с таким WHERE его присоединяется LEFTiness, я думаю, тоже излишне.
Намерение состоит в том, чтобы выполнить операцию И, где нельзя выполнить И, потому что ключевые слова находятся в строках.
По определению операция И - это метод, а не намерение. Если вы намереваетесь «выполнить операцию И», просто введите select 1 from rdb$database where (1=1) and (2=2), и вот оно, вы только что выполнили операцию И. Если бы это было настоящим намерением. Но это не так. У тебя другие намерения. Вы просто застряли в режиме «должно сработать И», ошибочно приняв инструмент и цель. perlmonks.org/?node=XY+Проблема
Если вы не можете понять и объяснить, что вы хотите, вы не сможете принять хорошее решение или получить хорошее предложение, кроме как по чистой случайности. Вы не первый, кто ошибается с целью и методом. Ссылка показывает, насколько это типично. Вы можете считать себя выше типичных недостатков. Это не повредит никому, кроме вас самих.
Покажите, пожалуйста, каким должен быть результат, и объясните почему.





Вы должны использовать ОДНО одно выражение CASE с несколькими ветвями WHEN.
Создание логических функций из различных выражений CASE просто не имеет смысла - CASE сама по себе не является логической функцией.
Вы можете увидеть правила и пример на https://firebirdsql.org/refdocs/langrefupd15-case.html
case
when Age >= 18 then 'Yes'
when Age < 18 then 'No'
end;
Преобразуйте два предложения CASE в одно предложение CASE по этому шаблону.
Однако вы используете CASE только тогда, когда вы не можете переместить фильтры и условия в стандартную часть SQL select. Нормальным подходом было бы минимизировать данные, которые должен извлекать механизм SQL, с помощью предварительной фильтрации. CASE использует постфильтрацию, она заставляет механизм SQL извлекать все данные, независимо от того, нужны они ему или нет, а затем отбрасывать ненужные извлеченные данные. Это лишняя работа, замедляющая процесс.
В вашем случае вы уже извлекли условие в предложение WHERE, это хорошо.
SELECT
...
WHERE (keywords.keyword LIKE '%purchased%')
OR (keywords.keyword LIKE '%item%')
Поскольку вы предварительно фильтруете свой поток данных, чтобы он всегда содержал «элемент» или «покупка», ваше предложение CASE всегда будет возвращать 1 во всех строках, выбранных в рамках этой предварительной фильтрации WHERE. Следовательно - просто удалите лишнее предложение CASE и поставьте вместо него "1".
SELECT Count(1)
FROM products
LEFT JOIN keywords_products ON products.product_rec_id = keywords_products.product_rec_id
LEFT JOIN keywords ON keywords_products.keyword_rec_id = keywords.keyword_rec_id
WHERE (keywords.keyword LIKE '%purchased%')
OR (keywords.keyword LIKE '%item%')
Теперь, учитывая, что предложение WHERE обрабатывается логически после JOINing, этот ваш запрос де-факто преобразовал LEFT JOINs в FULL JOINs (ваше предложение WHERE просто отбрасывает строки со значениями столбца NULL "ключевое слово"), но снова в ненадежном и неэффективном методе. Поскольку вы в любом случае не хотите, чтобы строки типа "ключевое слово равно NULL", просто преобразуйте ваши левые соединения в обычные соединения.
Спасибо. Я изучу JOIN позже сегодня, когда у меня будет возможность. Намерение состоит в том, чтобы выполнить операцию AND после Where, поскольку ключевые слова находятся в строках.
@nDelphi вы можете поставить AND в WHERE. На данный момент никто не может понять, чего именно вы хотите. Вы можете начать с объяснения проблемы человеческими терминами, а затем, возможно, переосмыслите и лучше ее поймете.
Я предполагаю, что вы хотите посчитать, сколько там строк, где выполняются оба условия.
Ошибка возникает из-за того, что нельзя использовать AND между целочисленными значениями. Значения должны быть истинными логическими значениями.
Итак, измените свой код на
Count((CASE WHEN keywords.keyword LIKE '%purchased%'
THEN TRUE END) AND
(CASE WHEN keywords.keyword LIKE '%item%'
THEN TRUE END))
Однако это слишком сложно. Вы можете упростить свое выражение до
count(nullif (
keywords.keyword LIKE '%purchased%' and keywords.keyword LIKE '%item%',
false))
Использование NULLIF необходимо, потому что COUNT будет считать все значения, отличные от NULL (как требует стандарт SQL), а false также не является NULL. Итак, чтобы достичь (предполагаемого) желаемого эффекта, мы преобразуем false в NULL, используя NULLIF.
Блестяще. Большое спасибо.
.... таким сложным хаком, когда все, что нужно, был COUNT(1) и правильный (один термин изменен) пункт WHERE. Бедная Жар-птица ...
@ Arioch'The Это зависит от того, был ли код из вопроса упрощенный (без других деталей).
@ Arioch'The я попробую с count (1) и посмотрю, что у меня получится. Думаю, я пробовал это и не получил ожидаемых результатов, потому что у меня есть другие таблицы, объединенные в других запросах. Я также пробовал здесь логическое значение перед ответом Марка, но у меня было THEN TRUE ELSE FALSE END, и это меня смутило, поскольку Firebird не принял это. Я должен упростить свои запросы, потому что они выходят из-под контроля, а я очень плохо разбираюсь в SQL.
Вам также нужно будет сформулировать свою задачу, а затем сформулировать предложение WHERE, чтобы точно представить вашу задачу. Например, вы имеете в виду OR, AND или XOR? Например, должен ли регистр AND считаться как 1 или как 2? И т. Д. И т. Д. «Правильная постановка задачи - половина решения». Это вдвойне верно для SQL, который является ответвлением математической теории множеств, поэтому бумага с ручкой часто более эффективна для разработки и отладки запросов, чем любое руководство.
Это решение не работает для других таблиц с аналогичной структурой. Единственное отличие - это названия полей. Что могло быть причиной? Если он работает для одного, он должен работать и с другим. Я могу получить данные в порядке, как с таблицами ключевых слов, но не с Count, он возвращает значение 0.
@nDelphi Я предлагаю вам опубликовать новый вопрос, предоставить соответствующий DDL таблиц, образцы данных, ваш предпринятый запрос, а также ожидаемый и фактический результат запроса.
Каково предполагаемое значение этого выражения
CASE, потому что для меня это не имеет особого смысла. Возможно, вам стоит заменитьANDна+