SQL Server 2008 - Instrucțiuni Case / If din clauza SELECT [duplicat]

Am o interogare care ar trebui să ruleze așa -


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

FROM 

.
.
.

Cum pot realiza acest lucru în T-SQL fără a scrie interogări separate pentru fiecare clauză? Momentan îl conduc ca


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

Acesta este doar o mulțime de cod redundant doar pentru a selecta coloane diferite în funcție de o valoare. Ceva alternative?


person Tejaswi Yerukalapudi    schedule 13.07.2009    source sursă


Răspunsuri (6)


Doar o notă aici că, de fapt, ar fi mai bine să aveți 3 SELECTE separate din motive de optimizare. Dacă aveți un singur SELECT, atunci planul generat va trebui să proiecteze toate coloanele col1, col2, col3, col7, col8 etc, deși, în funcție de valoarea runtime @var, sunt necesare doar unele. Acest lucru poate duce la planuri care efectuează căutări inutile ale indexului grupat, deoarece indexul non-cluster nu acoperă toate coloanele proiectate de SELECT.

Pe de altă parte, 3 SELECTE separate, fiecare proiectând numai coloanele necesare poate beneficia de indici non-cluster care acoperă doar coloana proiectată în fiecare caz.

Desigur, aceasta depinde de schema reală a modelului dvs. de date și de interogările exacte, dar acesta este doar un avertisment, astfel încât să nu aduceți cadrul de gândire imperativ al programării procedurale în lumea declarativă a SQL.

person Remus Rusanu    schedule 14.07.2009
comment
+1 observație foarte bună - person Sam Saffron; 14.07.2009

Căutați declarația CASE

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

Exemplu copiat de pe MSDN:

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
person Sam Saffron    schedule 13.07.2009
comment
Se pare că am fost ninja-d! :) - person Jeffrey Hantin; 14.07.2009
comment
Sunt încă un n00b, așa că aș putea (cu ușurință) să greșesc, dar cred că acest lucru nu răspunde de fapt la întrebare, nu? OP a întrebat cum ar putea să selecteze mai multe coloane, nu să atribuie una dintre mai multe opțiuni de valori unei singure coloane, ceea ce se pare că aceasta (și mai multe dintre răspunsuri) face. Dacă aș fi OP, s-ar părea că răspunsul de la @JoelMansford este cel mai corect. Vă rog să-mi spuneți dacă/de ce greșesc dacă greșesc! - person dah97765; 01.10.2013

Încearcă ceva de genul

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

Cu alte cuvinte, utilizați o expresie condiționată pentru a selecta valoarea, apoi redenumiți coloana.

Alternativ, puteți crea un fel de hack SQL dinamic pentru a partaja coada interogării; Am mai făcut asta cu iBatis.

person Jeffrey Hantin    schedule 13.07.2009

Expresie CASE simplă:

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

Expresia CASE căutată:

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

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

person Sutirth    schedule 16.11.2011

CASE este răspunsul, dar va trebui să aveți o declarație case separată pentru fiecare coloană pe care doriți să o returnați. Atâta timp cât clauza WHERE este aceeași, nu va exista prea mult beneficiu prin separarea ei în mai multe interogări.

Exemplu:

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
...
person Rob Boek    schedule 14.07.2009

Cele mai evidente soluții sunt deja enumerate. În funcție de locul în care se află interogarea (adică în codul aplicației), nu puteți utiliza întotdeauna instrucțiunile IF, iar instrucțiunile CASE inline pot deveni dureroase acolo unde multe coloane devin condiționate. Presupunând că Col1 + Col3 + Col7 sunt de același tip și, de asemenea, Col2, Col4 + Col8 puteți face acest lucru:

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'

Deoarece aceasta este o singură comandă, există mai multe beneficii de performanță în ceea ce privește memorarea în cache a planului. De asemenea, Optimizatorul de interogări va elimina rapid acele instrucțiuni în care @Var nu se potrivește cu valoarea corespunzătoare, fără a atinge motorul de stocare.

person Joel Mansford    schedule 14.07.2009