Интересный mysql запрос

S5
На сайте с 04.01.2010
Offline
77
759

Доброго времени суток. Столкнулся с необычной для меня траблой, не могу её грамотно победить. Суть следующая, есть запрос:


SELECT p.product_id,
(SELECT AVG(rating) AS total FROM c_review r1 WHERE r1.product_id = p.product_id AND r1.status = '1' GROUP BY r1.product_id) AS rating,
p.price as price,
(SELECT price FROM c_product_discount pd2 WHERE pd2.product_id = p.product_id AND pd2.customer_group_id = '1' AND pd2.quantity = '1' AND ((pd2.date_start = '0000-00-00' OR pd2.date_start < NOW()) AND (pd2.date_end = '0000-00-00' OR pd2.date_end > NOW())) ORDER BY pd2.priority ASC, pd2.price ASC LIMIT 1) AS discount,
(SELECT price FROM c_product_special ps WHERE ps.product_id = p.product_id AND ps.customer_group_id = '1' AND ((ps.date_start = '0000-00-00' OR ps.date_start < NOW()) AND (ps.date_end = '0000-00-00' OR ps.date_end > NOW())) ORDER BY ps.priority ASC, ps.price ASC LIMIT 1) AS special
FROM c_product_to_category p2c LEFT JOIN c_product p ON (p2c.product_id = p.product_id) LEFT JOIN c_product_description pd ON (p.product_id = pd.product_id) LEFT JOIN c_product_to_store p2s ON (p.product_id = p2s.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND p2c.category_id = '60' AND p.product_id IN(42) GROUP BY p.product_id ORDER BY rating DESC, LCASE(pd.name) DESC LIMIT 0,15

Получаем часть характеристик через вложенные запросы. Нужно к этому значению достучатся и сделать дополнительные проверки в WHERE. Беда в том, что полученный и обьявленный через AS результат для столбца недоступен в WHERE, это фича mysql. Конкретно в моем случае, нужно сделать часть проверок для special, такого плана

WHERE (special != NULL AND special > price AND special > 200) AND (special != NULL AND special > price AND special < 900)

Пытался это дело сделать через пользовательские переменные, почему-то не получилось, если кто-то покажет рабочий пример - буду очень признателен. Второй вариант, более грубый и менее практичный, завести отдельное поле в таблице и перед выборкой делать апдейт для этого значения и селектить уже его, без вложенных запросов. Может кому ещё какие варианты в голову прийдут, было бы интересно. Спасибо

doctorpc
На сайте с 12.07.2009
Offline
112
#1

Без повторения всей конструкции это технически невозможно, т.к. WHERE происходит хронологически до SELECT.

http://stackoverflow.com/questions/356675/using-an-alias-in-a-where-clause

http://stackoverflow.com/questions/200200/can-you-use-an-alias-in-the-where-clause-in-mysql

Возможно, Вам поможет HAVING?

IL
На сайте с 20.04.2007
Offline
435
#2
doctorpc:
Возможно, Вам поможет HAVING?

Он помогает для "агрегативных" функций.

К "AS `field`" можно достучаться, запихнув его в ещё один вложенный подзапрос. Эффективность - под вопросом, но вариант работающий..


SELECT * FROM (
-- тут тот самый большой запрос
) subquery
WHERE (special != NULL AND special > price AND special > 200) AND (special != NULL AND special > price AND special < 900)

Либо JOIN-ить c результатом запроса (В данном случае, похоже, не особо подходящий вариант, но в общем выглядит примерно так:

SELECT ... FROM table
INNER JOIN (SELECT hars ... ) subquery on subquery.id = table.id
... :) Облачные серверы от RegRu - промокод 3F85-3D10-806D-7224 ( http://levik.info/regru )
doctorpc
На сайте с 12.07.2009
Offline
112
#3
ivan-lev:
Он помогает для "агрегативных" функций.

Уточню. Having позволяет добавить фильтр уже после "агрегативных" фунций, а не до, как в случае с WHERE.

Если в конкретном запросе, нет разницы, когда применять фильтр (до Group by или после), то можно попробывать использовать HAVING как вариант.

Милованов Ю.С
На сайте с 24.01.2008
Offline
196
#4

Еще как вариант: запихивать результат выборки во временную таблицу, и из нее уже делать выборку по условию. Вариант не самый трушный, особенно если в результате выборки 100500 строк, а с условием всего 5 строк.

Подпись))
LEOnidUKG
На сайте с 25.11.2006
Offline
1774
#5

Если дело происходит в скрипте, то почему условие не поставить уже в самом цикле PHP?

✅ Мой Телеграм канал по SEO, оптимизации сайтов и серверов: https://t.me/leonidukgLIVE ✅ Качественное и рабочее размещение SEO статей СНГ и Бурж: https://getmanylinks.ru/ ✅ Настройка и оптимизация серверов https://getmanyspeed.ru/
edogs software
На сайте с 15.12.2005
Offline
775
#6
sg552:
Доброго времени суток. Столкнулся с необычной для меня траблой, не могу её грамотно победить. Суть следующая, есть запрос:

Получаем часть характеристик через вложенные запросы. Нужно к этому значению достучатся и сделать дополнительные проверки в WHERE. Беда в том, что полученный и обьявленный через AS результат для столбца недоступен в WHERE, это фича mysql. Конкретно в моем случае, нужно сделать часть проверок для special, такого плана

Пытался это дело сделать через пользовательские переменные, почему-то не получилось, если кто-то покажет рабочий пример - буду очень признателен. Второй вариант, более грубый и менее практичный, завести отдельное поле в таблице и перед выборкой делать апдейт для этого значения и селектить уже его, без вложенных запросов. Может кому ещё какие варианты в голову прийдут, было бы интересно. Спасибо

Судя по монстряческим запросам похоже на битрикс, если оно, то Вас могут спасти инфоблоки 2.0 ихние.

Если не битрикс, то в целом отдельное поле в таблице это как раз наиболее простой и правильный способ - по сути это кэширование, не только упрощающее, но и ускоряющее работу.

Разработка крупных и средних проектов. Можно с криптой. Разумные цены. Хорошее качество. Адекватный подход. Продаем lenovo legion в спб, дешевле магазинов, новые, запечатанные. Есть разные. skype: edogssoft
S5
На сайте с 04.01.2010
Offline
77
#7

Всем большое спасибо, помогло завернуть запрос в ещё один запрос, сделав его весь вложенным. Не знал такого финта ушами :) По поводу временных таблиц - думал, при наличии 1500+ товаров не самый лучший вариант, но все же лучше чем доп. поле и его апдейт перед выборкой. Что касательно доп поля в таблице, special зависит от группы пользователя, текущей даты и т.д. В общем, его всегда нужно обновлять перед запросом, что есть не правильно. Спасибо за направление, пошел дальше ваять :)

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий