CHỌN DISTINCT trên một cột


258

Sử dụng SQL Server, tôi có ...

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

tôi muốn

1   FOO-23  Orange
3   FOO-24  Apple

Truy vấn này không đưa tôi đến đó. Làm cách nào tôi có thể CHỌN DISTINCT trên chỉ một cột?

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

1
Chúng tôi có thể cho rằng bạn không quan tâm đến hậu tố trên dữ liệu cột SKU không? IE, Bạn chỉ quan tâm đến "FOO-" chứ không phải "FOO-xx"
Kane

3
Logic của bạn khi chọn ID = 1, SKU = FOO-23 so với các giá trị khác là gì? Thật dễ dàng để tạo một truy vấn trả lời cụ thể cho ID = 1 nhưng không thành công trong trường hợp chung
gbn

4
gbn - đây là một ví dụ đơn giản hóa quá mức (rõ ràng). Những gì tôi đang cố gắng thể hiện là một ví dụ thỏa mãn cả hai tiêu chí. Không có logic (và không cần phải) mà cái nào được chọn.
mmcglynn

Câu trả lời:


323

Giả sử rằng bạn đang sử dụng SQL Server 2005 trở lên, bạn có thể sử dụng CTE với 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
Bạn không sử dụng CTE trong truy vấn của mình. Đó chỉ là một bảng dẫn xuất. Nhưng bạn đã đúng rằng bạn có thể đã sử dụng CTE ở đây.
Mark Byers

bỏ qua "NHƯ" cho lời tiên tri -> ... Ở ĐÂU SKU THÍCH 'FOO%') a WHERE a.RowNumber = 1
Andre Nel

Điều này hoạt động mặc dù nó không phải là CTE (; VỚI CTE ......). thêm một truy vấn phụ với phân vùng bên trong ....
user274294

đây là trường hợp thực sự hữu ích trong mọi trường hợp sao chép khác nhau, xin cảm ơn
ASLIM

42

Giải pháp đơn giản nhất là sử dụng truy vấn con để tìm ID tối thiểu phù hợp với truy vấn của bạn. Trong truy vấn con bạn sử dụng GROUP BYthay vì DISTINCT:

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

13

thử cái này:

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
sau khi OP sửa lỗi đầu ra samle của mình (trước đây chỉ có MỘT hàng kết quả, bây giờ đã hiển thị tất cả), đây là truy vấn chính xác:

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
Sẽ đạt +1 điều này, vì tôi nghĩ rằng NHÓM THEO là cách phù hợp - nhưng ID tối thiểu và SKU tối thiểu có thể không thuộc về cùng một bản ghi. Thật khó để xác định ID và SKU chính xác để báo cáo cho một SẢN PHẨM cụ thể là gì.
Carl Manaster

8

Tôi biết nó đã được hỏi hơn 6 năm trước, nhưng kiến ​​thức vẫn là kiến ​​thức. Đây là giải pháp khác với tất cả ở trên, vì tôi phải chạy nó trong 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

Đây là một phiên bản, về cơ bản giống như một vài câu trả lời khác, nhưng bạn có thể sao chép dán vào Máy chủ quản lý SQL của mình để kiểm tra, (và không tạo ra bất kỳ bảng không mong muốn nào), nhờ một số giá trị nội tuyến.

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

Kết quả

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

Tôi đã bỏ qua những điều sau đây ...

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

như là một phần duy nhất của các tác giả mã bị lỗi và không phải là một phần của câu hỏi. Nó không hữu ích cho những người nhìn vào đây.


-1

Thử cái này:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.