Эти два запроса, кажется, возвращают те же результаты. Это случайно, или они - действительно то же?
1.
SELECT t.ItemNumber,
(SELECT TOP 1 ItemDescription
FROM Transactions
WHERE ItemNumber = t.ItemNumber
ORDER BY DateCreated DESC) AS ItemDescription
FROM Transactions t
GROUP BY t.ItemNumber
2.
SELECT DISTINCT(t.ItemNumber),
(SELECT TOP 1 ItemDescription
FROM Transactions
WHERE ItemNumber = t.ItemNumber
ORDER BY DateCreated DESC) AS ItemDescription
FROM Transactions t
Немного объяснения: я пытаюсь получить отличный список объектов от таблицы, полной транзакций. Для каждого объекта я ищу ItemNumber (поле идентификации) и новый ItemDescription.
В вашем примере №2 я некоторое время почесал голову - я подумал: «Вы не можете ОТЛИЧИТЬ
один столбец, что бы это значило?» - пока я не понял, что происходит.
Когда у вас есть
SELECT DISTINCT(t.ItemNumber)
, вы не , несмотря на внешность, на самом деле запрашиваете различные значения из t.ItemNumber
! Ваш пример №2 фактически анализируется так же, как
SELECT DISTINCT
(t.ItemNumber)
,
(SELECT TOP 1 ItemDescription
FROM Transactions
WHERE ItemNumber = t.ItemNumber
ORDER BY DateCreated DESC) AS ItemDescription
FROM Transactions t
, с синтаксически правильными, но лишними круглыми скобками вокруг t.ItemNumber
. DISTINCT
применяется к набору результатов в целом.
В этом случае, поскольку ваша GROUP BY
группирует по столбцу, который фактически изменяется, вы получите те же результаты.На самом деле я немного удивлен, что SQL Server (в примере GROUP BY
) не настаивает на том, чтобы столбец с подзапросом упоминался в списке GROUP BY
.
Если вы используете по крайней мере 2005 год и можете использовать CTE , это немного чище, ИМХО.
РЕДАКТИРОВАТЬ: Как указано в ответе Мартина , это также работает намного лучше.
;with cteMaxDate as (
select t.ItemNumber, max(DateCreated) as MaxDate
from Transactions t
group by t.ItemNumber
)
SELECT t.ItemNumber, t.ItemDescription
FROM cteMaxDate md
inner join Transactions t
on md.ItemNumber = t.ItemNumber
and md.MaxDate = t.DateCreated
Поскольку вы не используете какие-либо агрегатные функции, SQL Server должен быть достаточно умен, чтобы рассматривать GROUP BY
как a ОТЛИЧИТЕЛЬНЫЙ
.
Возможно, вас заинтересует следующий пост Stack Overflow для дальнейшего чтения по этой теме:
GROUP BY
необходим для правильного возврата результатов при использовании агрегатных функций в запросе sql. Поскольку вы не используете агрегатную функцию, нет необходимости в GROUP BY
, и, следовательно, запросы такие же.
Те же результаты, но у второго, похоже, более дорогой шаг сортировки для применения DISTINCT
на моем быстром тесте.
Оба были выбиты из поля зрения ROW_NUMBER
, хотя...
with T as
(
SELECT ItemNumber,
ItemDescription,
ROW_NUMBER() OVER ( PARTITION BY ItemNumber ORDER BY DateCreated DESC) AS RN
FROM Transactions
)
SELECT * FROM T
WHERE RN=1
edit ...который в свою очередь был побежден решением Джо на моей тестовой установке.
Test Setup
CREATE TABLE Transactions
(
ItemNumber INT not null,
ItemDescription VARCHAR(50) not null,
DateCreated DATETIME not null
)
INSERT INTO Transactions
SELECT
number, NEWID(),DATEADD(day, cast(rand(CAST(newid() as varbinary))*10000
as int),getdate())
FROM master.dbo.spt_values
ALTER TABLE dbo.Transactions ADD CONSTRAINT
PK_Transactions PRIMARY KEY CLUSTERED
(ItemNumber,DateCreated)
Основываясь на данных и простых запросах, обе программы вернут одинаковые результаты. Однако фундаментальные операции сильно отличаются.
DISTINCT
, как опередил меня AakashM, применяется к всем значениям столбцов, включая значения из подвыборок и вычисляемых столбцов. Все, что делает DISTINCT
- это удаляет дубликаты, основанные на всех задействованных столбцах, из видимости. Вот почему его принято считать хаком, потому что люди используют его для избавления от дубликатов, не понимая, почему запрос возвращает их в первую очередь (потому что они должны использовать IN
или EXISTS
, а не объединение, как правило). PostgreSQL - единственная известная мне база данных с предложением DISTINCT ON
, которое работает так, как, вероятно, и предполагал ОП.
Предложение GROUP BY
отличается - его основное назначение заключается в группировке для точного использования агрегатной функции. Чтобы обеспечить эту функцию, значения столбцов будут уникальными значениями на основе того, что определено в предложении GROUP BY. В этом запросе никогда не понадобится DISTINCT, потому что интересующие значения уже уникальны.
Это плохой пример, потому что он представляет DISTINCT и GROUP BY как равнозначные, хотя это не так.
Да, они возвращают те же результаты.
Обычно предложение group by (найдено здесь ) группирует строки по указанному столбцу, поэтому, если у вас есть сумма в вашем операторе select. Таким образом, если у вас есть таблица вроде:
O_Id OrderDate OrderPrice Customer
1 2008/11/12 1000 Hansen
2 2008/10/23 1600 Nilsen
3 2008/09/02 700 Hansen
4 2008/09/03 300 Hansen
5 2008/08/30 2000 Jensen
6 2008/10/04 100 Nilsen
Если вы группируете по покупателям и запрашиваете сумму или цену заказа, вы получите
Customer SUM(OrderPrice)
Hansen 2000
Nilsen 1700
Jensen 2000
В отличие от этого, отдельная (найденная здесь ) просто делает это так. у вас нет повторяющихся строк. В этом случае исходная таблица останется прежней, поскольку каждая строка отличается от других.