2010-11-11 16 views
22

¿Cuál es la sintaxis correcta de MS SQL para seleccionar varias columnas ORDER BY cuando el ORDER BY se basa en una instrucción CASE?Orden dinámico por SELECT con múltiples columnas

La continuación funciona bien con columnas sencillas, pero necesito para ordenar por varias columnas:

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 

Respuesta

39

Usted podría intentar esto

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

Por mi problema particular Solía ​​'ASC final, entonces -Price,' en lugar de 'ENTONCES FIN Precio DESC' ya que tuvimos que cargar la especie columnas de la misma columna en el DB. Entonces, para hacerlo limpio separamos cada columna por un espacio y usamos el signo negativo como reemplazo de 'DESC' – th3byrdm4n

1

hacer esto ... y decir adiós a su desempeño . Lamentablemente, la mejor solución es usar sql dinámico.

+0

¿Cuidar para elaborar? Mi aplicación real de esto para un procedimiento almacenado bastante complejo donde SQL dinámico no es posible. – BradB

+0

+1. vea mi respuesta debajo de – Sadhir

+5

En mi experiencia (solo 12 años trabajando con MSSQL), me encontré con múltiples oportunidades, donde estos constructos produjeron planes terribles. No es que sea malo en sí mismo, solo que lo encontré poco confiable, es decir. la consulta que funciona muy bien hoy puede producir planes abismales 4 meses en el futuro) –

2

Pruebe esto como un menor impacto en el rendimiento del servidor, suponiendo que tiene solo 2 valores en @SortIndex (1 y 2). Si no, extiende tu If con más condiciones.

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

Huelo parámetros aquí :) .. Esta solución podría en realidad introducir la detección de parámetros – Sadhir

+1

Suponiendo que se trata de un procedimiento almacenado y @SortIndex es un parámetro del sproc. Y por argumentos, digamos que había otra condición, si @SortIndex = 3, luego ordenamos solo por Tile, y digamos que había un índice sobre el precio y otro sobre el título. Ahora, si llama al sproc por primera vez con @SortIndex = 1, el servidor SQL creará un plan ejecutivo que hace uso del índice sobre el precio. Cuando vuelva a llamar al sproc, independientemente del valor de @SortTitle, el servidor SQL usará el mismo plan que antes. Entonces, si @SortTitle = 3, aún usará el índice en el precio aunque sea inútil aquí – Sadhir

+0

Nunca asumí que este es un procedimiento almacenado. Si se trata de una instrucción SQL simple con declaración de variables y atribución de valores a variables, entonces la consulta debe tener un buen plan de ejecución, dependiendo de qué hoja "IF" vaya a ir.El usuario no dijo que era un procedimiento almacenado con un parámetro; y si realmente lo es, el rastreo de parámetros se puede habilitar o deshabilitar teniendo en cuenta la cantidad de filas recuperadas para cada combinación. – yrushka

6

@Brad. Pavel se sugiere lo siguiente (creo),

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 

¿Por qué cree que SQL dinámico no es adecuado para los procedimientos almacenados complejas? Esos son exactamente los lugares donde debería utilizar SQL dinámico, ya que puede ayudar a reducir la complejidad y resolver problemas como el rastreo de parámetros. Estoy de acuerdo en que sql dinámico tiene sus desventajas, pero recomendaría que al menos lo intentes si funciona para ti.

+0

Gracias por la sugerencia. Voy a probar este método. – BradB

+1

Cuanto más compleja es la consulta (especialmente los temidos procedimientos de lista) con múltiples entradas, múltiples opciones de clasificación, etc., los resultados más fiables que obtiene de SQL dinámico. –

+0

Mi única sugerencia aquí es proteger sus consultas dinámicas de los ataques de inyección. – Keith

1

Se podría volver a escribir esto:

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

como

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

Esto añade la columna de ordenación añadido a todos los casos, pero en mi situación, eso es lo que quería.

También puede hacer esto (justo por ejemplo):

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

Este escenario funcionó muy bien para lo que necesitaba. ¡Gracias! – tmorell

+0

He votado la respuesta de yrushka. Es una opción válida aquí. Pero en mi caso, donde utilicé lo anterior, el usuario tenía 12 columbus posibles para ordenar por lo que este estilo/opción parecía más práctico. –

+0

Y mi comentario anterior tendría más sentido si añadiera que la declaración de consulta en sí misma fue bastante complicada. Hubiera sido poco práctico en ese caso repetir la declaración completa 12 veces con diferentes cláusulas orderby. –

Cuestiones relacionadas