Как использовать 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.