2010-11-11 23 views
22

Qual è la sintassi MS SQL corretta per selezionare più colonne ORDER BY quando ORDER BY si basa su un'istruzione CASE?Ordine dinamico con SELECT con più colonne

Il sotto funziona bene con colonne singole, ma ho bisogno di ordinare in base a più colonne:

SELECT * FROM Products 
ORDER BY 
CASE WHEN @SortIndex = 1 THEN Price END ASC, 
CASE WHEN @SortIndex = 2 THEN Price DESC, Title ASC END <-- problem line 

risposta

39

si potrebbe provare questo

SELECT * FROM Products 
ORDER BY 
CASE WHEN @SortIndex = 1 THEN Price END ASC, 
CASE WHEN @SortIndex = 2 THEN Price END DESC, 
CASE WHEN @SortIndex = 2 THEN Title END ASC 
+0

Per il mio problema particolare ho usato 'ASC FINE POI -Price,' invece di 'ALLORA prezzo finale desc' come abbiamo dovuto caricare il tipo colonne dalla stessa colonna nel DB. Quindi per renderlo pulito abbiamo separato ogni colonna di uno spazio e usato il segno negativo in sostituzione di 'DESC' – th3byrdm4n

1

fare questo ... e dire addio alla tua performance . Sfortunatamente la soluzione migliore è usare SQL dinamico.

+0

Cura da elaborare? La mia vera applicazione di questo per una stored procedure piuttosto complessa in cui SQL dinamico non è possibile. – BradB

+0

+1. vedi la mia risposta sotto – Sadhir

+5

Nella mia esperienza (solo 12 anni di lavoro con MSSQL), mi sono imbattuto in più occasioni, dove questi costrutti hanno prodotto piani terribili. Non è che è di per sé cattivo, solo che l'ho trovato inaffidabile, vale a dire. query che funziona alla grande oggi potrebbe produrre piani abissali 4 mesi in futuro) –

2

Provare a ridurre l'impatto sulle prestazioni del server, presupponendo che siano presenti solo 2 valori su @SortIndex (1 e 2). In caso contrario, estendi il tuo Se con più condizioni.

If @SortIndex = 1 
BEGIN 
    SELECT * FROM Products ORDER BY Price ASC 
END 
ELSE 
BEGIN 
    SELECT * FROM Products ORDER BY Price DESC, TITLE ASC 
END 
+0

I parametri odore qui :) .. Questa soluzione potrebbe effettivamente introdurre il parametro sniffing – Sadhir

+1

Supponendo che questa è una stored procedure e @SortIndex è un parametro per sproc. E per ragioni argomentative, diciamo che c'era un'altra condizione - se @SortIndex = 3, quindi ordinare solo per Tile, e diciamo che c'era un indice sul prezzo e uno sul titolo. Ora, se si chiama lo sproc per la prima volta con @SortIndex = 1, il server SQL creerà un piano exec che utilizza l'indice sul prezzo. Quando si richiama nuovamente lo sproc, indipendentemente dal valore per @SortTitle, SQL Server utilizzerà lo stesso piano di prima. Quindi, se @SortTitle = 3, continuerà a utilizzare l'indice sul prezzo anche se è inutile qui – Sadhir

+0

Non ho mai pensato che questa sia una stored procedure. Se si tratta di una semplice istruzione SQL con la dichiarazione di variabili e l'attribuzione di valori alle variabili, la query dovrebbe avere un buon piano di esecuzione, a seconda di quale "IF" dovrà andare.L'utente non ha detto che si trattava di una procedura memorizzata con un parametro; e se lo è davvero, lo sniffing dei parametri può essere abilitato o disabilitato considerando la quantità di righe recuperate per ciascuna combinazione. – yrushka

6

@Brad. Pavel stava suggerendo il seguente (credo),

DECLARE @query VARCHAR(MAX) 

SET @query = 'SELECT * FROM Products 
       ORDER BY 
       ' 

IF (@SortIndex = 1) 
    SET @query [email protected] + ' Price ASC ' 
ELSE IF (@SortIndex = 2) 
    SET @query [email protected] + ' Price DESC, Title ASC ' 

sp_executesql @query 

Perché pensi che SQL dinamico non è adatto per le stored procedure complesse? Questi sono esattamente i punti in cui dovresti utilizzare SQL dinamico in quanto può aiutare a ridurre la complessità e risolvere problemi come lo sniffing dei parametri. Sono d'accordo che SQL dinamico ha i suoi lati negativi, ma ti consiglierei di provarlo almeno se funziona per te.

+0

Grazie per il suggerimento. Proverò questo metodo. – BradB

+1

Quanto più complessa risulta la query (in particolare le procedure di elenco temuto) con più input, più scelte di ordinamento, ecc., I risultati più affidabili ottenuti da SQL dinamico. –

+0

Il mio unico suggerimento qui è quello di proteggere le vostre query dinamiche dagli attacchi di iniezione. – Keith

1

Si potrebbe riscrivere questo:

ORDER BY 
CASE WHEN @SortIndex = 1 THEN Price END ASC, 
CASE WHEN @SortIndex = 2 THEN Price DESC, Title ASC END 

come

CASE WHEN @SortIndex = 1 THEN Price END ASC, 
CASE WHEN @SortIndex = 2 THEN Price DESC END, 
Title ASC 

Questo aggiunge la colonna di ordinamento aggiunto a tutti i casi, ma nella mia situazione, che è quello che volevo.

Si può anche fare questo (solo per esempio):

CASE WHEN @SortIndex = 1 THEN Price END ASC,Title ASC, 
CASE WHEN @SortIndex = 2 THEN Price DESC END 
+0

Questo scenario ha funzionato perfettamente per ciò di cui avevo bisogno. Grazie! – tmorell

+0

Ho votato la risposta di yrushka. È un'opzione valida qui. Ma nel mio caso, dove ho usato quanto sopra, l'utente aveva 12 possibili columb da ordinare, quindi questo stile/opzione sembrava più pratico. –

+0

E il mio commento sopra avrebbe più senso se aggiungessi che l'istruzione della query stessa era piuttosto coinvolta. In tal caso sarebbe stato poco pratico ripetere l'intero statuto 12 volte con diverse clausole order-by. –