グループに対して条件が満たされた行を選択(一時テーブルなし)


10

3列のテーブルがある場合:

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

flag = 1カテゴリごとに少なくとも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

しかし、私は思いついたグループ化を使用した解決策を好みます。任意の助けをいただければ幸いです。

回答:


16

GROUP BYグループごとに1行しか返さないため、単独では使用できません(category)。


  • flag = 1andでサブクエリを使用できます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つの行だけがフラグ1を持つことができる場合、DISTINCTはまったく不要です。
Andriy M

@AndriyMはINクエリについて正しい。しかし、OPには「フラグ= 1のすべての行を、カテゴリごとに少なくとも1回選択したい」がありDISTINCT、他のクエリではが必要であると思います。
ypercubeᵀᴹ

1
で、CROSS APPLYSELECT DISTINCT category置き換えた場合、はおそらくより効率的になるはずSELECT TOP (1) whateverです。EXISTSサブクエリを作成するもう1つの方法です。
ypercubeᵀᴹ

フラグ= 1で1行のみがある場合は必要ありません:私はあなたの最初のコメントに基づいて、昨日のノートを追加した理由@Andriyこれはある
ジュリアンVavasseur

4

これFlagBIT列であるか、値INTのみをとるである0と仮定すると1、これはウィンドウ関数を使用しても実現できます。例えば:

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(1)ます。

は引数を受け入れないため、への変換TINYINTが必要です。MAXBIT

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.