2010-06-10 5 views
5

Je dois écrire une procédure stockée pour SQL Server 2008 pour effectuer une grande requête select et j'en ai besoin pour filtrer les résultats en spécifiant le type de filtrage via les paramètres de la procédure. J'ai trouvé quelques solutions comme ceci:Paramétrer la clause 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'; 

Je trouve que cette approche ne fonctionne pas. Il est possible de convertir toutes les colonnes en nvarchar(max) et de les comparer en tant que chaînes, mais je pense que cela entraînera une dégradation des performances.

Est-il possible de paramétrer la clause where dans la procédure stockée sans utiliser de constructions telles que EXEC sp_executesql?

+0

Avez-vous essayé LinQ to SQL? –

Répondre

2

Cela peut devenir un peu plus longue haleine, pour les besoins de grands filtres, mais je pense qu'il probablement plus performant/plus facile à lire/maintenir:

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' 

Cela vous permet également de filtrer par plus d'un élément en même temps.

+0

Je pense que vous pourriez remplacer les "et" extérieurs par des ors, et supprimer la première partie de la clause or, comme ceci: ... où f.ID = @id ou f. Code = @Code ou f.Name = @Name. (Cela fonctionnerait avec des valeurs nulles, sauf si vous recherchiez des colonnes qui ont la valeur null.) –

+0

@Philip Kelley - Dépend de ce que vous voulez que le filtre fasse - si vous voulez retourner où vous correspondez sur l'un des champs passés, alors ça marcherait. – Paddy

2

Essayez ce

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

merci, mais ça ne marche pas ... SQL Server essaie d'exécuter toutes les branches 'and' et ne parvient pas à convertir les données sur les bons côtés ... – ControlFlow

+0

Etes-vous sûr? La partie OR s'en chargera – 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)) 

l'exemple est adapté à la base de données Northwind.
Espérons que cela aide.

EDIT: Commentez 2 des 3 valeurs pour @field et @value pour ci-dessus.

0

Si vous n'avez pas beaucoup de critères de filtrage, vous pouvez envisager de créer des fonctions de délégation et d'envoyer la demande à la bonne personne. E.g.,

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