ВИБІРТЕ ДИСТИНЦТ на одному стовпчику


258

Використовуючи 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]

1
Чи можемо ми припустити, що вам не байдуже суфікс даних SKU-стовпчика? IE, Ви дбаєте лише про "FOO-", а не про "FOO-xx"
Kane

3
Яка ваша логіка вибору ID = 1, SKU = FOO-23 над іншими значеннями? Створити запит, який спеціально відповідає на ID = 1, легко, але не вдається для загального випадку
gbn

4
gbn - це надто спрощений приклад (очевидно). Що я намагаюся показати - це один приклад, який задовольняє обом критеріям. Не існує (і не повинно бути) логіки, до якої вибирається.
mmcglynn

Відповіді:


323

Якщо припустити, що ви перебуваєте на 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

37
Ви не використовуєте CTE у своєму запиті. Це просто похідна таблиця. Але ти маєш рацію, що ти міг би тут використати CTE.
Марк Байєрс

залиште "ЯК" для Oracle -> ... ДЕ СКАЗУЄТЬСЯ "FOO%") a WHERE a.RowNumber = 1
Andre Nel

Це працює, хоча це не CTE (; З CTE ......). більше
підзапросу

це справді корисний випадок у будь-якому різному дублюванні дякую
ASLIM

42

Найпростішим рішенням буде використовувати підзапит для пошуку мінімального ідентифікатора, відповідного вашому запиту. У підзапиті ви використовуєте GROUP BYзамість DISTINCT:

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

13

спробуйте це:

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

EDIT
після того, як ОП виправив вихідний показник вибірки (раніше був лише ОДИН рядок результатів, тепер показано все), це правильний запит:

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

8
SELECT min (id) AS 'ID', min(sku) AS 'SKU', Product
    FROM TestData
    WHERE sku LIKE 'FOO%' -- If you want only the sku that matchs with FOO%
    GROUP BY product 
    ORDER BY 'ID'

3
Збирався поставити +1 до цього, тому що я думаю, що GROUP BY - це правильний шлях - але мінімальний ідентифікатор та мінімальний SKU можуть не належати до одного запису. Важко визначити, які правильні ідентифікатор та SKU повідомити для даного ТОВАРУ.
Карл Манастер

8

Я знаю, що це запитували понад 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  

0

Ось версія, в основному така ж, як і пара інших відповідей, але ви можете скопіювати пасту у свою SQL-сервер управління студією для тестування (і без генерації непотрібних таблиць) завдяки деяким вбудованим значенням.

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-%')

як єдина частина авторів несправного коду, а не частина питання. Це навряд чи буде корисним людям, які шукають тут.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.