SELECT DISTINCT sur une colonne


258

En utilisant SQL Server, j'ai ...

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

Je voudrais

1   FOO-23  Orange
3   FOO-24  Apple

Cette requête ne m'y amène pas. Comment sélectionner SELECT DISTINCT sur une seule colonne?

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

1
Pouvons-nous supposer que vous ne vous souciez pas du suffixe des données de la colonne SKU? IE, Vous ne vous souciez que de "FOO-" et non de "FOO-xx"
Kane

3
Quelle est votre logique pour choisir ID = 1, SKU = FOO-23 sur les autres valeurs? Il est facile de créer une requête qui répond spécifiquement à ID = 1 mais échoue pour un cas général
gbn

4
gbn - c'est un exemple trop simplifié (évidemment). Ce que j'essaie de montrer est un exemple qui satisfait les deux critères. Il n'y a pas (et n'a pas besoin d'être) de logique à laquelle on est choisi.
mmcglynn

Réponses:


323

En supposant que vous êtes sur SQL Server 2005 ou supérieur, vous pouvez utiliser un CTE avec 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
Vous n'utilisez pas de CTE dans votre requête. Ce n'est qu'un tableau dérivé. Mais vous avez raison, vous auriez pu utiliser un CTE ici.
Mark Byers

omettre "AS" pour oracle -> ... O SK LA SKU COMME 'FOO%') a OERE a.RowNumber = 1
Andre Nel

Cela fonctionne bien que ce ne soit pas un CTE (; AVEC CTE ......). plus d'une sous-requête avec partition par l'intérieur ....
user274294

c'est un cas vraiment utile dans toutes les duplications diverses merci
ASLIM

42

La solution la plus simple serait d'utiliser une sous-requête pour trouver l'ID minimum correspondant à votre requête. Dans la sous-requête que vous utilisez GROUP BYau lieu de DISTINCT:

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

13

essaye ça:

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
une fois que l'OP a corrigé sa sortie de samle (auparavant, il n'y avait qu'une seule ligne de résultat, maintenant tout est affiché), c'est la bonne requête:

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
J'allais attribuer +1 à cela, car je pense que GROUP BY est la bonne voie à suivre - mais l'ID minimum et le SKU minimum peuvent ne pas appartenir au même enregistrement. Il est difficile de déterminer l'ID et la SKU corrects à signaler pour un PRODUIT donné.
Carl Manaster

8

Je sais que cela a été demandé il y a plus de 6 ans, mais la connaissance est toujours une connaissance. C'est une solution différente de toutes celles ci-dessus, car je devais l'exécuter sous 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

Voici une version, essentiellement la même que quelques autres réponses, mais que vous pouvez copier coller dans votre SQL Server Management Studio pour tester, (et sans générer de tables indésirables), grâce à certaines valeurs en ligne.

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

Résultat

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

J'ai ignoré ce qui suit ...

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

comme sa seule partie du code défectueux des auteurs et ne fait pas partie de la question. Il est peu probable que cela aide les gens qui regardent ici.


-1

Essaye ça:

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.