Wybierz DISTINCT w jednej kolumnie

258

Korzystając z programu SQL Server, mam ...

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

chcę

1   FOO-23  Orange
3   FOO-24  Apple

To zapytanie mnie tam nie prowadzi. Jak wybrać DISTINCT tylko w jednej kolumnie?

SELECT 
[ID],[SKU],[PRODUCT]
FROM [TestData] 
WHERE ([PRODUCT] = 
(SELECT DISTINCT [PRODUCT] FROM [TestData] WHERE ([SKU] LIKE 'FOO-%')) 
ORDER BY [ID]
mmcglynn
źródło
1
Czy możemy założyć, że nie obchodzi Cię przyrostek w danych kolumny SKU? IE, zależy Ci tylko na „FOO-”, a nie „FOO-xx”
Kane
3
Jaka jest Twoja logika, wybierając ID = 1, SKU = FOO-23 w porównaniu z innymi wartościami? Łatwo jest utworzyć zapytanie, które odpowiada konkretnie na ID = 1, ale nie udaje się w przypadku ogólnym
gbn
4
gbn - jest to zbyt uproszczony przykład (oczywiście). To, co próbuję pokazać, to jeden przykład, który spełnia oba kryteria. Nie ma (i nie musi) być logiki, do której ktoś jest wybrany.
mmcglynn

Odpowiedzi:

323

Zakładając, że korzystasz z SQL Server 2005 lub nowszej wersji, możesz użyć CTE z 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
Aaron Alton
źródło
37
Nie używasz CTE w swoim zapytaniu. To tylko tabela pochodna. Ale masz rację, że mógłbyś skorzystać z CTE tutaj.
Mark Byers,
pomiń „AS” dla wyroczni -> ... GDZIE SKU JAK „FOO%”) a GDZIE a.RowNumber = 1
Andre Nel
Działa to, chociaż nie jest to CTE (; Z CTE ......). więcej sub-kwerendy z partycją wewnątrz ...
user274294
to jest naprawdę przydatny przypadek w przypadku różnych kopii, dziękuję
ASLIM
42

Najprostszym rozwiązaniem byłoby użycie podzapytania w celu znalezienia minimalnego identyfikatora pasującego do zapytania. W podzapytaniu używasz GROUP BYzamiast DISTINCT:

SELECT * FROM [TestData] WHERE [ID] IN (
   SELECT MIN([ID]) FROM [TestData]
   WHERE [SKU] LIKE 'FOO-%'
   GROUP BY [PRODUCT]
)
Jakob Egger
źródło
13

Spróbuj tego:

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

EDYTUJ,
gdy OP poprawi wyniki swojej próbki (poprzednio miał tylko JEDEN wiersz wyników, teraz wszystko się pokazuje), to jest prawidłowe zapytanie:

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
KM.
źródło
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'

źródło
3
Zamierzałem dać +1, ponieważ myślę, że GROUP BY to właściwa droga - ale minimalne ID i minimalne SKU mogą nie należeć do tego samego rekordu. Trudno jest określić, jaki identyfikator i SKU mają być zgłaszane dla danego PRODUKTU.
Carl Manaster
8

Wiem, że zapytano o to ponad 6 lat temu, ale wiedza to wciąż wiedza. To jest inne rozwiązanie niż wszystkie powyższe, ponieważ musiałem uruchomić go w 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  
Bartosz X
źródło
0

Oto wersja, w zasadzie taka sama jak kilka innych odpowiedzi, ale którą można skopiować wklej do SQL Server Management Studio, aby przetestować (i bez generowania niechcianych tabel), dzięki niektórym wartościom wbudowanym.

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]
)

Wynik

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

Zignorowałem następujące ...

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

jako jedyna część wadliwego kodu autora, a nie część pytania. Jest mało prawdopodobne, aby był pomocny dla ludzi, którzy tu szukają.

Ivan
źródło
-1

Spróbuj tego:

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

Anna Karthi
źródło