SELECT DISTINCT für eine Spalte

258

Mit SQL Server habe ich ...

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

Ich will

1   FOO-23  Orange
3   FOO-24  Apple

Diese Abfrage bringt mich nicht dorthin. Wie kann ich DISTINCT nur für eine Spalte auswählen?

SELECT 
[ID],[SKU],[PRODUCT]
FROM [TestData] 
WHERE ([PRODUCT] = 
(SELECT DISTINCT [PRODUCT] FROM [TestData] WHERE ([SKU] LIKE 'FOO-%')) 
ORDER BY [ID]
mmcglynn
quelle
1
Können wir davon ausgehen, dass Ihnen das Suffix in den SKU-Spaltendaten egal ist? IE, Sie interessieren sich nur für "FOO-" und nicht für "FOO-xx"
Kane
3
Was ist Ihre Logik für die Auswahl von ID = 1, SKU = FOO-23 gegenüber den anderen Werten? Es ist einfach, eine Abfrage zu erstellen, die speziell auf ID = 1 antwortet, aber für einen allgemeinen Fall
fehlschlägt
4
gbn - dies ist (offensichtlich) ein stark vereinfachtes Beispiel. Was ich zu zeigen versuche, ist ein Beispiel, das beide Kriterien erfüllt. Es gibt keine Logik (und muss es auch nicht sein), für die man ausgewählt wird.
mmcglynn

Antworten:

323

Angenommen, Sie arbeiten mit SQL Server 2005 oder höher, können Sie einen CTE mit ROW_NUMBER () verwenden:

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
quelle
37
Sie verwenden in Ihrer Abfrage keinen CTE . Das ist nur eine abgeleitete Tabelle. Aber Sie haben recht , dass Sie könnte hier einen CTE verwendet haben.
Mark Byers
Lass "AS" für Orakel weg -> ... WO SKU WIE 'FOO%') a WO a.RowNumber = 1
Andre Nel
Dies funktioniert, obwohl es kein CTE ist (; WITH CTE ......). eher eine
Unterabfrage
Dies ist ein wirklich nützlicher Fall bei jeder Vervielfältigung. Vielen Dank
ASLIM
42

Die einfachste Lösung wäre, eine Unterabfrage zu verwenden, um die minimale ID zu finden, die Ihrer Abfrage entspricht. In der Unterabfrage verwenden Sie GROUP BYanstelle von DISTINCT:

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

Versuche dies:

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

BEARBEITEN
Sobald das OP seine Samle-Ausgabe korrigiert hat (zuvor hatte es nur EINE Ergebniszeile, jetzt werden alle angezeigt), ist dies die richtige Abfrage:

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.
quelle
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'

quelle
3
Wollte dies auf +1 bringen, weil ich denke, dass GROUP BY der richtige Weg ist - aber die minimale ID und die minimale SKU gehören möglicherweise nicht zum selben Datensatz. Es ist schwer zu bestimmen, welche ID und SKU für ein bestimmtes PRODUKT korrekt gemeldet werden sollen.
Carl Manaster
8

Ich weiß, dass es vor über 6 Jahren gefragt wurde, aber Wissen ist immer noch Wissen. Dies ist eine andere Lösung als alle oben genannten, da ich sie unter SQL Server 2000 ausführen musste:

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.
quelle
0

Hier ist eine Version, die im Grunde mit einigen anderen Antworten identisch ist, die Sie jedoch dank einiger Inline-Werte kopieren und in Ihr SQL Server Management Studio einfügen können, um sie zu testen (und ohne unerwünschte Tabellen zu generieren).

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

Ergebnis

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

Ich habe folgendes ignoriert ...

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

als einziger Teil des Autors fehlerhafter Code und nicht Teil der Frage. Es ist unwahrscheinlich, dass es für Leute, die hier suchen, hilfreich ist.

Ivan
quelle
-1

Versuche dies:

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

Anna Karthi
quelle