我应该使用什么而不是SQL“OR”语句

时间:2013-10-02 09:23:40

标签: c# sql .net

我有一个可以通过6个下拉框过滤的gridview,因此在编写sql时最简单的方法是使用'或'语句,如果下拉列表有选择或null等。

但是我已经阅读了这里和其他使用sql或语句的网站是一个坏主意,任何人都可以提供我可以使用的任何其他建议,而不是我写每个ddl选择是否为null的变体?下面是第一个查询的示例,每个ddl返回一个值

@ruleID int = null, 
@engagementStatusID int = null,
@areaOfWorkID int = null,
@registered bit = null,
@staffGroupID int = null,
@assignmentTypeID int = NULL

AS
SET NOCOUNT ON

IF (@ruleID IS NOT NULL and @engagementStatusID IS NOT NULL and @areaOfWorkID IS NOT NULL and 
        @registered IS NOT NULL and @staffGroupID IS NOT NULL and @assignmentTypeID IS NOT NULL)

BEGIN
    SELECT            r.dbRuleId AS RuleID,r.dbEngagementStatusId AS EngagementStatusID, 
                  r.dbIsAllStaffGroups AS AllStaffGroups,r.dbIsAllAssignments AS AllAssignments, 
                  r.dbIsAllRegistered AS AllRegistered,r.dbIsAllUnregistered AS AllUnregistered, 
                  r.dbSoftDelete AS Softdelete, es.dbName AS EngagementName, 
                  sgc.dbName AS StaffGroupName, aow.dbName AS AreaOfWorkName, 
                  at.dbName AS AssignmentName, at.dbIsRegistered AS Registered,sgc.dbStaffGroupCodeId AS StaffGroupCodeID, 
                  at.dbAssignmentTypeId AS AssignmentID, aow.dbAreaOfWorkId AS AreaOfWorkID
FROM              dbo.tbRule r INNER JOIN
                  dbo.EngagementStatus es ON r.dbEngagementStatusId = es.dbEngagementStatusId INNER JOIN
                  dbo.RuleStaffGroup rsg ON r.dbRuleId = rsg.dbRuleId INNER JOIN
                  dbo.StaffGroupCode sgc ON rsg.dbStaffGroupId = sgc.dbStaffGroupCodeId INNER JOIN
                  dbo.RuleAssignmentCode rac ON r.dbRuleId = rac.dbRuleId INNER JOIN
                  dbo.AssignmentCode ac ON 
                  rac.dbAssignmentCodeId = ac.dbAssignmentCodeId INNER JOIN
                  dbo.AssignmentType at ON ac.dbAssignmentId = at.dbAssignmentTypeId INNER JOIN
                  dbo.AreaOfWork aow ON ac.dbAreaOfWorkId = aow.dbAreaOfWorkId
    WHERE   ((r.dbRuleId = @ruleID) and (r.dbEngagementStatusId = @engagementStatusID) and (aow.dbAreaOfWorkId = @areaOfWorkID) and
                (at.dbIsRegistered = @registered) and (sgc.dbStaffGroupCodeId = @staffGroupID) and (at.dbAssignmentTypeId = @assignmentTypeID))

对此的任何建议都很棒

更新 我觉得我应该澄清一下我的代码,当我说null时,这是我分配给下拉列表的“全部”选择​​的值,所以例如imn大多数情况下我做这样的事情来获得值需要传递给DB

int? Type = (this.ddlType.SelectedValue.ToString() == "All") ? (int?)null : Convert.ToInt32(this.ddlType.SelectedValue.ToString());

所以如果用户选择了所有Db接收'null',然后我可以在'if @blah IS NOT NULL'上使用等等。我意识到这可能不是最好的方法来做到这一点

3 个答案:

答案 0 :(得分:1)

您似乎正在执行此存储过程,然后在数据库级别验证用户输入。如果下拉列表值为null,则不应调用数据库存储过程,您可以在客户端(或服务器端)处理此问题。

客户端(JavaScript)对于用户体验会更好,如果用户选择了所有适当的下拉列表值,则可以调用存储过程。

答案 1 :(得分:1)

当您执行以下操作时会出现问题:

WHERE   (r.dbRuleId = @ruleID or @ruleID is null)
and     (r.dbEngagementStatusId = @engagementStatusID
                 or @engagementStatusID is null)
-- ... lots more

迅速降级为非常糟糕的查询计划。那么,诀窍是让TSQL与您确切的查询参数集匹配。

难以维护修复此问题的方法是为每种可能性编写DML,并分支到正确的方式 - 但这真的丑陋,并且混淆了很多工具。

最简单这样做的方法是在调用者处适当地构建TSQL - 但是如果你的系统要求你使用存储过程(这些天的好处,最好是可疑的 - 顺便说一下,那么最简单的选择就是动态SQL。显然,你需要在这里小心 - 你仍然不想连接输入(出于注入和查询计划的原因),但是 - 你可以这样做:

declare @sql nvarchar(4000) = N'...start of query...';

if(@ruleID is not null)
    set @sql = @sql + N' and r.dbRuleId = @ruleID';
if(@engagementStatusID is not null)
    set @sql = @sql + N' and r.dbEngagementStatusId = @engagementStatusID';

然后,您需要使用sp_executesql执行该操作,并声明参数:

exec 'sp_executesql', @sql,
      N'@ruleID int, @engagementStatusID int',
      @ruleID, @engagementStatusID

答案 2 :(得分:0)

我不确定我理解你的问题,但是如果你想避免重复OR运算符,可以考虑使用IN('x','y','z') - 列出可能的值。这比[something] ='x'或[某事] ='y'或[某事] ='z'更容易阅读。

相关问题