chọn các hàng có điều kiện đáp ứng cho nhóm (không có bảng tạm thời)


10

Có bảng có 3 cột:

ID  category    flag
1       A       1
2       A       0
3       A       0
4       B       0
5       C       0

Tôi muốn chọn tất cả các hàng có flag = 1ít nhất một lần cho mỗi danh mục.

Kết quả dự kiến:

ID  category    flag
1       A       1
2       A       0
3       A       0

Nó có thể được giải quyết bằng cách sử dụng một bảng tạm thời như thế này:

select ID into #tempTable from someTable where flag = 1
select * from someTable join #tempTable on someTable.ID = #tempTable.ID

Nhưng tôi thích một giải pháp với nhóm, mà tôi đấu tranh để đưa ra. Bất kỳ trợ giúp sẽ được đánh giá cao.

Câu trả lời:


16

GROUP BYkhông thể được sử dụng một mình vì nó chỉ trả về 1 hàng mỗi nhóm ( category).


  • Bạn có thể sử dụng truy vấn phụ với flag = 1INNER JOIN:

    SELECT d1.ID, d1.category, d1.flag
    FROM data d1
    INNER JOIN (
        SELECT DISTINCT category FROM data WHERE flag = 1
    ) d2 
        ON d2.category = d1.category ;
  • Bạn có thể sử dụng EXISTSmệnh đề:

    SELECT d.ID, d.category, d.flag
    FROM data d
    WHERE EXISTS (
        SELECT 1 FROM data WHERE flag = 1 AND category = d.category
    ) ;   
  • Bạn có thể sử dụng INmệnh đề (mặc dù EXISTStốt hơn):

    SELECT d.ID, d.category, d.flag
    FROM data d
    WHERE d.category IN (SELECT category FROM data WHERE flag = 1) ;
  • Bạn cũng có thể sử dụng CROSS APPLYvới một truy vấn phụ trên flag = 1:

    SELECT d.ID, d.category, d.flag
    FROM data d
    CROSS APPLY (
        SELECT TOP (1) category 
        FROM data 
        WHERE flag = 1 AND category = d.category
    ) ca ;

DISTINCTkhông cần thiết nếu, đối với mỗi danh mục, chỉ có 1 hàng có thể có flag = 1.

Đầu ra:

ID  category    flag
1       A       1
2       A       0
3       A       0

DISTINCT là không cần thiết cho vị từ IN. Và nếu chỉ một hàng cho mỗi danh mục có thể có cờ là 1, thì DISTINCT hoàn toàn không cần thiết.
Andriy M

@AndriyM đúng về INtruy vấn. Nhưng OP có " Tôi muốn chọn tất cả các hàng có cờ = 1 ít nhất một lần cho mỗi danh mục " khiến tôi nghĩ rằng điều đó DISTINCTlà cần thiết trong các truy vấn khác.
ypercubeᵀᴹ

1
Và trong CROSS APPLY, SELECT DISTINCT categorycó lẽ nên hiệu quả hơn nếu được thay thế bằng SELECT TOP (1) whatever. Nó có hiệu quả sẽ là một cách khác để viết một EXISTStruy vấn con.
ypercubeᵀᴹ

@Andriy Đây là lý do tại sao tôi đã thêm một ghi chú ngày hôm qua dựa trên nhận xét ban đầu của bạn: không cần thiết nếu chỉ có 1 hàng với cờ = 1.
Julien Vavasseur

4

Giả sử rằng đó Flaglà một BITcột hoặc INTchỉ lấy 01làm giá trị, điều này có thể đạt được bằng cách sử dụng các hàm cửa sổ. Ví dụ:

DECLARE @Test TABLE
(
  ID INT
  , Category VARCHAR(1)
  , Flag BIT
);

INSERT INTO @Test (ID, Category, Flag)
VALUES (1, 'A', 1)
  , (2, 'A', 0)
  , (3, 'A', 0)
  , (4, 'B', 0)
  , (5, 'C', 0);

SELECT T.ID
  , T.Category
  , T.Flag
FROM (
  SELECT ID
    , Category
    , Flag
    , MAX(CAST(Flag AS TINYINT)) OVER(PARTITION BY Category) AS MaxFlag
  FROM @Test
  ) AS T
WHERE T.MaxFlag = 1;

Đó là đầu ra:

ID Category Flag  
-- -------- ----- 
1  A        True  
2  A        False 
3  A        False 

Điều này sẽ tìm thấy cao nhất Flagcho mỗi danh mục trong bảng của bạn, trong trường hợp của bạn có lẽ chỉ đúng / sai và chọn một người true(1)chỉ có.

Việc chuyển đổi thành TINYINTcần thiết vì MAXkhông chấp nhận BITđối số.

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.