2009-03-30 36 views
30

Tengo un formulario donde los usuarios pueden especificar varios parámetros para explorar algunos datos (estado, fecha, etc.).Procedimiento almacenado con parámetros "DONDE" opcionales

puedo producir una consulta que es:

SELECT * FROM table WHERE: 
status_id = 3 
date = <some date> 
other_parameter = <value> 

etc. Cada WHERE es opcional (que puede seleccionar todas las filas con status = 3, o todas las filas con date = 10/10/1980, o todas las filas con status = 3 AND date = 10/10/1980 etc.)

Dado un gran número de parámetros, todos opcionales, ¿cuál es la mejor manera de compensar un procedimiento almacenado dinámico?

Estoy trabajando en varios DB, tales como: MySQL, Oracle y SQLServer.

Respuesta

44

Una de las maneras más fáciles de lograr esto:

SELECT * FROM table 
WHERE ((@status_id is null) or (status_id = @status_id)) 
and ((@date is null) or ([date] = @date)) 
and ((@other_parameter is null) or (other_parameter = @other_parameter)) 

etc. Esto elimina por completo de SQL dinámico y le permite buscar en uno o más campos. Al eliminar el sql dinámico, elimina otra preocupación de seguridad relacionada con la inyección de sql.

+2

Esto no permite que todos los parámetros sean opcionales. En este ejemplo, debe pasar @status_id. Incluso si es nulo, debe pasar nulo para que se ejecute. – Eppz

+0

Puede proporcionar un valor predeterminado para los parámetros en MS SQL Server. No sé acerca de MySQL –

+4

Solo tenga en cuenta que, dependiendo de su RDBMS y de cómo almacena en caché los planes de consulta, es posible que no obtenga el mejor rendimiento posible con este método. –

3

Usted puede hacer algo como

WHERE 
(
ParameterA == 4 OR ParameterA IS NULL 
) 

AND 
(
ParameterB == 12 OR ParameterB IS NULL 
) 
11

Crear su procedimiento como éste:

CREATE PROCEDURE [dbo].[spXXX] 
    @fromDate datetime = null, 
    @toDate datetime = null, 
    @subCode int = null 
as 
begin 
set NOCOUNT ON 
/* NOCOUNT limits the server feedback on select results record count */ 
SELECT 
    fields... 
FROM 
    source 
WHERE 
    1=1 
--Dynamic where clause for various parameters which may or may not be passed in. 
and (@fromDate is null or [dateField] >= @fromDate) 
and (@toDate is null or [dateField] <= @toDate) 
and (@subCode is null or subCode= @leaveTypeSubCode) 
order by fields... 

Esto le permitirá ejecutar el procedimiento con 0 params, todos los parametros, o cualquier # de params.

1

Si desea evitar la creación dinámica de cadenas de SQL (que a menudo es mejor evitar), puede hacerlo en procesos almacenados comparando cada criterado en su cláusula con un valor predeterminado, que equivale a "ignorar". Por ejemplo:

select * from Table where 
    (@Col1 IS NULL OR Col1 = @Col1) /*If you don't want to filter in @col, pass in NULL*/ 
    AND 
    (@Col2 IS NULL OR Col2 = @Col2) 
4

Este es el estilo que utilizo:

T-SQL

SELECT *   
FROM table   
WHERE  
status_id = isnull(@status_id ,status_id)  
and date = isnull(@date ,date)  
and other_parameter = isnull(@other_parameter,other_parameter) 

oráculo

SELECT *   
FROM table   
WHERE  
status_id = nval(p_status_id ,status_id)  
and date = nval(p_date ,date)  
and other_parameter = nval(p_other_parameter,other_parameter) 
2

Una forma legible y fácil de mantener para hacerlo (incluso utilizable con UNIR/SOLICITAR):

where 
     (@parameter1 IS NULL OR your_condition1) 
    and (@parameter2 IS NULL OR your_condition2) 
-- etc 

Sin embargo, es una mala idea en la mayoría de las mesas grandes (usando aún más JOIN/a verificar), ya que su plan de ejecución no se ignoran los valores nulos y genera laguna masiva de rendimiento (por ejemplo: escaneando toda una tabla de búsqueda de valores NULL)

Una manera indirecta en SQL Server es usar las opciones WITH (RECOMPILE) en su consulta (disponible desde SQL 2008 SP1 CU5 (10.0.2746)).

La mejor manera de implementar esto (en lo que respecta al rendimiento) es usar el bloque IF ... ELSE, uno para cada combinación posible. Tal vez sea agotador, pero tendrá las mejores actuaciones y no importa la configuración de su base de datos.

Si necesita más detalles, puede buscar KM. respuesta here.

Cuestiones relacionadas