MySQL Order By в подзапросе

#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 подзапросе:

  1. Если я уберу ‘order by start_date’ в подзапросе, результат, который он возвращает, будет неправильным — у меня создалось впечатление, что в MySQL порядок подзапросов игнорируется?
  2. Насколько я понимаю, 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 .