Задавайте вопросы, мы ответим
Вы не зашли.
Всем привет
столкнулся с проблемой сортировки выборки в MySQL. Почти весь день просидел, испробовал разные варианты, но нужного результата не добился. Возможно, кто-то подскажет правильное решение или просто еще один вариант "попробовать", потому что мне явно нужен свежий взгляд на проблему.
Итак, имеем таблицу MySQL (пожалуйста, смотрите вложение)
Имеем упрощенный до минимума ЗАПРОС 1
SELECT
order_id,
cost,
rd_id,
product_order_date
FROM report_data
GROUP BY WEEK(product_order_date)
Возвращает результат (РЕЗУЛЬТАТ 1)
order_id cost rd_id product_order_date
88164 0 1 0000-00-00 00:00:00
143747 0 3 2011-07-18 11:40:42
149491 10.1 19 2011-07-25 04:27:24
151797 138 66 2011-08-02 14:45:06
152271 94.14 109 2011-08-08 15:49:20
155702 94.14 166 2011-08-17 06:00:03
теперь выполним ЗАПРОС 2
SELECT
order_id,
cost,
rd_id,
product_order_date
FROM report_data
вернет все строки (РЕЗУЛЬТАТ 2) (публиковать не буду, так как слишком много записей)
смотрим РЕЗУЛЬТАТ 2. Видим, что действительно в неделю с 8-08 п- 14-08 первая запись была сделана 2011-08-08 15:49:20 и имеет rd_id=109, а в неделю с 15-08 по 21-08 первая запись сделана 2011-08-17 06:00:03 и имеет rd_id=166.
Теперь сравним с РЕЗУЛЬТАТом 1 и увидим, что ЗАПРОС 1 отработал правильно
Теперь в ЗАПРОС 1 добавим одну строку и получим ЗАПРОС 3
SELECT
GROUP_CONCAT(order_id) AS ids,
rd_id,
order_id,
cost,
product_order_date
FROM report_data
GROUP BY WEEK(product_order_date)
вернет РЕЗУЛЬТАТ 3
ids rd_id order_id cost product_order_date
88164,88165 1 88164 0 0000-00-00 00:00:00
143829,1438... 12 143829 0 2011-07-19 10:19:19
150957,1509... 52 150957 33.48 2011-07-29 12:00:20
152246,1522... 97 152246 42.54 2011-08-05 17:26:18
152358,1523... 146 152358 12.92 2011-08-11 12:05:02
155726,1557... 175 155726 63.72 2011-08-17 12:04:53
Видим, что для предпоследней строки почему-то выбрана запись с rd_id=146 и датой 2011-08-11 12:05:02, а для последней строки запись rd_id=175 и датой 2011-08-17 12:04:53
Таким образом получается, что GROUP_CONCAT() изменяет порядок группы
по ссылке http://lists.mysql.com/mysql/2664 прочел, что WEEK() не гарантирует выборку именно первой записи в группе. Но при этом, без GROUP_CONCAT() группировка правильная.
пробовал следующие запросы
ЗАПРОС 4
SELECT
rd_id,
order_id,
cost,
product_order_date,
WEEK(product_order_date) AS _week
FROM report_data
GROUP BY _week
ЗАПРОС 5
SELECT
GROUP_CONCAT(order_id) AS ids,
rd_id,
order_id,
cost,
product_order_date,
WEEK(product_order_date) AS _week
FROM report_data
GROUP BY _week
ЗАПРОС 4 возвращает результат, аналогичный РЕЗУЛЬТАТу 1, а ЗАПРОС 5 - аналогичный РЕЗУЛЬТАТу 3.
Заметил, что такой (баг?) наблюдается только при использовании функций дат в предложении группировки. Т.е замена WEEK() на DAY(), DAYOFYEAR(), MONTH() и другие функции даты не спасает - GROUP_CONCAT() изменяет порядок выборки
MIN(), MAX() на подходят по той причине, что дата может изменяться
Т.е, например:
запись с rd_id=2 имеет дату 2011-08-09 12:12:12, а запись с rd=3 имеет дату 2011-08-12 23:23:23. Это дата, когда запись была добавлена в таблицу или последний раз обновлялась.
rd_id date
2 2011-08-09 12:12:12
3 2011-08-12 23:23:23
Т.е. администратор может отредактировать запись с rd_id=2, например, 13 августа. Тогда таблица будет иметь вид
rd_id date
2 2011-08-13 12:12:12
3 2011-08-12 23:23:23
Значит MIN(rd_id) вернет неправильный результат.
Кстати, пробовал MIN() и MAX() применять к дате, но результата никакого: без GROUP_CONCAT() выборка правильная, с
GROUP_CONCAT() - неправильная
Пожалуйста, если кто знает решение проблемы или видит мою ошибку, подскажите.
Заранее спасибо
Неактивен
kolombetam написал:
смотрим РЕЗУЛЬТАТ 2. Видим, что действительно в неделю с 8-08 п- 14-08 первая запись была сделана 2011-08-08 15:49:20 и имеет rd_id=109, а в неделю с 15-08 по 21-08 первая запись сделана 2011-08-17 06:00:03 и имеет rd_id=166.
Теперь сравним с РЕЗУЛЬТАТом 1 и увидим, что ЗАПРОС 1 отработал правильно
Если Вы указали в SELECT поля, по которым не производится группировка без аггрегирующих функций (MAX, SUM, AVG, GROUP_CONCAT, ...), то MySQL выберет произвольного представителя группы. Стандарт SQL запрещает такие запросы, но MySQL, к сожалению, их обрабатывает из-за чего возникают не предсказуемые результаты.
Таким образом, ваш запрос не гарантирует вам выдачу первой записи из группы. И тот факт, что выбрана первая запись в группе всего лишь случайность и в следующий раз результат может быть иным.
Неактивен
Спасибо за ответ
Если я правильно понял, то нужно в SELECT использовать аггрегирующие функции. Изменил запрос
Неактивен
kolombetam написал:
Если я правильно понял, то нужно в SELECT использовать аггрегирующие функции.
Да.
kolombetam написал:
Изменил запрос
SELECT
CONCAT(t._date)
FROM (SELECT
order_id,
product_order_date AS _date
FROM report_data) AS t
GROUP BY WEEK(t._date)
Подзапрос нужен для того, чтобы сортировать порядок в группе.
Что-то от меня ускользает смысл данного запроса.
1. Ваш подзапрос ничего не сортирует.
2. Даже если добавить в него order by это ничего не изменит.
Используйте min, max по отношению к дате, чтобы выбрать 1ую/последнюю запись за неделю.
Неактивен
Например:
Неактивен
Хочу вас огорчить но большинство ваших выводов ошибочные.
Напишите коротко содержания таблицы, и как должен выглядеть результат который хотите получить + короткое словесное описание.
Вам покажут как это делается, и потом будите изучать уже рабочий пример.
Неактивен
Спасибо за ответы! Совет с использованием MIN(), MAX() очень выручил. Действительно, свежий взгляд - новое решение.
В итоге все оказалось намного проще по сравнению с теми дебрями, куда я залез. Подзапрос, как и Вы и говорили, vasya, оказался не нужен
Неактивен
kolombetam написал:
В итоге все оказалось намного проще по сравнению с теми дебрями, куда я залез. Подзапрос, как и Вы и говорили, vasya, оказался не нужен
Это вы ещё не успели залезть И подзапрос вам понадобится, только другой.
Если администратор отредактирует запись с rd_id=2, например, 13 августа. Тогда таблица будет иметь вид
rd_id date
2 2011-08-13 12:12:12
3 2011-08-12 23:23:23
И MIN(r_id) не будет соответствовать MIN(date), т.е. ваш последней запрос вернет вам ошибочный результат.
Правильный вариант:
Неактивен
Спасибо за помощь и правильное направление!
итоговый запрос получился следующий. #A#, #B#, #C#, #D#, #X#, #Y#, #Z# - произвольные названия полей. Всего в таблице 62 поля, по каждому из них пожет быть/не быть сортировка, группировка, конкатенация, сумма и т.п.
Отредактированно kolombetam (24.08.2011 17:20:43)
Неактивен
А зачем в вашем примере JOIN?
Неактивен
отредактировал сообщение выше. Выбраются еще некоторые значения без аггрегирующих функий
Неактивен