2009-07-18 6 views
19

Escribo un SP que acepta como columna de parámetros para ordenar y dirección.Dirección de orden dinámica

No quiero usar SQL dinámico.

El problema está en establecer el parámetro de dirección.

Este es el código parcial:

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

recomendaría recogiendo Patt conversión ern para AddedDate que asegura que las cadenas de caracteres ordenarán el orden de las fechas. Creo que la conversión predeterminada puede cambiar con la configuración de localidad. Mejor definir explícitamente y estar seguro. –

+0

¿Se aplica a algunos otros tipos? ¿O solo la FECHA? – markiz

+0

Los números también serán un problema. Por ejemplo, convertir 10, 1 y 2 a varchar le dará una especie de '1', '10', '2'. Imagino que está convirtiendo Visible y AddedDate en varchar porque un CASE tiene que devolver todo el mismo tipo, ¿correcto? –

Respuesta

27

Usted podría tener dos ORDEN casi idénticas de elementos, uno ASC y uno DESC, y extender su instrucción CASE para hacer uno u otro de ellos siempre igual a un valor único:

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

¿me puede responder la misma pregunta que le hice a Alex Black en el comentario? – markiz

+0

Acaba de hacer ORDER BY Column1 ASC, Column2 DESC (lo que significa orden por Columna1 ascendente, luego por Columna2 descendente) pero en lugar de Columna1 y Columna2 tiene una expresión para cada uno. –

+0

si AddedDate es una columna de fecha y hora, debe usar _CONVERT (char (23), AddedDate, 121) _ o no ordenará correctamente –

3

Aquí se muestra un ejemplo:

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 

A partir de aquí:

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

ascendente y acciones descendente necesitan a agruparse en declaraciones CASE separadas, separadas por una coma. En su código de servidor/script asegurarse a anexar 'Asc' o 'descripción' en el orden por la cadena, ya que podría tener dos parámetros de entrada del procedimiento almacenado para el nombre la columna y el orden por la dirección si que quieren .

+0

¿me puede explicar esta sintaxis de CASO FINAL (ASC), (coma)? Si la entrada es ProductNameDesc, ¿no generará: .. ORDER BY ASC, ProductName DESC? el "asc", que sigue al final, es la parte del enunciado, ¿no es así? - markiz 0 segundos atrás [eliminar este comentario] – markiz

+0

No lo sé, simplemente busqué en Google ese artículo. La respuesta de Gary a continuación parece usar la misma técnica. –

+0

hey markiz, solo debes * probar * it. Básicamente estás diciendo que no crees que lo que este artículo sugiera funcionará, así que solo pruébalo, apuesto a que funcionará bien. –

10

Puede Simplifique el CASO utilizando ROW_NUMBER que ordena sus datos y los convierte efectivamente en un formato entero útil. Sobre todo porque la cuestión está marcado SQL Server 2005

Esto también se expande fácilmente lo suficiente como para hacer frente a las clases secundarias y terciarias

He usado multiplicador para simplificar más la instrucción de selección actual y reducir la posibilidad de evaluación en el 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

¿Ha notado algún golpe de rendimiento con hacer '' ROW_NUMBER() '' múltiples? Entiendo que los datos de everyones son diferentes. –

+0

@ Scotty.NET, estaba preocupado por el rendimiento de row_number, después de algunas pruebas la implementación row_number se ve un poco mejor que los casos múltiples en orden por cláusula, excepto cuando se necesita una porción de los datos. De hecho, el mejor resultado que he encontrado fue con solo un número de rown sobre los casos - [aquí hay una pequeña idea con mis consultas] (https://gist.github.com/thluiz/228c9e496322695e66213815aa80254e). –

1

Esto funciona muy bien para mí - (donde, por fin, la dirección, ir a buscar a compensar)

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 
Cuestiones relacionadas