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.