2013-10-02 74 views
0

我有一個可以通過6個下拉框過濾的gridview,所以在編寫sql時最簡單的事情是使用'或'語句,如果下拉列表有選擇或空等我應該用什麼來代替SQL「OR」語句

但是我已閱讀這裏和其他網站使用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)) 

對此有何意見將是巨大的

更新 我覺得我應該澄清一些關於我的代碼,當我說空,這是我分配到「所有」選擇下拉列表中的值,因此,例如IMN大多數情況下,我做這樣的事情來獲取需要傳遞給DB

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

所以價值如果用戶選擇了所有Db接收者'空'w然後我可以使用'if @blah IS NOT NULL'等。我意識到這可能不是最好的方法來做到這一點

+3

爲什麼SQL還是一個​​壞主意? – Liam

+0

您可能想閱讀Erland Sommarskog的[T-SQL中的動態搜索條件](http://www.sommarskog。se/dyn-search.html) –

回答

1

看來你正在執行這個存儲過程,然後在數據庫驗證用戶輸入水平。如果下拉列表值爲null,則不應該調用數據庫存儲過程,您可以在客戶端(或服務器端)處理此操作。

客戶端(JavaScript)對用戶體驗會更好,如果用戶選擇了所有適當的下拉列表值,則可以調用存儲過程。

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 
+0

哇從未想過以這種方式編寫查詢,但它非常有意義!非常感謝,我會試試看,然後標記你的答案是正確的:) – Nixdorf

0

我不知道我理解你的問題,但如果你正在尋找避免或運營商的重複,可以考慮使用IN(「X」,「Y」,」 z') - 列出可能的值。這會比[something] ='x'或[something] ='y'或[something] ='z'更容易閱讀。

相關問題