2016-05-06 22 views
0

Ein Kollege dieses Stück SQL geschrieben zu verwenden (SQL Server 2012):Suche nach einem Minimalwert in einer Unterabfrage

SELECT 
    a.account_id 
    ,(SELECT SUM(e.amount) 
    FROM event e 
    WHERE e.event_type_id <> 47 
    AND e.master_comm_id = (SELECT c.comm_id 
          FROM comm c 
          WHERE c.item_id = a.item_id 
          AND c.comp_type_id = 20 
          AND c.comm_type_id = 485)) 
FROM account a 

Allerdings gibt es Fälle, in denen es mehr master_comm_ids gegen ein Ereignis sind, und so die Abfrage fehlgeschlagen (Unterabfrage hat mehr als 1 Wert zurückgegeben. Dies ist nicht zulässig, wenn die Unterabfrage =,! =, <, < =,>,> = oder wenn die Unterabfrage als Ausdruck verwendet wird.). Ich möchte nur die erste master_comm_id, dh. die MIN eins.

Ich habe verschiedene ähnliche Fragen untersucht und verschiedene Dinge versucht, um dies zu erreichen (mit MIN oder ROW_NUMBER und Neuanordnung der Abfrage Joins zu verwenden), aber ich muss etwas Offensichtliches vermissen, da alles entweder zu SQL-Fehlern oder dem Falschen geführt hat Daten oder nicht das Problem behoben.

Kann mir jemand helfen, finde die min master_comm_id, um sie dann in der Unterabfrage zu verwenden?

+0

Bitte Tabellenstrukturen und einige Beispieldaten veröffentlichen. – RichardCL

+0

Der beste Weg, hier nützliche Ratschläge zu erhalten, besteht darin, Ihre Tabellenstrukturen, einige minimale Beispieldaten, die das Problem veranschaulichen, und Ihr erwartetes Ergebnis einzubeziehen. Bitte lesen Sie: http://stackoverflow.com/help/how-to-ask –

+0

Warum würde 'ORDERBY' nicht funktionieren? –

Antwort

0

Top 1 funktioniert, aber nur dann, wenn die Daten sind bestellt (siehe unten SO)

Sie haben erwähnt, dass Sie MIN versucht haben, aber wo? Dies kann arbeiten (Sie sind ganz in der Nähe):

SELECT 
    a.account_id 
    ,(SELECT SUM(e.amount) 
    FROM event e 
    WHERE e.event_type_id <> 47 
    AND e.master_comm_id = (SELECT **MIN**(c.comm_id) 
          FROM comm c 
          WHERE c.item_id = a.item_id 
          AND c.comp_type_id = 20 
          AND c.comm_type_id = 485)) 
FROM account 

MAX vs Top 1 - which is better?

1

Versuchen Sie diese. Da ich keine Beispieldaten haben, kann ich nicht überprüfen, aber es sieht offensichtlich - wählen nur Top-1, während die Auswahlliste durch die ID aufsteigend geordnet ist ...

SELECT 
    a.account_id 
    ,(SELECT SUM(e.amount) 
    FROM event e 
    WHERE e.event_type_id <> 47 
    AND e.master_comm_id = (SELECT top 1 c.comm_id 
          FROM comm c 
          WHERE c.item_id = a.item_id 
          AND c.comp_type_id = 20 
          AND c.comm_type_id = 485 
          ORDER BY C.COMM_ID ASC)) 
FROM account a 
2

Die "normale" Lösung ist IN oder = ANY zu verwenden:

SELECT a.account_id, 
     (SELECT SUM(e.amount) 
     FROM event e 
     WHERE e.event_type_id <> 47 AND 
       e.master_comm_id IN (SELECT c.comm_id 
            FROM comm c 
            WHERE c.item_id = a.item_id AND 
             c.comp_type_id = 20 AND 
             c.comm_type_id = 485 
           ) 
     ) as sumamount 
FROM account a; 

Es gibt andere Alternativen, wie eine explizite JOIN und GROUP BY.

Ich bemerke tatsächlich, dass die Unterabfrage keine Korrelationsklausel hat. Ohne eine wird immer der gleiche Wert zurückgegeben. Es ist klarer solche Abfragen in der FROM Klausel zu setzen:

SELECT a.account_id, e.sumamount 
FROM account a CROSS JOIN 
    (SELECT SUM(e.amount) as sumamount 
     FROM event e 
     WHERE e.event_type_id <> 47 AND 
      e.master_comm_id IN (SELECT c.comm_id 
           FROM comm c 
           WHERE c.item_id = a.item_id AND 
             c.comp_type_id = 20 AND 
             c.comm_type_id = 485 
           ) 
    ) e; 

Einige Datenbanken werden die Unterabfrage in den SELECT für jede Zeile auszuführen. SQL Server ist wahrscheinlich schlau genug, um das zu optimieren. Aber indem man es in die FROM Klausel setzt, wird garantiert, dass es nur einmal ausgeführt wird.

0
SELECT a.account_id, 
     oa.[amount] 
FROM account a 
     OUTER APPLY (
      SELECT SUM(e.amount) [amount] 
      FROM event e 
      WHERE e.event_type_id <> 47 
        AND EXISTS (
         SELECT 1 
         FROM comm c 
         WHERE e.master_comm_id = c.comm_id 
           AND c.item_id = a.item_id 
           AND c.comp_type_id IN (20, 485) 
        ) 
     ) oa 

wenn das, was Sie sagen, über I only want the first master_comm_id, ie. the MIN one. bedeutet, dass nur Sie die Summe aus dem min(master_comm_id) wollen, dann können Sie so etwas wie dies versuchen.

SELECT a.account_id, 
     oa.[amount] 
FROM account a 
     OUTER APPLY (
      SELECT MIN(e.master_comm_id) master_comm_id 
      FROM event e 
      WHERE e.event_type_id <> 47 
        AND EXISTS (
         SELECT 1 
         FROM comm c 
         WHERE e.master_comm_id = c.comm_id 
           AND c.item_id = a.item_id 
           AND c.comp_type_id IN (20, 485) 
        ) 
     ) mmci 
     OUTER APPLY (
      SELECT SUM(e.amount) [amount] 
      FROM event e 
      WHERE e.master_comm_id = mmci.master_comm_id 
        AND e.event_type_id <> 47 
     ) oa 
Verwandte Themen