ВЫБЕРИТЕ DISTINCT в одном столбце

Используя SQL Server, я ...

ID  SKU     PRODUCT
=======================
1   FOO-23  Orange
2   BAR-23  Orange
3   FOO-24  Apple
4   FOO-25  Orange

я хочу

1   FOO-23  Orange
3   FOO-24  Apple

Этот запрос меня не ведет. Как я могу ВЫБРАТЬ DISTINCT только для одного столбца?

SELECT
[ID],[SKU],[PRODUCT]
FROM [TestData]
WHERE ([PRODUCT] =
(SELECT DISTINCT [PRODUCT] FROM [TestData] WHERE ([SKU] LIKE 'FOO-%'))
ORDER BY [ID]

person mmcglynn    schedule 08.06.2009    source источник
comment
Можно ли предположить, что вас не волнует суффикс в данных столбца SKU? Т.е., вас волнует только FOO- а не FOO-xx   -  person Kane    schedule 08.06.2009
comment
Какова ваша логика при выборе ID = 1, SKU = FOO-23 среди других значений? Легко создать запрос, который отвечает конкретно для ID = 1, но не работает в общем случае.   -  person gbn    schedule 08.06.2009
comment
gbn - это слишком упрощенный пример (очевидно). Я пытаюсь показать один пример, удовлетворяющий обоим критериям. Нет (и не должно быть) логики, для которой выбирается один.   -  person mmcglynn    schedule 08.06.2009


Ответы (7)


arrow_upward
350
arrow_downward

Предполагая, что вы используете SQL Server 2005 или выше, вы можете использовать CTE с ROW_NUMBER ():

SELECT  *
FROM    (SELECT ID, SKU, Product,
                ROW_NUMBER() OVER (PARTITION BY PRODUCT ORDER BY ID) AS RowNumber
         FROM   MyTable
         WHERE  SKU LIKE 'FOO%') AS a
WHERE   a.RowNumber = 1
person Aaron Alton    schedule 08.06.2009
comment
Вы не используете CTE в своем запросе. Это просто производная таблица. Но вы правы, что вы могли использовать здесь CTE. - person Mark Byers; 07.12.2011
comment
оставьте AS для оракула - ›... WHERE SKU LIKE 'FOO%') a WHERE a.RowNumber = 1 - person Andre Nel; 21.06.2017
comment
Это работает, хотя это не CTE (; WITH CTE ......). больше подзапроса с разделением внутри .... - person user274294; 24.07.2019
comment
это действительно полезный случай в любом разнообразном дублировании спасибо - person ASLIM; 13.01.2020

arrow_upward
48
arrow_downward

Самым простым решением было бы использовать подзапрос для поиска минимального идентификатора, соответствующего вашему запросу. В подзапросе вы используете GROUP BY вместо DISTINCT:

SELECT * FROM [TestData] WHERE [ID] IN (
   SELECT MIN([ID]) FROM [TestData]
   WHERE [SKU] LIKE 'FOO-%'
   GROUP BY [PRODUCT]
)
person Jakob Egger    schedule 28.03.2012

arrow_upward
13
arrow_downward

попробуй это:

SELECT
    t.*
    FROM TestData t
        INNER JOIN (SELECT
                        MIN(ID) as MinID
                        FROM TestData
                        WHERE SKU LIKE 'FOO-%'
                   ) dt ON t.ID=dt.MinID

РЕДАКТИРОВАТЬ
после того, как ОП исправил свой выборочный вывод (раньше была только ОДНА строка результатов, теперь отображается вся), это правильный запрос:

declare @TestData table (ID int, sku char(6), product varchar(15))
insert into @TestData values (1 ,  'FOO-23'      ,'Orange')
insert into @TestData values (2 ,  'BAR-23'      ,'Orange')
insert into @TestData values (3 ,  'FOO-24'      ,'Apple')
insert into @TestData values (4 ,  'FOO-25'      ,'Orange')

--basically the same as @Aaron Alton's answer:
SELECT
    dt.ID, dt.SKU, dt.Product
    FROM (SELECT
              ID, SKU, Product, ROW_NUMBER() OVER (PARTITION BY PRODUCT ORDER BY ID) AS RowID
              FROM @TestData
              WHERE  SKU LIKE 'FOO-%'
         ) AS dt
    WHERE dt.RowID=1
    ORDER BY dt.ID
person KM.    schedule 08.06.2009

arrow_upward
9
arrow_downward

Я знаю, что об этом спрашивали более 6 лет назад, но знание - это все еще знание. Это другое решение, чем все вышеперечисленное, так как мне пришлось запускать его под SQL Server 2000:

DECLARE @TestData TABLE([ID] int, [SKU] char(6), [Product] varchar(15))
INSERT INTO @TestData values (1 ,'FOO-23', 'Orange')
INSERT INTO @TestData values (2 ,'BAR-23', 'Orange')
INSERT INTO @TestData values (3 ,'FOO-24', 'Apple')
INSERT INTO @TestData values (4 ,'FOO-25', 'Orange')

SELECT DISTINCT  [ID] = ( SELECT TOP 1 [ID]  FROM @TestData Y WHERE Y.[Product] = X.[Product])
                ,[SKU]= ( SELECT TOP 1 [SKU] FROM @TestData Y WHERE Y.[Product] = X.[Product])
                ,[PRODUCT]
            FROM @TestData X
person Bartosz X    schedule 18.11.2015

arrow_upward
3
arrow_downward

Вот версия, в основном такая же, как и пара других ответов, но вы можете скопировать вставку в SQL Server Management Studio для тестирования (и без создания каких-либо нежелательных таблиц) благодаря некоторым встроенным значениям.

WITH [TestData]([ID],[SKU],[PRODUCT]) AS
(
    SELECT *
    FROM (
        VALUES
        (1,   'FOO-23',  'Orange'),
        (2,   'BAR-23',  'Orange'),
        (3,   'FOO-24',  'Apple'),
        (4,   'FOO-25',  'Orange')
    )
    AS [TestData]([ID],[SKU],[PRODUCT])
)

SELECT * FROM [TestData] WHERE [ID] IN
(
    SELECT MIN([ID])
    FROM [TestData]
    GROUP BY [PRODUCT]
)

Результат

ID  SKU     PRODUCT
1   FOO-23  Orange
3   FOO-24  Apple

Я проигнорировал следующее ...

WHERE ([SKU] LIKE 'FOO-%')

как это только часть ошибочного кода авторов и не часть вопроса. Людям, которые сюда смотрят, это вряд ли поможет.

person Ivan    schedule 19.03.2019
comment
Отличная идея для разработки и тестирования без создания тестовых таблиц. Спасибо. - person luisdev; 16.03.2021

arrow_upward
0
arrow_downward

Попробуй это:

SELECT * FROM [TestData] WHERE Id IN(SELECT DISTINCT MIN(Id) FROM [TestData] GROUP BY Product)

person Anna Karthi    schedule 14.12.2013

arrow_upward

arrow_downward

person    schedule
comment
Собирался поставить +1, потому что я думаю, что GROUP BY - правильный путь, но минимальный идентификатор и минимальный SKU могут не принадлежать одной и той же записи. Трудно определить правильный идентификатор и артикул, которые нужно сообщить для конкретного ПРОДУКТА. - person Carl Manaster; 09.06.2009