Мне нужен эквивалент этого графа с базой данных Case for Firebird 3

Мне нужен эквивалент этого 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

Каково предполагаемое значение этого выражения CASE, потому что для меня это не имеет особого смысла. Возможно, вам стоит заменить AND на +

Mark Rotteveel 28.03.2018 11:35

@MarkRotteveel использование plus не имеет смысла также и w.r.t. Совокупный COUNT для NULL+1 = NULL. Я думаю, здесь есть случай XYZ.

Arioch 'The 28.03.2018 11:43

@ Arioch'The Это зависит от обстоятельств. Если намерение состоит в том, чтобы считать, когда оба условия истинны, тогда он будет вести себя одинаково, предполагая, что SQLite переводит 1 в истину при использовании AND и имеет правильное нулевое поведение (или если count не будет считать false). Учитывая отсутствие объяснения предполагаемого поведения, это просто предположение.

Mark Rotteveel 28.03.2018 11:50

@MarkRotteveel, поскольку все, что ему нужно, это просто подсчет, он должен полностью отказаться от CASE и вместо этого использовать правильный WHERE. Вот почему я подозреваю случай XYZ. TS кажется повсюду видит гвозди, потому что он привык обращаться с молотком. Когда в данном конкретном случае, я думаю, ему это не нужно. Также с таким WHERE его присоединяется LEFTiness, я думаю, тоже излишне.

Arioch 'The 28.03.2018 11:51

Намерение состоит в том, чтобы выполнить операцию И, где нельзя выполнить И, потому что ключевые слова находятся в строках.

nDelphi 28.03.2018 12:22

По определению операция И - это метод, а не намерение. Если вы намереваетесь «выполнить операцию И», просто введите select 1 from rdb$database where (1=1) and (2=2), и вот оно, вы только что выполнили операцию И. Если бы это было настоящим намерением. Но это не так. У тебя другие намерения. Вы просто застряли в режиме «должно сработать И», ошибочно приняв инструмент и цель. perlmonks.org/?node=XY+Проблема

Arioch 'The 28.03.2018 15:28

Если вы не можете понять и объяснить, что вы хотите, вы не сможете принять хорошее решение или получить хорошее предложение, кроме как по чистой случайности. Вы не первый, кто ошибается с целью и методом. Ссылка показывает, насколько это типично. Вы можете считать себя выше типичных недостатков. Это не повредит никому, кроме вас самих.

Arioch 'The 28.03.2018 16:23

Покажите, пожалуйста, каким должен быть результат, и объясните почему.

Mark Rotteveel 28.03.2018 18:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
414
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы должны использовать ОДНО одно выражение 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 28.03.2018 13:05

@nDelphi вы можете поставить AND в WHERE. На данный момент никто не может понять, чего именно вы хотите. Вы можете начать с объяснения проблемы человеческими терминами, а затем, возможно, переосмыслите и лучше ее поймете.

Arioch 'The 28.03.2018 15:26
Ответ принят как подходящий

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

Ошибка возникает из-за того, что нельзя использовать 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.

Блестяще. Большое спасибо.

nDelphi 28.03.2018 19:06

.... таким сложным хаком, когда все, что нужно, был COUNT(1) и правильный (один термин изменен) пункт WHERE. Бедная Жар-птица ...

Arioch 'The 29.03.2018 11:06

@ Arioch'The Это зависит от того, был ли код из вопроса упрощенный (без других деталей).

Mark Rotteveel 29.03.2018 11:11

@ Arioch'The я попробую с count (1) и посмотрю, что у меня получится. Думаю, я пробовал это и не получил ожидаемых результатов, потому что у меня есть другие таблицы, объединенные в других запросах. Я также пробовал здесь логическое значение перед ответом Марка, но у меня было THEN TRUE ELSE FALSE END, и это меня смутило, поскольку Firebird не принял это. Я должен упростить свои запросы, потому что они выходят из-под контроля, а я очень плохо разбираюсь в SQL.

nDelphi 29.03.2018 14:28

Вам также нужно будет сформулировать свою задачу, а затем сформулировать предложение WHERE, чтобы точно представить вашу задачу. Например, вы имеете в виду OR, AND или XOR? Например, должен ли регистр AND считаться как 1 или как 2? И т. Д. И т. Д. «Правильная постановка задачи - половина решения». Это вдвойне верно для SQL, который является ответвлением математической теории множеств, поэтому бумага с ручкой часто более эффективна для разработки и отладки запросов, чем любое руководство.

Arioch 'The 29.03.2018 15:17

Это решение не работает для других таблиц с аналогичной структурой. Единственное отличие - это названия полей. Что могло быть причиной? Если он работает для одного, он должен работать и с другим. Я могу получить данные в порядке, как с таблицами ключевых слов, но не с Count, он возвращает значение 0.

nDelphi 30.03.2018 06:41

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

Mark Rotteveel 30.03.2018 10:31

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