我有一个表单,用户可以指定各种参数来挖掘一些数据(状态,日期等)。
我可以生成一个查询:
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。
答案 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)