SELECT DISTINCT em uma coluna


258

Usando o SQL Server, eu tenho ...

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

eu quero

1   FOO-23  Orange
3   FOO-24  Apple

Esta consulta não está me levando até lá. Como posso selecionar DISTINCT em apenas uma coluna?

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

1
Podemos assumir que você não se importa com o sufixo nos dados da coluna SKU? IE, você só se preocupam com "foo-" e não "FOO-xx"
Kane

3
Qual é a sua lógica para escolher ID = 1, SKU = FOO-23 em relação aos outros valores? É fácil criar uma consulta que respostas specfically para ID = 1, mas não para um caso geral
GBN

4
gbn - este é um exemplo excessivamente simplificado (obviamente). O que estou tentando mostrar é um exemplo que satisfaz ambos os critérios. Não existe (e não precisa) lógica para a escolha de uma.
8139 mmcglynn

Respostas:


323

Supondo que você esteja no SQL Server 2005 ou superior, você pode usar um CTE com 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
Você não está usando um CTE na sua consulta. Essa é apenas uma tabela derivada. Mas você está certo de que poderia ter usado um CTE aqui.
Mark Byers

deixe de fora "AS" para oracle -> ... WHERE SKU COMO 'FOO%') a WHERE a.RowNumber = 1
Andre Nel

Isso funciona, embora não seja um CTE (; WITH CTE ......). mais de uma subconsulta com partição por dentro ....
user274294 24/07

este é realmente um caso útil em qualquer duplicação, obrigado
ASLIM 13/01

42

A solução mais simples seria usar uma subconsulta para encontrar o ID mínimo correspondente à sua consulta. Na subconsulta que você usa em GROUP BYvez de DISTINCT:

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

13

tente isto:

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
uma vez que o OP corrigiu sua saída de amostra (anteriormente tinha apenas UMA linha de resultado, agora foi mostrada), esta é a consulta correta:

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
Iria marcar com +1 isso, porque acho que GROUP BY é o caminho certo a seguir - mas o ID mínimo e o SKU mínimo podem não pertencer ao mesmo registro. É difícil determinar quais são o ID e o SKU corretos a serem relatados para um determinado PRODUTO.
246 Carl Manaster

8

Eu sei que isso foi perguntado há mais de 6 anos, mas o conhecimento ainda é conhecimento. Esta é uma solução diferente da anterior, pois tive que executá-la no 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

Aqui está uma versão, basicamente o mesmo que algumas das outras respostas, mas que você pode copiar e colar no SQL Server Management Studio para testar (e sem gerar tabelas indesejadas), graças a alguns valores embutidos.

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

Eu ignorei o seguinte ...

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

como sua única parte do código defeituoso dos autores e não parte da questão. É improvável que seja útil para as pessoas que olham aqui.


-1

Tente o seguinte:

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.