SQL 服务器中的 ALL IF Null 逻辑
ALL IF Null logic in SQL Server
我们需要在网页中实现搜索功能。所以我们创建了一个存储过程来检索记录。
逻辑是,当 i select 输入参数 Sp returns 参数的过滤记录时,它会检索所有可用记录。
例如:如果我给,
EXEC [WB_GetClassesByLocation_new2] null,null,null,'null',null,NULL,'N','N','N','N','N','N','N',NULL,null,null,null,null,null
(N 是天数字段的默认值)
SP 将 return 所有可用的记录。
如果我给,
EXEC [WB_GetClassesByLocation_new2] 1000,null,null,'null',null,NULL,'N','N','N','N','N','N','N',NULL,null,null,null,null,null
。 SP 将 return 区 1000 的记录。我已经实现了以下逻辑
Select distinct c.classID, co.fCourseName as CourseName, StreetAddress + ', ' + l.City as LocationAddress, s.SessionName, sh.fShift as shift, StartTime, EndTime, c.classname, s.SessionID,
c.StartDate,c.enddate
From dbo.vw_Class c
Inner Join dbo.lk_Session s
On (s.SessionID = c.sessionID)
Inner Join dbo.lk_Course co
On (co.CourseID = c.CourseID )
Inner Join dbo.vw_Location l
On (l.locationid = c.locationid)
Inner Join lk_District d
On (d.districtID = c.districtId)
Inner Join lk_Province p
On (p.provik = d.provik)
Inner Join lk_Shift sh
On (c.shiftid = sh.shiftid)
where
c.DistrictID = case when @Districtid is null then c.DistrictID else @Districtid end
and c.LocationID = case when @locationid is null then c.LocationID else @locationid end
and s.SessionID = case when @sessionid is null then s.SessionID else @sessionid end
and c.CourseID = case when @levelid is null then c.CourseID else @levelid end
and c.ShiftID = case when @shiftid is null then c.ShiftID else @shiftid end
and c.StartDate >= case when @startdate is null then c.StartDate else @startdate end
and c.EndDate <= case when @enddate is null then c.EndDate else @enddate end
and convert(time,c.StartTime) >= case when @starttime is null then convert(time,c.StartTime) else convert(time,@starttime) end
and convert(time,c.endtime) <= case when @endtime is null then convert(time,c.endtime) else convert(time,@endtime) end
and c.Monday = case when @day1 = 'N' then c.monday else @day1 end
and c.Tuesday = case when @day2 = 'N' then c.Tuesday else @day2 end
and c.Wednesday = case when @day3 = 'N' then c.Wednesday else @day3 end
and c.Thursday = case when @day4 = 'N' then c.Thursday else @day4 end
and c.Friday = case when @day5 = 'N' then c.Friday else @day5 end
and c.Saturday = case when @day6 = 'N'then c.Saturday else @day6 end
and c.Sunday = case when @day7 = 'N' then c.Sunday else @day7 end
and c.RowStatus = 'A'
ORDER BY co.fCourseName, s.SessionID ,c.ClassName
但是 Sp 的执行时间太长了。这是在 sql 服务器中实现 "All IF null" 逻辑的正确方法吗?还有其他方法可以做到吗?
这是我的做法:
( @Districtid is null OR c.DistrictID = @Districtid )
AND
( @Locationid is null OR c.LocationID = @Locationid )
AND
...
但是,当您拥有非常多的此类过滤器,并且已经足够接近我要试验的临界点时,您最好创建一个动态 SQL 查询。
当你有很多过滤器的查询时,我知道 2 个选项:
使用 OR(如上建议),这会导致查询优化器扫描 table。
请参阅此 post 了解更多信息:How to Optimize the Use of the "OR" Clause When Used with Parameters (SQL Server 2008)
使用动态 SQL - 这会导致查询优化器根据每个参数的每个变化计算执行计划
一个好的选择是使用动态 sql 和 Bind Variables,
这样优化器将缓存查询和执行计划。
declare @sql varchar(500)
DECLARE @ParmDefinition nvarchar(500);
SET @sql='select * from a where 1=1 '
if @Locationid is null
set @sql=@sql +' and @LocationId is null'
else
set @sql=@sql +' and LocationID= @LocationId'
EXECUTE sp_executesql @sql, N'@LocationId int',
@LocationID ;
我们需要在网页中实现搜索功能。所以我们创建了一个存储过程来检索记录。 逻辑是,当 i select 输入参数 Sp returns 参数的过滤记录时,它会检索所有可用记录。
例如:如果我给,
EXEC [WB_GetClassesByLocation_new2] null,null,null,'null',null,NULL,'N','N','N','N','N','N','N',NULL,null,null,null,null,null
(N 是天数字段的默认值) SP 将 return 所有可用的记录。 如果我给,
EXEC [WB_GetClassesByLocation_new2] 1000,null,null,'null',null,NULL,'N','N','N','N','N','N','N',NULL,null,null,null,null,null
。 SP 将 return 区 1000 的记录。我已经实现了以下逻辑
Select distinct c.classID, co.fCourseName as CourseName, StreetAddress + ', ' + l.City as LocationAddress, s.SessionName, sh.fShift as shift, StartTime, EndTime, c.classname, s.SessionID,
c.StartDate,c.enddate
From dbo.vw_Class c
Inner Join dbo.lk_Session s
On (s.SessionID = c.sessionID)
Inner Join dbo.lk_Course co
On (co.CourseID = c.CourseID )
Inner Join dbo.vw_Location l
On (l.locationid = c.locationid)
Inner Join lk_District d
On (d.districtID = c.districtId)
Inner Join lk_Province p
On (p.provik = d.provik)
Inner Join lk_Shift sh
On (c.shiftid = sh.shiftid)
where
c.DistrictID = case when @Districtid is null then c.DistrictID else @Districtid end
and c.LocationID = case when @locationid is null then c.LocationID else @locationid end
and s.SessionID = case when @sessionid is null then s.SessionID else @sessionid end
and c.CourseID = case when @levelid is null then c.CourseID else @levelid end
and c.ShiftID = case when @shiftid is null then c.ShiftID else @shiftid end
and c.StartDate >= case when @startdate is null then c.StartDate else @startdate end
and c.EndDate <= case when @enddate is null then c.EndDate else @enddate end
and convert(time,c.StartTime) >= case when @starttime is null then convert(time,c.StartTime) else convert(time,@starttime) end
and convert(time,c.endtime) <= case when @endtime is null then convert(time,c.endtime) else convert(time,@endtime) end
and c.Monday = case when @day1 = 'N' then c.monday else @day1 end
and c.Tuesday = case when @day2 = 'N' then c.Tuesday else @day2 end
and c.Wednesday = case when @day3 = 'N' then c.Wednesday else @day3 end
and c.Thursday = case when @day4 = 'N' then c.Thursday else @day4 end
and c.Friday = case when @day5 = 'N' then c.Friday else @day5 end
and c.Saturday = case when @day6 = 'N'then c.Saturday else @day6 end
and c.Sunday = case when @day7 = 'N' then c.Sunday else @day7 end
and c.RowStatus = 'A'
ORDER BY co.fCourseName, s.SessionID ,c.ClassName
但是 Sp 的执行时间太长了。这是在 sql 服务器中实现 "All IF null" 逻辑的正确方法吗?还有其他方法可以做到吗?
这是我的做法:
( @Districtid is null OR c.DistrictID = @Districtid )
AND
( @Locationid is null OR c.LocationID = @Locationid )
AND
...
但是,当您拥有非常多的此类过滤器,并且已经足够接近我要试验的临界点时,您最好创建一个动态 SQL 查询。
当你有很多过滤器的查询时,我知道 2 个选项:
使用 OR(如上建议),这会导致查询优化器扫描 table。 请参阅此 post 了解更多信息:How to Optimize the Use of the "OR" Clause When Used with Parameters (SQL Server 2008)
使用动态 SQL - 这会导致查询优化器根据每个参数的每个变化计算执行计划 一个好的选择是使用动态 sql 和 Bind Variables, 这样优化器将缓存查询和执行计划。
declare @sql varchar(500) DECLARE @ParmDefinition nvarchar(500); SET @sql='select * from a where 1=1 ' if @Locationid is null set @sql=@sql +' and @LocationId is null' else set @sql=@sql +' and LocationID= @LocationId' EXECUTE sp_executesql @sql, N'@LocationId int', @LocationID ;