2010-06-10 30 views
5

Necesito escribir un procedimiento almacenado para SQL Server 2008 para realizar una gran consulta select y necesito filtrar los resultados especificando el tipo de filtrado a través de los parámetros del procedimiento. Encontré algunas soluciones como esta:Parametrizar la cláusula WHERE?

create table Foo(
    id bigint, code char, name nvarchar(max)) 
go 

insert into Foo values 
(1,'a','aaa'), 
(2,'b','bbb'), 
(3,'c','ccc') 
go 

create procedure Bar 
     @FilterType nvarchar(max), 
     @FilterValue nvarchar(max) as 
begin 
    select * from Foo as f 
    where case @FilterType 
      when 'by_id' then f.id 
      when 'by_code' then f.code 
      when 'by_name' then f.name end 
      = 
      case @FilterType 
      when 'by_id' then cast(@FilterValue as bigint) 
      when 'by_code' then cast(@FilterValue as char) 
      when 'by_name' then @FilterValue end 
end 
go 

exec Bar 'by_id', '1'; 
exec Bar 'by_code', 'b'; 
exec Bar 'by_name', 'ccc'; 

Me parece que este enfoque no funciona. Es posible emitir todas las columnas al nvarchar(max) y compararlas como cadenas, pero creo que provocará la degradación del rendimiento.

¿Es posible parametrizar la cláusula where en procedimiento almacenado sin utilizar construcciones como EXEC sp_executesql?

+0

¿Has probado LinQ a SQL? –

Respuesta

2

Esto puede llegar a ser un poco más largo aliento, para grandes requisitos de filtro, pero creo que es probablemente más performante/más fácil de leer/mantener:

create procedure Bar 
     @Id int, 
     @Code nvarchar, 
     @name nvarchar 
begin 
    select * from Foo as f 
    where (@id = -1 or f.ID = @id) 
    and (@Code = '' or f.Code = @Code) 
    and (@Name = '' or f.Name = @Name) 
end 
go 

exec Bar 1, '', '' 
exec Bar -1, 'code', '' 
exec Bar -1, '', 'name' 

Esto también le permite filtrar por más de un elemento al mismo tiempo.

+0

Creo que podría reemplazar el "y" externo con ors, y soltar la primera parte de la cláusula o, como sigue: ... donde f.ID = @id o f. Código = @Code o f.Name = @Name. (Esto funcionaría con valores nulos, a menos que estuviera buscando columnas que se configuraron como nulas). –

+0

@Philip Kelley - Depende de lo que quiera que haga el filtro - si desea regresar donde coincide en cualquiera de los campos pasados, entonces eso funcionaría. – Paddy

2

probar este

create procedure Bar 
     @FilterType nvarchar(max), 
     @FilterValue nvarchar(max) as 
begin 
    select * from Foo as f 
    where 
     (@FilterType ='by_id' and f.id =cast(@FilterValue as bigint)) 
     OR 
     (@FilterType ='by_code' and f.code =cast(@FilterValue as char) 
     OR 
     (@FilterType ='by_name' and f.name [email protected] 

end 
go 
+0

gracias, pero no funciona ... SQL Server intenta ejecutar todas las ramas 'y' y no puede convertir los datos en el lado derecho ... – ControlFlow

+0

¿Estás seguro? La parte OR se ocupará de ello – Madhivanan

0
declare @field varchar(20) 

declare @value varchar(100) 

set @field = 'customerid' 
set @value = 'ALFKI' 

set @field = 'Country' 
set @value = 'Germany' 

set @field = 'ContactTitle' 
set @value = 'Owner' 

select * from customers 
where (customerid = (case when @field = 'customerid' then @value else customerid end) 
and ContactTitle = (case when @field = 'ContactTitle' then @value else ContactTitle end) 
and country = (case when @field = 'Country' then @value else country end)) 

Ejemplo está adaptado para la base de datos Northwind.
Espero que esto ayude.

EDITAR: Comente cualquiera de 2 de los 3 valores para @field y @value para arriba.

0

Si no tiene muchos criterios de filtrado, podría considerar crear funciones de delegado y enviar la solicitud a la apropiada. Por ejemplo,

create procedure Bar 
     @FilterType nvarchar(max), 
     @FilterValue nvarchar(max) as 
begin 
    case @FilterType 
      when 'by_id' then FilterById(@FilterValue) 
      when 'by_code' then FilterByCode(@FilterValue) 
      when 'by_name' then FilterByName(@FilterValue) 
      end 
end 
go