#mysql
Вопрос:
Я пытаюсь решить эту проблему на уровне хакера:
Ввод (таблица проектов)
Вывод:
2015-10-28 2015-10-29
2015-10-30 2015-10-31
2015-10-13 2015-10-15
2015-10-01 2015-10-04
Итак, проблема заключается в том, чтобы обрабатывать последовательные даты окончания как часть одного проекта и возвращать даты начала и окончания проектов, упорядоченных по разнице дат в порядке возрастания. Как вы можете видеть из приведенного выше примера, задачи 1,2,3 находятся в том же проекте, задачи 4,5 находятся в том же проекте, а задачи 7 и 8 являются их собственными проектами.
Это одно из решений, которые я нашел:
set @sdate = null;
set @nextdate = null;
select sd, max(ed) ed2
from (
select if(@nextdate = start_date, @sdate, @sdate := start_date) as sd,
@nextdate := end_date as ed
from Projects
order by start_date
) tmp
group by sd
order by datediff(max(ed), sd)
Он использует переменные для хранения предыдущей даты окончания и сравнения ее с текущей строкой, но меня смущает предложение в order by
подзапросе:
- Если я уберу ‘order by start_date’ в подзапросе, результат, который он возвращает, будет неправильным — у меня создалось впечатление, что в MySQL порядок подзапросов игнорируется?
- Насколько я понимаю, order by выполняется после выбора, поэтому здесь он будет упорядочивать результаты из select в подзапросе, но похоже, что на самом деле он упорядочивает исходную таблицу (Свойства) перед оператором select — я прав?
Может кто-нибудь помочь мне понять, почему это так? Спасибо
Ответ №1:
ORDER BY
В подзапросе необходимо, чтобы назначение переменной работало. Это похоже на идею присвоения номеров строк в более старой версии MySQL. Когда вы запускаете:
SELECT *
FROM Projects;
Без ORDER BY
вы получите почти каждое Start_date
значение в порядке возрастания, за исключением Start_date
of 2015-11-04
until 2015-11-07
, которое дает вам результат в этом порядке:
...
ID Start_date End_date
16 2015-11-04 2015-11-05
10 2015-11-07 2015-11-08
15 2015-11-06 2015-11-07
11 2015-11-05 2015-11-06
...
Он начинается с 4, но затем следующий — 7,6, затем 5. Это нарушает присвоение переменной. Если вы запустите запрос следующим образом:
SELECT *,IF(@nextdate = start_date, @sdate, @sdate := start_date) AS sd,
@nextdate := end_date AS ed
FROM Projects;
Вы можете видеть разницу в результатах, где Start_date
находится в правильном порядке по сравнению с неправильным порядком:
----- ------------ ------------ ------------ ------------
| ID | Start_date | End_date | sd | ed |
----- ------------ ------------ ------------ ------------
| 1 | 2015-10-01 | 2015-10-02 | 2015-10-01 | 2015-10-02 |
| 24 | 2015-10-02 | 2015-10-03 | 2015-10-01 | 2015-10-03 |
| 2 | 2015-10-03 | 2015-10-04 | 2015-10-01 | 2015-10-04 |
| 23 | 2015-10-04 | 2015-10-05 | 2015-10-01 | 2015-10-05 |
.......
| 3 | 2015-10-11 | 2015-10-12 | 2015-10-11 | 2015-10-12 |
| 22 | 2015-10-12 | 2015-10-13 | 2015-10-11 | 2015-10-13 |
.......
| 16 | 2015-11-04 | 2015-11-05 | 2015-11-04 | 2015-11-05 |
| 10 | 2015-11-07 | 2015-11-08 | 2015-11-07 | 2015-11-08 |
| 15 | 2015-11-06 | 2015-11-07 | 2015-11-06 | 2015-11-07 |
| 11 | 2015-11-05 | 2015-11-06 | 2015-11-05 | 2015-11-06 |
----- ------------ ------------ ------------ ------------
Поскольку подзапрос возвращает результат, подобный приведенному выше, в результате чего 3 строки должны фактически генерироваться sd=2015-11-04
, но вместо этого имеют другое значение, внешний запрос GROUP BY
затем выдаст 14 строк результатов. Добавив ORDER BY Start_date
в подзапрос, вы получите результат для 2015-11-04
until 2015-11-07
, подобный этому:
---- ------------ ------------ ------------ ------------
| ID | Start_date | End_date | sd | ed |
---- ------------ ------------ ------------ ------------
| 16 | 2015-11-04 | 2015-11-05 | 2015-11-04 | 2015-11-05 |
| 11 | 2015-11-05 | 2015-11-06 | 2015-11-04 | 2015-11-06 |
| 15 | 2015-11-06 | 2015-11-07 | 2015-11-04 | 2015-11-07 |
| 10 | 2015-11-07 | 2015-11-08 | 2015-11-04 | 2015-11-08 |
---- ------------ ------------ ------------ ------------
Итак, на самом деле не порядок делает ответ неправильным, а дополнительные строки в конечном результате.
Комментарии:
1. спасибо за ответ, поэтому я понимаю
order by
, что это упорядочивает входные данные так, чтобы следующая строка была либо последовательным днем, либо нет, что делает присвоение переменной в зависимости от этого условия работы — это правильная идея? Потому что исходная таблица может располагаться не в таком порядке. если да, то order by выполняется перед select (тот, что в подзапросе, который выполняет присвоение переменной), поэтому он фактически сначала упорядочивает таблицу проектов, а затем поверх нее выполняется select?2. Да, это идея, и yes
order by
выполняется раньшеselect
.