Я боролся с MySQL-запросом, и, похоже, я не могу найти решение проблемы.
У меня есть база данных документов, которые я хочу заказать по времени. Очень просто. Усложнение заключается в следующем: если два или более документа имеют одно и то же значение в столбце, называемом correlation_id
, я хочу, чтобы они располагались рядом друг с другом. Если я сначала упорядочиваю по correlation_id
, то коррелированные строки будут располагаться сверху или снизу. Я хочу, чтобы они были размещены в месте расположения самого последнего документа.
В качестве примера предположим, что у меня есть список документов, а документы B
и D
"коррелированы" с идентификатором, просто число, которое они имеют в общем столбце.
Когда я использую время ORDER BY time
, выход:
time document correlation_id
1h A 0
2h B 1
4h C 0
4h D 1
6h E 0
Когда я использую ORDER BY correlation_id, time
, таблица становится в основном упорядоченной по корреляции и даст:
time document correlation_id
2h B 1
4h D 1
1h A 0
4h C 0
6h E 0
Я не хочу, чтобы коррелированные элементы были размещены сверху или снизу, но в позиции самого последнего документа, чтобы он выглядел так:
time document correlation_id
1h A 0
2h B 1
4h D 1
4h C 0
6h E 0
В качестве запроса он должен выглядеть следующим образом:
SELECT * FROM DOCUMENTS ORDER BY [if (correlation_id<>0) {order by correlation_id first}], time DESC
Заранее спасибо.
Демо в Rextester для обоих ответов ниже.
Я не сторонник использования selects в selects... Соединение, чтобы получить минимальное время, и группировка кажется, что их будет сложнее поддерживать; и добавил к путанице. Таким образом, выбор в select может быть легче понять и поддерживать, хотя в конечном итоге он должен быть медленнее.
Мы используем select для получения минимального времени для каждого не-корреляционного_ID; для тех, которые равны нулю, мы просто используем время записи. и объединить эти два значения, давая нам столбец MinTime, который мы можем затем сначала заказать, а затем по времени, чтобы получить желаемый порядок.
SELECT BaseSet.*, coalesce((SELECT min(time) MT
FROM DOCUMENTS MinCorT
WHERE MinCorT.Correlation_ID = BaseSet.Correlation_ID
and correlation_ID <> 0), time) MINTIME
FROM documents BaseSet
ORDER BY MINTIME, Time
Другой подход, который, как я считаю, быстрее (тем более, у вас больше строк), но сложнее понять/поддерживать.
SELECT BaseSet.*, coalesce(MinCorT.MinTime, BasetSet.Time) MinTime
FROM documents BaseSet
LEFT JOIN (SELECT min(Time) MinTime, Correlation_ID
FROM Documents MinCorT
WHERE Correlation_ID <> 0
GROUP BY Correlation_Id) B
on BaseSet.Correlation_ID = MinCorT.Correlation_ID
ORDER BY MinTime, time
Во втором запросе предполагается, что у вас есть указатель на идентификатор корреляции, время. Причина, по которой второй запрос будет быстрее, состоит в том, что он должен выполнить одно только одно соединение. В то время как первый запрос должен выполнить подзапрос для каждой записи в документах. Таким образом, вы можете видеть, что больше документов у вас медленнее, чем запрос.
Второй запрос генерирует подмножество данных (MinCorT), содержащих минимальное время для каждого идентификатора корреляции. Мы LEFT присоединяем базовый набор к этому набору, поэтому у нас есть минимальное время для каждого документа, имеющего идентификатор corre_ID. Мы используем coalesce, чтобы использовать время базового документа в ситуациях, когда идентификатор корреляции равен 0 (нет записи mintime). Мы снова закончим столбец aa MinTime, который мы можем упорядочить по столбцу времени и времени, чтобы создать желаемый порядок.
Второй подход - это больше кода и, следовательно, более сложно поддерживать, но он должен работать с большей производительностью в долгосрочной перспективе.
Учитывая ваши данные образца; оба запроса приводят к:
+------+----------+----------------+---------+
| Time | document | Correlation_ID | MinTime |
+------+----------+----------------+---------+
| 1h | A | 0 | 1h |
| 2h | B | 1 | 2h |
| 4h | D | 1 | 2h |
| 4h | C | 0 | 4h |
| 6h | E | 0 | 6h |
+------+----------+----------------+---------+
Хотя во втором мы могли бы перемещать коалесценцию до порядка и вообще не иметь столбец MinTime. Однако для понимания я думал, что покажу его.
ORDER BY time, correlation_id DESC
?time
. В крайне редком случае, когдаtime
в нескольких строках одинаковое, он упорядочит этот небольшой выбор по ихcorrelation_id
. Как видите, это не совсем то, что я ищу ...