选择满足组条件的行(无临时表)


10

该表具有3列:

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

我想选择flag = 1每个类别至少具有一次的所有行。

预期成绩:

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

可以使用如下临时表来解决:

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

但是我更喜欢使用分组的解决方案,但是我很难解决。任何帮助将不胜感激。

Answers:


16

GROUP BY不能单独使用,因为每个组(category)仅返回1行。


  • 您可以将子查询与flag = 1和一起使用INNER 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 ;
  • 您可以使用以下EXISTS子句:

    SELECT d.ID, d.category, d.flag
    FROM data d
    WHERE EXISTS (
        SELECT 1 FROM data WHERE flag = 1 AND category = d.category
    ) ;   
  • 您可以使用IN子句(尽管EXISTS更好):

    SELECT d.ID, d.category, d.flag
    FROM data d
    WHERE d.category IN (SELECT category FROM data WHERE flag = 1) ;
  • 您还可以在上使用CROSS APPLY子查询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 ;

DISTINCT如果每个类别只能有1行,则不需要flag = 1

输出:

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

对于IN谓词,DISTINCT是不必要的。而且,如果每个类别仅一行可以具有1标志,则根本不需要DISTINCT。
Andriy M

@AndriyM正确关于IN查询。但OP有“ 我要选择有标志的所有行= 1 至少一次按类别 ”,这让我觉得DISTINCT是在其他查询必要的。
ypercubeᵀᴹ

1
并且,如果将替换为CROSS APPLY,则SELECT DISTINCT category可能应该更有效SELECT TOP (1) whatever。这实际上是编写EXISTS子查询的另一种方法。
ypercubeᵀᴹ

@Andriy这就是为什么我昨天加了注释根据您最初的评论:如果只有1标志= 1的行没有必要
朱利安Vavasseur

4

假设这Flag是一BIT列或INT仅包含01作为值的,则也可以使用窗口函数来实现。例如:

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;

那是输出:

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

这将Flag在表中的每个类别中找到最高的类别,在您的情况下,可能只有true / false,并选择只有一个类别的true(1)

TINYINT需要转换为,因为MAX它不接受BIT参数。

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.