2009-07-13 10 views
18

Ich habe eine Abfrage, die wie folgt ausgeführt wird angenommen hat -SQL Server 2008 - Case/If-Anweisungen in SELECT-Klausel

 

If(var = xyz) 
    SELECT col1, col2 
ELSE IF(var = zyx) 
    SELECT col2, col3 
ELSE 
    SELECT col7,col8 

FROM 

. 
. 
. 

Wie erreiche ich das in T-SQL, ohne für jede Klausel separate Abfragen zu schreiben? Zur Zeit leite ich es als

 

IF (var = xyz) { 
    Query1 
} 
ELSE IF (var = zyx) { 
    Query2 
} 
ELSE { 
    Query3 
} 

Das ist nur eine Menge redundanter Code, nur um verschiedene Spalten abhängig von einem Wert auszuwählen. Irgendwelche Alternativen?

Antwort

18

Nur eine Anmerkung hier, dass Sie eigentlich besser aus 3 SELECTS aus Gründen der Optimierung sein können. Wenn Sie nur eine einzige SELECT-Anweisung haben, muss der generierte Plan alle Spalten col1, col2, col3, col7, col8 usw. projizieren, obwohl abhängig vom Wert der Laufzeit @var nur einige benötigt werden. Dies kann dazu führen, dass Pläne unnötige Clustered-Index-Lookups durchführen, da der Nicht-Clustered-Index nicht alle von SELECT ausgewählten Spalten abdeckt.

Auf der anderen Seite können 3 separate SELECTS, von denen jede nur die benötigten Spalten projiziert, von nicht geclusterten Indizes profitieren, die jeweils nur Ihre projizierte Spalte abdecken.

Natürlich hängt dies vom tatsächlichen Schema Ihres Datenmodells und den genauen Abfragen ab, aber dies ist nur ein Kopf, so dass Sie den imperativ denkenden Mind Frame der prozeduralen Programmierung nicht in die deklarative Welt von SQL bringen.

+3

+1 sehr gute Beobachtung –

22

Sie suchen die CASE-Anweisung

http://msdn.microsoft.com/en-us/library/ms181765.aspx

Beispiel von MSDN kopiert:

USE AdventureWorks; 
GO 
SELECT ProductNumber, Category = 
     CASE ProductLine 
     WHEN 'R' THEN 'Road' 
     WHEN 'M' THEN 'Mountain' 
     WHEN 'T' THEN 'Touring' 
     WHEN 'S' THEN 'Other sale items' 
     ELSE 'Not for sale' 
     END, 
    Name 
FROM Production.Product 
ORDER BY ProductNumber; 
GO 
+0

Sieht aus wie ich ninja'd worden sind! :) –

+0

Ich bin immer noch ein n00b, also könnte ich (leicht) falsch liegen, aber ich denke, das beantwortet nicht wirklich die Frage, richtig? Das OP fragte, wie er ** mehrere ** Spalten auswählen könnte, und nicht eine von mehreren Optionen von Werten einer einzelnen Spalte zuweisen würde, was es scheint (und mehrere der Antworten). Wenn ich das OP wäre, scheint die Antwort von @JoelMansford am richtigsten zu sein. Bitte lass mich wissen, wenn/warum ich falsch liege, wenn ich es bin! – dah97765

9

Probieren Sie etwas wie

SELECT 
    CASE var 
     WHEN xyz THEN col1 
     WHEN zyx THEN col2 
     ELSE col7 
    END AS col1, 
    ... 

Mit anderen Worten, verwenden Sie einen bedingten Ausdruck Um den Wert auszuwählen, benennen Sie die Spalte um.

Alternativ könnten Sie eine Art dynamischer SQL-Hack erstellen, um den Query Tail zu teilen; Ich habe das schon vorher mit iBatis gemacht.

0

CASE ist die Antwort, aber Sie müssen eine separate case-Anweisung für jede Spalte haben, die Sie zurückgeben möchten. Solange die WHERE-Klausel dieselbe ist, wird es keinen großen Vorteil haben, sie in mehrere Abfragen aufzuteilen.

Beispiel:

SELECT 
    CASE @var 
     WHEN 'xyz' THEN col1 
     WHEN 'zyx' THEN col2 
     ELSE col7 
    END, 
    CASE @var 
     WHEN 'xyz' THEN col2 
     WHEN 'zyx' THEN col3 
     ELSE col8 
    END 
FROM Table 
... 
0

Die offensichtlichsten Lösungen bereits aufgeführt sind. Abhängig davon, wo die Abfrage gesetzt ist (d.h. im Anwendungscode), können Sie IF-Anweisungen nicht immer verwenden, und die CASE-Inline-Anweisungen können schmerzhaft werden, wenn viele Spalten bedingt werden. Unter der Annahme, Col1 + Col3 + COL7 vom gleichen Typ sind, und ebenfalls Col2, Col4 + CoL8 Sie können dies tun:

SELECT Col1, Col2 FROM tbl WHERE @Var LIKE 'xyz' 
UNION ALL 
SELECT Col3, Col4 FROM tbl WHERE @Var LIKE 'zyx' 
UNION ALL 
SELECT Col7, Col8 FROM tbl WHERE @Var NOT LIKE 'xyz' AND @Var NOT LIKE 'zyx' 

Da dies ein einziger Befehl mehrere Leistungsvorteile hinsichtlich sind Caching zu planen. Auch das Query Optimiser eliminiert schnell die Anweisungen, bei denen @Var nicht mit dem entsprechenden Wert übereinstimmt, ohne die Speicher-Engine zu berühren.

2

Einfache CASE-Ausdruck:

CASE input_expression 
    WHEN when_expression THEN result_expression [ ...n ] 
    [ ELSE else_result_expression ] 
END 

Gesucht CASE-Ausdruck:

CASE 
    WHEN Boolean_expression THEN result_expression [ ...n ] 
    [ ELSE else_result_expression ] 
END 

Referenz: http://msdn.microsoft.com/en-us/library/ms181765.aspx