2010-09-15 85 views
2

有沒有一種方法可以在sql語句中實時獲取構建WHERE子句?SQL:建立where子句

此代碼在存儲過程中。我有一個參數x量和每個參數的默認值是NULL

SELECT * 
FROM MyTable m 
WHERE 
    IF(NOT(@Param1 IS NULL)) 
    m.Col1 = @Param1 
    END IF 
AND 
    IF(NOT(@Param2 IS NULL)) 
    m.Col2 = @Param2 
    END IF 

[編輯:]我運行SQL Server 2005 [編輯:]參數的數量是固定的,但可以有一個NULL值。如果參數具有NULL值,則不應將其包含在WHERE子句中。每個參數也與特定列相關。

+0

這取決於您使用的數據庫。例如,在SQL Server中,可以將SQL查詢構造爲字符串並運行它(我會建議不要這樣做)。 – 2010-09-15 16:48:07

回答

3

是不是等同於以下內容,沒有任何動態行爲?

SELECT * 
FROM MyTable m 
WHERE 
    (@Param1 IS NULL OR m.Col1 = @Param1) 
AND 
    (@Param2 IS NULL OR m.Col2 = @Param2) 

或者是否有可能失去這些列本身?

+2

從邏輯上看,這是一個動態構建的查詢,但[不可sargable](http://en.wikipedia.org/wiki/Sargable) – 2010-09-15 17:20:47

+3

請參閱這裏爲什麼這對性能不利?http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/do-you-use-column-param-or-param-is-null – SQLMenace 2010-09-15 17:22:37

+0

這會對性能更好還是導致執行計劃相同? m.Col1 = coalesce(@Param1,m.Col1) – Bill 2010-09-15 18:11:58

2

假設的SQL Server 2005 +語法,因爲沒有指定數據庫...強烈推薦解決查詢之前閱讀:The curse and blessings of dynamic SQL

DECLARE @SQL NVARCHAR(4000) 
    SET @SQL = N'SELECT m.* 
        FROM MyTable m 
        WHERE 1 = 1 ' 

    SET @SQL = @SQL + CASE 
         WHEN @param1 IS NOT NULL THEN ' AND m.col1 = @param1 ' 
         ELSE ' ' 
         END 

    SET @SQL = @SQL + CASE 
         WHEN @param2 IS NOT NULL THEN ' AND m.col2 = @param2 ' 
         ELSE ' ' 
         END 

BEGIN 

    EXEC sp_executesql @SQL, 
        N'@param1 [replace w/ data type], @param2 [replace w/ data type]' 
        @param1, @param2 

END 
+0

這也應該在SQL 2000上運行得很好,我沒有看到你的代碼中使用2005+語法的任何東西..但是SET @SQL =需要SET @SQL = @SQL +或2008+語法SET @SQL + = ..... – SQLMenace 2010-09-15 17:28:09

+1

sp_executesql在版本7中已經存在 – SQLMenace 2010-09-15 17:31:24

0

你可能被迫使用動態SQL無論您使用的是存儲過程與否。在實現這個存儲過程之前,請考慮幾件事情。

  1. 參數本身是動態的嗎?你會使用2個參數嗎?如果是這種情況,則需要創建大量「佔位符」存儲的proc參數,這些參數可能不會在每次調用時使用。如果你定義了10個佔位符參數但是需要11個參數呢?這不乾淨。也許你可以使用某種數組參數....

  2. 如果參數是動態的,你將被迫在你的proc中使用動態SQL。這會打開你注射攻擊。您將不得不手動轉儲存儲過程中的所有輸入。在proc中使用dymamaic sql會失去使用procs的主要原因之一。

如果參數是真正動態的,我實際上可能更喜歡從代碼生成sql而不是存儲過程。爲什麼?如果從代碼生成,則可以使用ADO庫來轉義輸入。

只要確保你做這樣的事情....

SQL = 「從表,其中可樂= @可樂選擇*」; // dyanmically生成 SQlCommand.Parameters.add(「@ colA」,valueA);

而且不....

SQL = 「從表中選擇*,其中可樂=」 +值a; // dyanmically產生錯誤的方式

0

還有第三件事要考慮。如果參數的數據類型是動態的呢?存儲過程開始崩潰,因爲它們是一個定義的接口。如果你的操作不符合界面,試圖將它們擠壓到預先設置的界面將會變得很難看。

如果您正在製作某種開放式圖形查詢工具,則會彈出這種情況。大多數情況下,你的數據訪問將符合一個接口,但是當它不存在時......存儲過程可能不是要走的路。