2010-06-10 17 views
5

Potrzebuję napisać procedurę przechowywaną dla SQL Server 2008 do wykonania dużego zapytania select i potrzebuję go do filtrowania wyników z określeniem typu filtrowania za pomocą parametrów procedury. Znalazłem kilka takich rozwiązań:Parametryzować klauzulę 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'; 

Zauważyłem, że to podejście nie działa. Możliwe jest rzutowanie wszystkich kolumn na nvarchar(max) i porównywanie ich jako łańcuchów, ale myślę, że spowoduje to pogorszenie wydajności.

Czy można parametryzować klauzulę where w procedurze przechowywanej bez użycia takich konstrukcji jak EXEC sp_executesql?

+0

Czy próbowałeś LinQ do SQL? –

Odpowiedz

2

To może stać się trochę bardziej długi dmuchania, w przypadku dużych wymagań filtracyjnych, ale myślę, że chyba bardziej wydajnych/łatwiejsze do odczytu/utrzymania:

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' 

ta pozwala również filtrować przez więcej niż jedną pozycję w tym samym czasie.

+0

Myślę, że możesz zamienić zewnętrzny "i" na ors i upuścić pierwszą część lub klauzuli, tak jak: ... gdzie f.ID = @id lub f. Code = @Code lub f.Name = @Name. (Działałoby to z wartościami null, chyba że szukałeś kolumn, które miały wartość null.) –

+0

@Philip Kelley - Zależy od tego, co chcesz zrobić z filtrem - jeśli chcesz powrócić tam, gdzie pasujesz do któregoś z podanych pól, to by działało. – Paddy

2

Spróbuj

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

dziękuję, ale to nie działa ... SQL Server próbuje wykonać wszystkie gałęzie 'i' i nie może konwertować danych po prawej stronie ... – ControlFlow

+0

Czy jesteś pewien? Część OR zajmie się tym – 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)) 

Przykład przystosowany jest do bazy danych Northwind.
Mam nadzieję, że to pomoże.

EDYCJA: Skomentuj dowolne 2 z 3 wartości dla @field i @value dla powyższych.

0

Jeśli nie masz wielu kryteriów filtrowania, możesz rozważyć utworzenie funkcji pełnomocnika i wysłanie żądania do odpowiedniej. Np.,

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 
Powiązane problemy