在一列上选择DISTINCT


258

使用SQL Server,我有...

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

我想要

1   FOO-23  Orange
3   FOO-24  Apple

这个查询没有让我知道。如何仅在一列上选择DISTINCT?

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

1
我们是否可以假定您不关心SKU列数据上的后缀?IE,您只关心“ FOO-”而不是“ FOO-xx”
凯恩2009年

3
在其他值上选择ID = 1,SKU = FOO-23的逻辑是什么?可以很容易地创建一个查询,答案specfically为ID = 1,但失败了一般的情况下
GBN

4
gbn-这是一个过于简化的示例(显然)。我试图显示的是一个满足两个标准的例子。没有(也没有必要)选择逻辑。
mmcglynn,2009年

Answers:


323

假设您使用的是SQL Server 2005或更高版本,则可以将CTE与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
您在查询中没有使用CTE。那只是一个派生表。但是您说对了,您可以在这里使用CTE。
Mark Byers

为甲骨文省略“ AS”-> ...在类似SKU的'FOO%')a WHERE a.RowNumber = 1
Andre Nel

尽管它不是CTE(; WITH CTE ......),它仍然可以工作。更多的子查询,内部有分区...
user274294 '19

这在任何重复中都非常有用,谢谢您
ASLIM

42

最简单的解决方案是使用子查询来查找与查询匹配的最小ID。在子查询中,您使用GROUP BY而不是DISTINCT

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

13

试试这个:

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


一旦OP纠正了他的样本输出(以前只有一个结果行,现在已全部显示),请进行EDIT,这是正确的查询:

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
我打算为此+1,因为我认为GROUP BY是正确的方法-但是最小ID和最小SKU可能不会属于同一记录。很难确定要报告给定产品的正确ID和SKU。
Carl Manaster 09年

8

我知道这是6年前提出的,但是知识仍然是知识。这是不同于上面所有解决方案的解决方案,因为我必须在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

这是一个版本,与其他几个答案基本相同,但是由于一些内联值,您可以将粘贴复制到SQL Server Management Studio中进行测试(并且不会生成任何不需要的表)。

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

结果

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

我忽略了以下内容...

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

作为作者错误代码的唯一部分,而不是问题的一部分。对于看这里的人来说不太可能有帮助。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.