SELECCIONE DISTINCT en una columna


258

Usando SQL Server, tengo ...

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

quiero

1   FOO-23  Orange
3   FOO-24  Apple

Esta consulta no me lleva allí. ¿Cómo puedo SELECCIONAR DISTINCT en una sola columna?

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

1
¿Podemos suponer que no le importa el sufijo en los datos de la columna SKU? De forma que solamente se preocupan por "foo" y no "FOO-xx"
— Kane

3
¿Cuál es su lógica para elegir ID = 1, SKU = FOO-23 sobre los otros valores? Es fácil crear una consulta que respuestas especificamente para ID = 1 pero no para un caso general
— GBN

44
gbn: este es un ejemplo demasiado simplificado (obviamente). Lo que estoy tratando de mostrar es un ejemplo que satisface ambos criterios. No hay (y no es necesario) lógica para elegir uno.
— mmcglynn

Respuestas:


323

Suponiendo que está utilizando SQL Server 2005 o superior, puede usar 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
No está utilizando un CTE en su consulta. Eso es solo una tabla derivada. Pero tiene razón en que podría haber usado un CTE aquí.
— Mark Byers

omita "AS" para Oracle -> ... DONDE SKU COMO 'FOO%') a DONDE a.RowNumber = 1
— Andre Nel

Esto funciona aunque no es un CTE (; CON CTE ......). más de una consulta sub con partición por dentro ....
— user274294

Este es un caso realmente útil en cualquier duplicación gracias
— ASLIM

42

La solución más simple sería utilizar una subconsulta para encontrar el ID mínimo que coincida con su consulta. En la subconsulta que usas en GROUP BYlugar de DISTINCT:

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

13

prueba esto:

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

EDITAR
una vez que el OP corrigió su salida samle (anteriormente solo tenía UNA fila de resultados, ahora se ha mostrado todo), esta es la consulta correcta:

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
Iba a hacer +1 en esto, porque creo que GROUP BY es el camino correcto, pero la ID mínima y la SKU mínima pueden no pertenecer al mismo registro. Es difícil determinar cuáles son los ID y SKU correctos para informar para un PRODUCTO determinado.
— Carl Manaster

8

Sé que se hizo hace más de 6 años, pero el conocimiento sigue siendo conocimiento. Esta es una solución diferente a todas las anteriores, ya que tuve que ejecutarla en 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

Aquí hay una versión, básicamente la misma que algunas de las otras respuestas, pero que puede copiar y pegar en su SQL Server Management Studio para probar, (y sin generar tablas no deseadas), gracias a algunos valores en línea.

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

Resultado

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

He ignorado lo siguiente ...

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

como su única parte del código defectuoso de los autores y no es parte de la pregunta. Es poco probable que sea útil para las personas que buscan aquí.


-1

Prueba esto:

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.