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]
mmcglynn
fuente
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
Aaron Alton
fuente
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]
)
Jakob Egger
fuente
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
KM.
fuente
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'

fuente
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  
Bartosz X
fuente
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í.

Ivan
fuente
-1

Prueba esto:

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

Anna Karthi
fuente