带有可选“WHERE”参数的存储过程

时间:2009-03-30 15:21:42

标签: sql mysql sql-server oracle

我有一个表单,用户可以指定各种参数来挖掘一些数据(状态,日期等)。

我可以生成一个查询:

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

等。每个WHERE都是可选的(我可以选择status = 3的所有行,或date = 10/10/1980的所有行,或status = 3 AND date = 10/10/1980等所有行。)

给定大量参数,所有可选项,构成动态存储过程的最佳方法是什么?

我正在研究各种数据库,例如: MySQL,Oracle和SQLServer。

6 个答案:

答案 0 :(得分:54)

实现这一目标的最简单方法之一:

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))

等。 这完全消除了动态sql,并允许您搜索一个或多个字段。通过消除动态sql,您可以删除有关sql注入的另一个安全问题。

答案 1 :(得分:11)

像这样创建你的程序:

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...

这将允许您使用0参数,所有参数或任何#srms执行该过程。

答案 2 :(得分:5)

这是我使用的风格:

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) 

oracle

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)

答案 3 :(得分:3)

您可以执行类似

的操作
WHERE 
(
 ParameterA == 4 OR ParameterA IS NULL
)

AND
(
 ParameterB == 12 OR ParameterB IS NULL
)

答案 4 :(得分:3)

一种可读且可维护的方法(甚至可用于JOIN / APPLY):

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

然而,对于大多数大表(甚至更多使用JOIN / APPLY)来说这是一个坏主意,因为您的执行计划不会忽略NULL值并产生大量性能漏洞(例如:扫描所有搜索NULL值的表)。

SQL Server中的一种迂回方式是在查询中使用WITH(RECOMPILE)选项(自SQL 2008 SP1 CU5(10.0.2746)起可用)。

实现这一点(性能方面)的最佳方法是使用IF ... ELSE块,每种组合可以使用一个。也许这很累,但你会有最好的表现,而且数据库的设置无关紧要。

如果您需要更多详细信息,可以查找知识管理。回答here

答案 5 :(得分:1)

如果您想避免动态构建SQL字符串(通常最好避免),您可以在存储过程中执行此操作,方法是将where claject中的每个critera与默认值(等于“ignore”)进行比较。 E.g:

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)