Как наложить условия на инструкцию «GROUP BY» — MySQL

#mysql

#mysql

Вопрос:

У меня есть следующий запрос MySQL:

 SELECT * 
  FROM products
 WHERE catalog = 1
 GROUP BY style
 ORDER BY name ASC
 limit 0, 100
  

Поскольку у меня есть несколько продуктов с одинаковым «стилем», это вернет информацию о любом первом продукте, который имеет определенный «стиль» (через условие GROUP BY).

Поскольку на некоторые товары предоставляется «скидка», мой вопрос заключается в следующем: КАК мне сделать так, чтобы условие «ГРУППИРОВАТЬ ПО стилю» отдавало первый приоритет продукту со скидкой? Моя конечная цель — использовать 1 запрос вместо того, чтобы после этого просматривать каждый возвращенный стиль и проверять, есть ли какие-либо товары со скидкой

Если я укажу «ГРУППИРОВАТЬ ПО стилю, со скидкой», он вернет 2 продукта с одинаковым стилем: 1 со скидкой и 1 без скидки. Это НЕ то, что мне нужно — мне нужно вернуть только 1 соответствующий (уникальный) стиль, но отдать предпочтение тем товарам, которые соответствуют этому стилю и на которые предоставляется скидка.

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

1. Что вы подразумеваете под «предпочтением»? Вам нужны только результаты со скидкой или вы хотите, чтобы сначала они были упорядочены по скидке, а затем остальные результаты?

2. @wes: Я хочу, чтобы результаты имели скидку, НО если скидки нет, я все равно хочу получать результаты.

3. если выходные данные для данного стиля [normal, discounted] возвращают только [со скидкой], но если это просто [normal] возвращает [normal]?

4. @Дэн: именно. не уверен, как поместить это в запрос.

5. вам нужен какой-либо товар со скидкой или товар с наибольшей скидкой?

Ответ №1:

Вы не можете наложить приоритет в пределах группового набора в одном запросе. Вы можете ограничить свои результаты, используя WHERE перед применением GROUP BY, но это просто лишит ваш результат строк, не удовлетворяющих условию WHERE. Чтобы найти порядок в сгруппированных наборах, используйте запрос, подобный этому: (предполагая, что id здесь является первичным ключом)

 SELECT p.* FROM
  ( SELECT style,max(discount) as highest_discount 
    FROM products
    WHERE catalog = 1
    GROUP BY style ) p1
JOIN products p
ON p.id =
  ( SELECT pu.id 
    FROM products pu
    WHERE pu.catalog = 1
      AND pu.style = p1.style
      AND pu.discount = p1.highest_discount
    LIMIT 1 )
  

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

1. Петр, это сработало как по волшебству. Однако для обработки запроса в моей системе потребовалось ~ 6 секунд (и 2,7 секунды на рабочем сервере), и это учитывая, что я ограничил его значением 0,12. В значительной степени это то же самое или медленнее, чем выполнение 2 запросов.

2. Это не должно быть так медленно, попробуйте EXPLAIN, чтобы увидеть, правильно ли используются индексы.

3. ИЗМЕНИТЬ ТАБЛИЦУ продуктов, ДОБАВИТЬ ИНДЕКС (каталог, стиль, скидку);

4. это ужасно. менее чем за 1 секунду на моей тестовой машине. Я думаю, мне следует заняться оптимизацией моих таблиц. еще раз спасибо! отличный ответ.

5. Исправленный ответ, в первом подзапросе был select * , но все, что нужно для ссылки на 2-й подзапрос, это просто style, max (скидка)

Ответ №2:

Взгляните на предложение «HAVING». Это должно приблизить вас. http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html

Ответ №3:

Когда вы говорите «приоритет товара со скидкой», приоритет подразумевает упорядочение, а не группировку. Вам нужно упорядочить свои результаты по discount (я предполагаю, что это столбец, а не таблица).

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

1. Я хочу, чтобы результаты выдавали мне поле со скидкой > 0. Если товаров со скидкой не существует, я все равно хочу получить результаты. видите ли, я не уверен, КАК инструкции «GROUP BY» выбирают, какую именно информацию о продукте (из всех продуктов, имеющих заданный стиль) отображать.

Ответ №4:

Я думаю, это можно сделать с помощью HAVING предложения; предполагая, что таблица скидок является логической, 1 для скидки, 0 для отсутствия скидки:

 SELECT * 
FROM 
  products 
WHERE 
  catalog = 1 
GROUP BY 
  style 
HAVING
  discount = MAX(discount)
ORDER BY 
  name ASC limit 0, 100
  

редактировать: возможно, я неправильно истолковал вопрос. Если все, что вы хотите, это чтобы товары со скидкой появлялись первыми в вашем списке, вам нужно будет только изменить ORDER BY предложение:

 SELECT * 
FROM 
  products 
WHERE 
  catalog = 1 
GROUP BY 
  style 
ORDER BY 
  discount DESC,
  name ASC 
LIMIT 
  0, 100
  

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

1. спасибо, но ни один из этих запросов не дает желаемого результата. решение piotrm, приведенное выше, выполняет эту работу.