2009-07-18 12 views
19

Scrivo un SP che accetta come colonna parametri per ordinare e direzione.Direzione ordine dinamico

Non voglio utilizzare SQL dinamico.

Il problema è con l'impostazione del parametro di direzione.

Questo è il codice parziale:

SET @OrderByColumn = 'AddedDate' 
SET @OrderDirection=1; 
. 
. 
. 
ORDER BY 
     CASE WHEN @OrderByColumn='AddedDate' THEN CONVERT(varchar(50),AddedDate)   
      WHEN @OrderByColumn='Visible' THEN CONVERT(varchar(2), Visible)  
      WHEN @OrderByColumn='AddedBy' THEN AddedBy  
      WHEN @OrderByColumn='Title' THEN Title  
     END 
+1

mi sento di raccomandare la raccolta di conversione patt ern per AddedDate che si assicura che le stringhe di caratteri si ordinino in ordine di data. Credo che la conversione predefinita possa cambiare con le impostazioni della località. Meglio definire in modo esplicito ed essere sicuro. –

+0

Si applica ad altri tipi? O solo la DATA? – markiz

+0

Anche i numeri saranno un problema. Ad esempio, la conversione da 10, 1 e 2 a varchar ti darà una sorta di '1', '10', '2'. Immagino che stai convertendo Visible e AddedDate in varchar perché un CASE deve restituire tutti lo stesso tipo, corretto? –

risposta

27

Si potrebbe avere due vicino-identici ORDER BY articoli, uno ASC e uno DESC, ed estendere la vostra dichiarazione caso di fare uno o l'altro di essi eguagliare sempre un unico valore:

ORDER BY 
     CASE WHEN @OrderDirection=0 THEN 1 
     ELSE 
      CASE WHEN @OrderByColumn='AddedDate' THEN CONVERT(varchar(50),AddedDate)   
       WHEN @OrderByColumn='Visible' THEN CONVERT(varchar(2), Visible)  
       WHEN @OrderByColumn='AddedBy' THEN AddedBy   
       WHEN @OrderByColumn='Title' THEN Title 
      END 
     END ASC, 
     CASE WHEN @OrderDirection=1 THEN 1 
     ELSE 
      CASE WHEN @OrderByColumn='AddedDate' THEN CONVERT(varchar(50),AddedDate)   
       WHEN @OrderByColumn='Visible' THEN CONVERT(varchar(2), Visible)  
       WHEN @OrderByColumn='AddedBy' THEN AddedBy   
       WHEN @OrderByColumn='Title' THEN Title 
      END 
     END DESC 
+0

puoi rispondere alla stessa domanda che ho chiesto ad Alex Black in un commento? – markiz

+0

Stai facendo solo ORDER BY Column1 ASC, Column2 DESC (che significa ordine di Column1 crescente, quindi di Column2 decrescente) ma invece di Column1 e Column2 hai un'espressione per ciascuno. –

+0

se AddedDate è una colonna datetime è necessario utilizzare _CONVERT (char (23), AddedDate, 121) _ oppure non verrà ordinata correttamente –

3

Ecco un esempio:

CREATE PROCEDURE GetProducts 
( 
    @OrderBy  VARCHAR(50), 
    @Input2  VARCHAR(30) 
) 
AS 
BEGIN 
    SET NOCOUNT ON 

    SELECT Id, ProductName, Description, Price, Quantity 
    FROM Products 
    WHERE ProductName LIKE @Input2 
    ORDER BY 
     CASE    
      WHEN @OrderBy = 'ProductNameAsc' THEN ProductName 
     END ASC, 
     CASE 
      WHEN @OrderBy = 'ProductNameDesc' THEN ProductName 
     END DESC 

END 

Da qui:

http://www.dominicpettifer.co.uk/Blog/21/dynamic-conditional-order-by-clause-in-sql-server-t-sql

Crescente e le azioni Discendente bisogno aessere raggruppati in istruzioni CASE separate, separate da una virgola. In il codice lato server/script assicurarsi ad appendere 'Asc' o 'Disc' sulla fine da stringa, o si potrebbe avere due parametri di input stored procedure per nome colonne e l'ordine dalla direzione se si desidera .

+0

puoi spiegare questa sintassi CASE END, (virgola) CASE? Se l'input è ProductNameDesc, non genererà: .. ORDER BY ASC, ProductName DESC? la "asc", che segue la fine è la parte dell'affermazione, non è vero? - markiz 0 secondi fa [elimina questo commento] – markiz

+0

Non lo so, ho cercato su Google per trovare quell'articolo. La risposta di Gary di seguito sembra utilizzare la stessa tecnica. –

+0

hey markiz, dovresti solo * provare * it. In pratica stai dicendo che non credi che ciò che questo articolo suggerisce funzionerà, quindi provaci, scommetto che funzionerà bene. –

10

Puoi Semplifica il CASO utilizzando ROW_NUMBER che ordina i tuoi dati e li converte in un pratico formato intero. Tanto più che la questione è aggiunto SQL Server 2005

Questo espande anche abbastanza facilmente a che fare con i tipi secondari e terziari

ho usato moltiplicatore per semplificare ancora una volta la dichiarazione reale selezionare e ridurre la possibilità di valutare in rbar ORDER bY

DECLARE @multiplier int; 

SELECT @multiplier = CASE @Direction WHEN 1 THEN -1 ELSE 1 END; 

SELECT 
    Columns you actually want 
FROM 
    (
    SELECT 
     Columns you actually want, 
     ROW_NUMBER() OVER (ORDER BY AddedDate) AS AddedDateSort, 
     ROW_NUMBER() OVER (ORDER BY Visible) AS VisibleSort, 
     ROW_NUMBER() OVER (ORDER BY AddedBy) AS AddedBySort, 
     ROW_NUMBER() OVER (ORDER BY Title) AS TitleSort 
    FROM 
     myTable 
    WHERE 
     MyFilters... 
    ) foo 
ORDER BY 
    CASE @OrderByColumn 
     WHEN 'AddedDate' THEN AddedDateSort 
     WHEN 'Visible' THEN VisibleSort  
     WHEN 'AddedBy' THEN AddedBySort 
     WHEN 'Title' THEN TitleSort 
    END * @multiplier; 
+0

Hai notato un risultato di prestazioni con più 'ROW_NUMBER()'? S Capisco che tutti i dati sono diversi. –

+0

@ Scotty.NET, ero preoccupato per le prestazioni di row_number, dopo alcuni test l'implementazione di numero_riga sembra leggermente migliore di i casi multipli in ordine per clausola, tranne quando hai bisogno di una porzione di dati. In effetti, il risultato migliore che ho trovato è stato con un solo Rownumber sui casi - [ecco un piccolo senso con le mie domande] (https://gist.github.com/thluiz/228c9e496322695e66213815aa80254e). –

1

Questo funziona bene per me - (dove, per ordine, direzione, compensato prendere)

parameters 

    @orderColumn int , 
    @orderDir varchar(20), 
    @start int , 
    @limit int 


    select * from items 
    WHERE  (items.status = 1) 
    order by 

    CASE WHEN @orderColumn = 0 AND @orderdir = 'desc' THEN items.[category] END DESC,  
    CASE WHEN @orderColumn = 0 AND @orderdir = 'asc' THEN items.[category] END ASC,  
    CASE WHEN @orderColumn = 1 AND @orderdir = 'desc' THEN items.[category] END DESC, 
    CASE WHEN @orderColumn = 1 AND @orderdir = 'asc' THEN items.[category] END ASC, 
    CASE WHEN @orderColumn = 2 AND @orderdir = 'desc' THEN items.[category] END DESC, 
    CASE WHEN @orderColumn = 2 AND @orderdir = 'asc' THEN items.[category] END ASC 

    OFFSET @start ROWS FETCH NEXT @limit ROWS ONLY