Результат вложенных SQL-инструкций в предложении WHERE

#mysql #sql

#mysql #sql

Вопрос:

У меня есть таблица beats , и для каждого такта в таблице есть несколько строк, содержащих разные цены pricing .

 SELECT b.id, b.name,
(SELECT p.price FROM pricing as p WHERE p.license = 1 AND p.beat_id = b.id) as price_1,
(SELECT p.price FROM pricing as p WHERE p.license = 2 AND p.beat_id = b.id) as price_2
FROM beats as b 
WHERE b.added > 0 
AND b.active = 1 
AND b.deleted = 0 
AND price_1 > 0
ORDER BY b.id DESC 
LIMIT 50
 

Я пытаюсь убедиться, что a beat извлекается только тогда, когда значение price_1 больше 0.

Это не работает, потому что вы не можете использовать результат вложенного оператора SQL в WHERE предложении, но я пробовал HAVING price_1 > 0 , и это тоже не работает.

Как я могу проверить price_1 и price_2 ?

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

1. Почему вы используете GROUP BY без каких-либо агрегатных функций?

2. @Barmar это была ошибка копирования / вставки, я исправил вопрос.

Ответ №1:

Вы можете переместить это условие в having предложение. Это особенность MySQL и не поддерживается другими базами данных:

 SELECT b.id, b.name,
       (SELECT p.price FROM pricing as p WHERE p.license = 1 AND p.beat_id = b.id) as price_1,
       (SELECT p.price FROM pricing as p WHERE p.license = 2 AND p.beat_id = b.id) as price_2
FROM beats as b 
WHERE b.added > 0 AND b.active = 1 AND b.deleted = 0 
GROUP BY b.producer 
HAVING price_1 > 0
ORDER BY b.id DESC 
LIMIT 50;
 

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

1. Ах, правильно, теперь это работает HAVING после GROUP BY того, как я поместил его чуть раньше. Спасибо за вашу помощь… теперь чувствую себя глупо!

2. @JohnRuddell Я всегда принимаю правильные ответы, но на этот вопрос ответили так быстро, что он не позволил мне сделать это сразу.

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

Ответ №2:

Вы можете использовать соединение:

 SELECT b.id, b.name, p1.price AS price_1, p2.price AS price_2
FROM beats AS b
JOIN pricing AS p1 ON p1.beat_id = b.id
JOIN pricing AS p2 ON p2.beat_id = b.id
WHERE b.added > 0 AND b.active = 1 AND b.deleted = 0
  AND p1.license = 1 AND p1.price > 0
  AND p2.licence = 2
GROUP BY b.producer
ORDER BY b.id DESC
LIMIT 50
 

Ответ №3:

В отсутствие DML для ваших таблиц (например, непонятно, зачем вам это нужно group by b.producer , учитывая, что b.id это выглядит как первичный ключ), минимальное изменение заключается в том, чтобы перенести вложенный запрос в подзапрос и выполнить для него внутреннее соединение

 SELECT b.id, b.name,
       p1.price as price_1,
       (SELECT p.price FROM pricing as p WHERE p.license = 2 AND p.beat_id = b.id) as price_2
  FROM beats as b
       JOIN pricing p1 ON (p1.license = 1 AND p1.beat_id = b.id AND p1.price > 0) 
 WHERE b.added > 0 
   AND b.active = 1 
   AND b.deleted = 0 
GROUP BY b.producer 
ORDER BY b.id DESC 
LIMIT 50
 

Предполагая, что b.id это первичный ключ, я бы также отбросил group by b.producer , и, вероятно, разумно включить запрос price_2 в соединение (хотя, опять же, без дополнительных знаний ваших данных и DML я не могу точно сказать, должно ли это быть внутреннее или левое внешнее соединение).