0

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

但是,我在这里和其他网站上读到使用 sql 或语句是一个坏主意,谁能提供我可以使用的任何其他建议,而不是我写每个 ddl 选择是否为空的变体?下面是第一个查询的示例,每个 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 大多数情况下我会做这样的事情来获取值需要传递给数据库

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

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

4

3 回答 3

1

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

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

于 2013-10-02T09:26:02.057 回答
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
于 2013-10-02T09:42:49.213 回答
0

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

于 2013-10-02T09:51:47.643 回答