Дайте приоритет второстепенному полю ORDER BY в MySQL

0

Я боролся с 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

Заранее спасибо.

  • 2
    как насчет ORDER BY time, correlation_id DESC ?
  • 0
    Нет, поскольку все равно будет отсортировано по time . В крайне редком случае, когда time в нескольких строках одинаковое, он упорядочит этот небольшой выбор по их correlation_id . Как видите, это не совсем то, что я ищу ...
Показать ещё 3 комментария
Теги:
sorting
sql-order-by

1 ответ

0
Лучший ответ

Демо в 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. Однако для понимания я думал, что покажу его.

  • 0
    Работает отлично, спасибо! Я использовал первый из ваших методов, так как мои запросы не будут превышать более 50 строк на страницу. Минимальный комментарий относительно обозначений, использующий A, C и D для имен псевдонимов таблиц, немного сбивает с толку, так как это также значение некоторых строк. Небольшое наблюдение для начинающих / неопытных программистов SQL, таких как я!
  • 0
    Извините за то, что я обычно называю псевдонимы лучше; но в спешке я вернулся к своей стенографии.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню