SELEZIONA DISTINCT su una colonna


258

Utilizzando SQL Server, ho ...

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

Voglio

1   FOO-23  Orange
3   FOO-24  Apple

Questa domanda non mi sta portando lì. Come posso SELEZIONARE DISTINCT su una sola colonna?

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

1
Possiamo supporre che non ti interessi del suffisso nei dati della colonna SKU? IE, ti preoccupi solo di "FOO-" e non di "FOO-xx"
— Kane,

3
Qual è la tua logica per scegliere ID = 1, SKU = FOO-23 rispetto agli altri valori? È facile creare una query che risponda specificatamente per ID = 1 ma non riesce per un caso generale
— gbn

4
gbn - questo è un esempio eccessivamente semplificato (ovviamente). Quello che sto cercando di mostrare è un esempio che soddisfa entrambi i criteri. Non esiste (e non è necessario che sia) la logica a cui viene scelto.
— mmcglynn,

Risposte:


323

Supponendo di utilizzare SQL Server 2005 o versioni successive, è possibile utilizzare un CTE con 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
Non stai usando un CTE nella tua query. Questa è solo una tabella derivata. Ma hai ragione sul fatto che avresti potuto usare un CTE qui.
— Mark Byers,

tralasciare "AS" per l'oracolo -> ... DOVE SKU COME "FOO%") a DOVE a.RowNumber = 1
— Andre Nel

Funziona anche se non è un CTE (; CON CTE ......). più di una
— sottoquery

questo è un caso davvero utile in ogni duplicazione, grazie
— ASLIM,

42

La soluzione più semplice sarebbe quella di utilizzare una sottoquery per trovare l'ID minimo corrispondente alla tua query. Nella sottoquery usi GROUP BYinvece di DISTINCT:

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

13

prova questo:

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
una volta che l'OP ha corretto il suo output samle (in precedenza aveva solo UNA riga di risultati, ora ha mostrato tutto), questa è la query corretta:

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
Avrei fatto +1 su questo, perché penso che GROUP BY sia la strada giusta da percorrere, ma l'ID minimo e lo SKU minimo potrebbero non appartenere allo stesso record. È difficile determinare quali sono l'ID e lo SKU corretti da segnalare per un determinato PRODOTTO.
— Carl Manaster,

8

So che è stato chiesto più di 6 anni fa, ma la conoscenza è ancora conoscenza. Questa è una soluzione diversa rispetto a tutte le precedenti, poiché dovevo eseguirla in 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

Ecco una versione, sostanzialmente uguale a un paio di altre risposte, ma che puoi copiare e incollare nel tuo SQL Server Management Studio per testare (e senza generare tabelle indesiderate), grazie ad alcuni valori incorporati.

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

Risultato

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

Ho ignorato quanto segue ...

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

come unica parte del codice difettoso degli autori e non parte della domanda. È improbabile che sia utile per le persone che guardano qui.


-1

Prova questo:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.