2012-07-09 35 views
2

當您需要動態WHERE子句時,我可以使用;SQL,如何使用動態條件邏輯?

CREATE PROCEDURE [dbo].[sp_sel_Articles] 
     @articleId   INT    = NULL 
    , @title   NVARCHAR(250) = NULL 
    , @accessLevelId INT    = NULL 
AS 
BEGIN 
    SELECT * 
    FROM table_Articles Art 
    WHERE 
      (Art.ArticleId = @articleId OR @articleId IS NULL) 
      AND (Art.Title LIKE '%' + @title + '%' OR @title IS NULL) 
      AND (Art.AccessLevelId = @accessLevelId OR @accessLevelId IS NULL) 
END 

所以,我能夠調用此方法 - 因爲通過精確的條款ArticleID例 - ONLY

EXEC [sp_sel_Articles] @articleId = 3 

但是,有時我需要通過AccessLevelId調用有時NOT價值。例如,我需要超過給定的accesslevelId或LESS THAN。

當前程序可以ONLY使用

Art.AccessLevelId = @accessLevelId 

也是可能給予條件類型以及值到程序處理EXACT價值?這似乎在這個例子很奇怪,但請和我一起承擔:

CREATE PROCEDURE [dbo].[sp_sel_Articles] 
      @articleId   INT    = NULL 
     , @title   NVARCHAR(250) = NULL 
     , @accessLevelId INT    = NULL 
     , **@accessLevelIdCondition** 
    AS 
    BEGIN 
     SELECT * 
     FROM table_Articles Art 
     WHERE 
       (Art.ArticleId = @articleId OR @articleId IS NULL) 
       AND (Art.Title LIKE '%' + @title + '%' OR @title IS NULL) 
       AND (Art.AccessLevelId **@accessLevelIdCondition** @accessLevelId OR @accessLevelId IS NULL) 
    END 

也許可以使用的功能,我不知道。因爲至少會有20個程序需要這種靈活性,所以我需要儘可能更好,更全面的解決方案,而不是在每個程序中編寫IF ELSE條件。

在此先感謝,

+0

不要調用你的SP sp _.... http://msdn.microsoft.com/en-us/library/dd172115.aspx – podiluska 2012-07-09 13:06:37

回答

2

請閱讀www.sommarskog.se/dynamic_sql。HTML應用

CREATE PROCEDURE [dbo].[sp_sel_Articles] 
       @articleId   INT    = NULL 
      , @title   NVARCHAR(250) = NULL 
      , @accessLevelId INT    = NULL 
      , @accessLevelIdCondition varchar(100) 
     AS 
     BEGIN 
       DECLARE @SQL varchar(8000) 
    SET @SQL=' 
     SELECT * 
     FROM table_Articles Art 
     WHERE 
       (Art.ArticleId = '+cast(@articleId as varchar(100))+' OR '+cast(@articleId as varchar(100))+'IS NULL) 
       AND (Art.Title LIKE ''%'' + @title + ''%'' OR @title IS NULL) 
       AND (Art.AccessLevelId '[email protected]+ cast(@accessLevelId as varchar(100))+' OR '+cast(@accessLevelId as varchar(100))+' IS NULL) ' 
    EXEC(@sql) 
     END 
+0

謝謝。我忘了那個。 :) – Madhivanan 2012-07-09 13:19:15

3

您可能需要使用動態SQL才能傳入運算符。或者你可以傳入兩個值,例如

@MinAccessLevelID INT, 
@MaxAccessLevelID INT 

... 
WHERE (
    (@MinAccessLevelID IS NULL AND @MaxAccessLevelID IS NULL) 
    OR 
    (AccessLevelID >= @MinAccessLevelID AND AccessLevelID <= @MaxAccessLevelID) 
) 

當你想要精確的(例如只有3)時,只需將3傳遞給兩個值。當你想要3以上的任何東西時,將20000000000傳入@Max參數,或者如果你想要低於3的所有值,則爲0.

但是你會發現,隨着這些排列變得越來越複雜, SQL(並且設置爲optimize for ad hoc workloads,這對計劃緩存重用和挫敗參數嗅探會更好)。

1

您可以隨時進行動態查詢,只需做一個查詢字符串

execute ('select count(*) from table') 
在存儲過程中進入PARAMS

所以,你也可以形成了,你可以執行一個查詢字符串。

+0

顯然有人不喜歡動態SQL,否則我不清楚反對票。正如OP所說,他可能對where子句中的每一列都有> =,>,=,<,<=。動態SQL似乎是一個更可行的選擇,因爲這些組合增加... – 2012-07-09 13:29:36

1

之前,你可以使用一個case語句 - 它可以看起來有點滑稽,如果格式不正確,但你可以嘗試這樣的:

SELECT Columns FROM SomeTable 
WHERE 1 = CASE 
       WHEN @SomeOption = '<>' AND SomeValue >= @SomeMinParam AND SomeValue <= SomeMaxParam THEN 1 
       WHEN @SomeOption '=' AND SomeValue = @SomeMinParam THEN 1 
       ELSE 0 
      END  

(雖然亞倫指出 - 在< >你傳遞並沒有真正反映語句中的比較操作 - 在你的情況下將其更改爲有意義的事情:))

CREATE PROCEDURE [dbo].[sp_sel_Articles] 
    @articleId   INT    = NULL, 
    @title   NVARCHAR(250) = NULL, 
    @MinaccessLevelId INT    = NULL, 
    @MaxaccessLevelId  INT   = NULL, 
    @accessType  varchar(5)  = '<>' 
AS 
BEGIN 
SELECT * 
FROM table_Articles Art 
WHERE 
     (Art.ArticleId = @articleId OR @articleId IS NULL) 
     AND (Art.Title LIKE '%' + @title + '%' OR @title IS NULL) 
     AND 1 = CASE 
        WHEN @accessType = '<>' AND (Art.AccessLevelId = @MinaccessLevelId OR @accessLevelId IS NULL) THEN 1 
        WHEN @accessType = '=' AND (Art.AccessLevelId >= @MinaccessLevelId OR Art.AccessLevelId <= @MaxaccessLevelId) THEN 1 
        ELSE 0 
       END 
END 

也許使用@CompareAccessLevelToMin而不是@accessType參數的varchar()。仍然有麻煩,不告訴你什麼設置爲'假'意味着。

+0

我不認爲這會得到您期望的結果,原因有兩個:(1)<>應該產生< and >而不是<= and > =(2)SomeValue不能是>'@ SomeParam'和<'@ SomeParam' at同一時間。 – 2012-07-09 13:19:56

+0

我更新它以添加缺少的最大參數 - 我認爲雖然您可以只使用NULL來指定您希望它只使用最小值,但它使它更容易閱讀,而無需查看定義sproc(然後你可能需要打開它才能看到可能的參數值) - 也許命名參數'@accessLevelMustEqualMin'並使其更清楚一點?我可能會這樣做你的方式亞倫 - 與NULL,說實話:) – Charleh 2012-07-09 13:22:37

+0

我在說你的第一個代碼片段。我的評論是在您添加該程序之前發佈的。 – 2012-07-09 13:24:20