Wählen Sie Zeilen aus, deren Bedingung für die Gruppe erfüllt ist (ohne temporäre Tabelle).


10

Die Tabelle mit 3 Spalten haben:

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

Ich möchte alle Zeilen auswählen, die flag = 1mindestens einmal pro Kategorie haben.

Erwartete Ergebnisse:

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

Es kann mit einer temporären Tabelle wie folgt gelöst werden:

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

Aber ich würde eine Lösung mit Gruppierung bevorzugen, die ich nur schwer finden kann. Jede Hilfe wird geschätzt.

Antworten:


16

GROUP BYkann nicht alleine verwendet werden, da nur 1 Zeile pro Gruppe ( category) zurückgegeben wird.


  • Sie können eine Unterabfrage mit flag = 1und verwenden 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 ;
  • Sie können die EXISTSKlausel verwenden:

    SELECT d.ID, d.category, d.flag
    FROM data d
    WHERE EXISTS (
        SELECT 1 FROM data WHERE flag = 1 AND category = d.category
    ) ;   
  • Sie können die INKlausel verwenden (obwohl dies EXISTSbesser ist):

    SELECT d.ID, d.category, d.flag
    FROM data d
    WHERE d.category IN (SELECT category FROM data WHERE flag = 1) ;
  • Sie können auch CROSS APPLYmit einer Unterabfrage Folgendes verwenden 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 ;

DISTINCTwerden nicht benötigt, wenn für jede Kategorie nur 1 Zeile vorhanden sein kann flag = 1.

Ausgabe:

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

DISTINCT ist für das IN-Prädikat nicht erforderlich. Und wenn nur eine Zeile pro Kategorie das Flag 1 haben kann, ist DISTINCT überhaupt nicht erforderlich.
Andriy M

@AndriyM korrekt über die INAbfrage. Aber das OP hat " Ich möchte alle Zeilen mit Flag = 1 mindestens einmal pro Kategorie auswählen ", was mich denken lässt, dass das DISTINCTin den anderen Abfragen notwendig ist.
Ypercubeᵀᴹ

1
Und in der CROSS APPLY, das SELECT DISTINCT categorysollte wohl effizienter sein , wenn mit ersetzt SELECT TOP (1) whatever. Es wäre effektiv eine andere Möglichkeit, eine EXISTSUnterabfrage zu schreiben .
Ypercubeᵀᴹ

@Andriy Aus diesem Grund habe ich gestern eine Notiz hinzugefügt, die auf Ihrem ersten Kommentar basiert: Nicht erforderlich, wenn nur 1 Zeile mit Flag = 1 vorhanden ist.
Julien Vavasseur

4

Angenommen, dies Flagist eine BITSpalte oder eine INT, die nur 0und dauert1 als Werte verwendet wird, könnte dies auch mithilfe von Fensterfunktionen erreicht werden. Zum Beispiel:

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;

Das ist die Ausgabe:

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

Dies wird am höchsten finden Flag für jede Kategorie in Ihrer Tabelle am In Ihrem Fall ist es wahrscheinlich nur wahr / falsch und wählen Sie eine aus, die true(1)nur hat.

Die Konvertierung nach TINYINTist erforderlich, da MAXkein BITArgument akzeptiert wird .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.