Как использовать DISTINCT и ORDER BY в одном операторе SELECT?


118

После выполнения следующего оператора:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

Я получаю из базы данных следующие значения:

test3
test3
bildung
test4
test3
test2
test1

но я хочу удалить дубликаты, например:

bildung
test4
test3
test2
test1

Я пытался использовать DISTINCT, но он не работает с ORDER BY в одном выражении. Пожалуйста помоги.

Важный:

  1. Я пробовал это с:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC

    это не работает.

  2. Заказ по CreationDate очень важен.


1
Как это не работает? Неправильный вывод?
— Fedearne

Ответы:


195

Проблема в том, что столбцы, используемые в ORDER BY, не указаны в DISTINCT. Для этого вам нужно использовать агрегатную функцию для сортировки и использовать GROUP BYдля выполнения DISTINCTработы.

Попробуйте что-то вроде этого:

SELECT DISTINCT Category, MAX(CreationDate) 
FROM MonitoringJob 
GROUP BY Category 
ORDER BY MAX(CreationDate) DESC, Category

99
Вам даже не нужно ключевое слово DISTINCT, если вы группируете по категориям.
— MatBailie,

18

Ключевые столбцы расширенной сортировки

Причина, по которой то, что вы хотите сделать, не работает, заключается в логическом порядке операций в SQL , который для вашего первого запроса (упрощенно):

  • FROM MonitoringJob
  • SELECT Category, CreationDateт.е. добавить так называемый расширенный ключевой столбец сортировки
  • ORDER BY CreationDate DESC
  • SELECT Categoryт.е. снова удалите столбец расширенного ключа сортировки из результата.

Таким образом, благодаря стандартной функции расширенного ключевого столбца сортировки SQL , можно полностью упорядочить то, чего нет в SELECTпредложении, потому что оно временно добавляется к нему за кулисами.

Итак, почему это не работает DISTINCT?

Если мы добавим DISTINCTоперацию, она будет добавлена ​​между SELECTи ORDER BY:

  • FROM MonitoringJob
  • SELECT Category, CreationDate
  • DISTINCT
  • ORDER BY CreationDate DESC
  • SELECT Category

Но теперь, с расширенным ключевым столбцом сортировки CreationDate , семантикаDISTINCT операции была изменена, поэтому результат больше не будет прежним. Это не то, что мы хотим, поэтому и стандарт SQL, и все разумные базы данных запрещают такое использование.

обходные

Его можно эмулировать с помощью стандартного синтаксиса следующим образом

SELECT Category
FROM (
  SELECT Category, MAX(CreationDate) AS CreationDate
  FROM MonitoringJob
  GROUP BY Category
) t
ORDER BY CreationDate DESC

Или просто (в данном случае), как показал также Прутсвондер

SELECT Category, MAX(CreationDate) AS CreationDate
FROM MonitoringJob
GROUP BY Category
ORDER BY CreationDate DESC

Я подробно писал о SQL DISTINCT и ORDER BY здесь .


1
Я думаю, вы ошибаетесь в том, как DISTINCT ONработает, и почти уверен, что это не поможет. Выражение в круглых скобках - это то, что используется для определения отличимости (условия группировки). Если есть разные категории с одинаковыми CreationDateименами, то в результате появится только одна из них! Так как мне было интересно, не ошибся ли я в чем-то, я также загрузил пример базы данных в ваш блог, чтобы перепроверить: DISTINCT ONзапрос, который вы там дали, дал в общей сложности 1000 результатов (с большим количеством дубликатов length), в то время как запрос ниже дал всего 140 (уникальных) значений.
— Инклинг

@Inkling: Спасибо за уделенное время. OP явно хочет удалить «дубликаты». См. Формулировку OP «но я хочу, чтобы дубликаты были удалены, вот так» . Вы, наверное, ошиблись при копировании запросов из моего сообщения в блоге. Есть два запроса: один использует DISTINCT(нет ON), а другой - DISTINCT ON. Обратите внимание, что последнее явно не удаляет повторяющиеся длины, а дублирующие заголовки. Думаю, что мой ответ здесь совершенно правильный.
— Лукас Эдер

1
Я хочу сказать, что ваши DISTINCT ONусловия удаляют дубликаты с использованием неправильного условия. В вашем сообщении в блоге DISTINCT ONзапрос действительно удаляет повторяющиеся заголовки , однако DISTINCTзапрос над ним и запрос под ним (который, как вы утверждаете, является «синтаксическим сахаром») удаляют повторяющиеся длины , что, по-видимому, и является всей целью. То же самое применимо и здесь: OP хочет удалить повторяющиеся категории , а не дублировать CreationDates, как это DISTINCT ONделает запрос. Если вы мне все еще не верите, проверьте сами.
— Инклинг

6

Если вывод MAX (CreationDate) не требуется - как в примере исходного вопроса - единственным ответом является второе утверждение ответа Прашанта Гупты:

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

Объяснение: вы не можете использовать предложение ORDER BY во встроенной функции, поэтому оператор в ответе Prutswonder не может использоваться в этом случае, вы не можете поместить вокруг него внешний выбор и отбросить часть MAX (CreationDate).


2

Просто используйте этот код, если вам нужны значения столбцов [Категория] и [CreationDate]

SELECT [Category], MAX([CreationDate]) FROM [MonitoringJob] 
             GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

Или используйте этот код, если вам нужны только значения столбца [Категория].

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

У вас будут все отличные записи, какие захотите.


эти фигурные скобки [] совершенно сбивают с толку ... это правильный синтаксис SQL?
— m13r

1
Скобки предназначены для экранирования ключевых слов, таких как порядок, событие и т. Д., Поэтому, если у вас есть (например) столбец в вашей таблице с именем, Eventвы можете писать [Event]вместо того, Eventчтобы SQL не вызывал ошибку синтаксического анализа.
— Бен Максфилд,

1

2) Порядок по дате создания очень важен

Исходные результаты показали, что "test3" дал несколько результатов ...

Очень легко начать использовать MAX постоянно, чтобы удалить дубликаты в Group By ... и забыть или проигнорировать основной вопрос ...

ОП предположительно понял, что использование MAX дает ему последнее «созданное», а использование MIN дает первое «созданное» ...


3
На самом деле это не похоже на ответ на вопрос, это, похоже, комментарий к использованию других респондентов MAX, а не что-то отдельное в качестве ответа на вопрос.
— DaveyDaveDave 01

0
if object_id ('tempdb..#tempreport') is not null
begin  
drop table #tempreport
end 
create table #tempreport (
Category  nvarchar(510),
CreationDate smallint )
insert into #tempreport 
select distinct Category from MonitoringJob (nolock) 
select * from #tempreport  ORDER BY CreationDate DESC

0

По подзапросу он должен работать:

    SELECT distinct(Category) from MonitoringJob  where Category in(select Category from MonitoringJob order by CreationDate desc);

Эммм ... Не думаю, что так будет. Внешний выбор не сортируется.
— Хосам Эль-Дин,

это не сработает, я здесь, потому что это не работает
— Амирреза

-1

Distinct отсортирует записи в порядке возрастания. Если вы хотите отсортировать по убыванию, используйте:

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

Если вы хотите отсортировать записи на основе поля CreationDate, это поле должно быть в операторе выбора:

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC

12
Это будет выполнено, но не даст того, что нужно OP. OP хочет отдельные категории, а не отдельные комбинации категорий и CreateDate. Этот код может дать несколько экземпляров одной и той же категории, каждый с разными значениями CreationDate.
— MatBailie

-1

Вы можете использовать CTE:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

SELECT Distinct_Category 
FROM DistinctMonitoringJob 
ORDER BY Distinct_Category DESC

-3

Попробуйте следующий, но это бесполезно для огромных данных ...

SELECT DISTINCT Cat FROM (
  SELECT Category as Cat FROM MonitoringJob ORDER BY CreationDate DESC
);

4
«Предложение ORDER BY недопустимо в представлениях, встроенных функциях, производных таблицах, подзапросах и общих табличных выражениях, если также не указаны TOP или FOR XML».
— TechplexEngineer 01

Это не работает, потому что вы не указали столбец CreationDate в заказе по.
— Mauro Bilotti

1
@TechplexEngineer Ваш комментарий неверен. Использование ORDER BYв подзапросах абсолютно допустимо. А кто-то даже проголосовал за ваш неверный комментарий.
— Racil Hilan

Я пытаюсь это сделать, и у меня такая же ошибка с @TechplexEngineer. Я использую индивидуальный заказ со случаем когда.
— Эге Байрак

-4

Это можно сделать с помощью внутреннего запроса.

$query = "SELECT * 
            FROM (SELECT Category  
                FROM currency_rates                 
                ORDER BY id DESC) as rows               
            GROUP BY currency";

-5
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC

2
мне нужно отсортировать по дате создания !! это очень важно
— rr

Неужели нельзя самостоятельно добавить столбец, который хотите заказать? В вашем примере записи упорядочены в алфавитном порядке. Если вам нужно упорядочить по дате создания, просто добавьте его. Это действительно не так уж и сложно.
— Furicane

8
-1: ОП пробовал это, но это не сработало, потому что это невозможно, и вы, очевидно, проигнорировали этот факт, покровительствуя ОП. Дело в том, что оператор DISTINCT сопоставляет несколько записей с одним и тем же значением категории, каждая с потенциально разными датами создания. Таким образом, при использовании DISTINCT это невозможно. Это подталкивает требуемую логику к GROUP BY вместо DISTINCT, позволяя агрегат (MAX) на дату создания.
— MatBailie

На самом деле, если вы внимательно посмотрите на то, что сделал OP, который является абсолютно некорректным SQL - я не сделал ни одной ошибки, и приведенный результат соответствует тому, который он запросил. Я не буду заморачиваться на -1, просто прочтите в следующий раз, прежде чем исправлять людей. Спасибо.
— Furicane

8
Вы прямо предлагаете добавить поле CreationDate, даже говоря, что «это действительно не так уж и сложно». Это приведет к искажению SQL. Вы получили -1 за покровительство OP, предоставление совета, возвращающего OP к заявлению, которое он изначально опубликовал, и неспособность заметить противоречие между DISTINCT и упорядочиванием по полю, не входящему в DISTINCT. Кроме того, «b» стоит перед «t», а «1» - перед «4», поэтому результаты, предоставляемые OP, категорически не в алфавитном порядке. Тогда позвольте мне предложить ваш собственный совет: прочтите (более внимательно) в следующий раз.
— MatBailie,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.