2010-07-15 83 views
0

很抱歉的長期職位,但大部分是代碼拼寫出我的方案:動態SQL查詢(可變項,每列變量項)

我試圖執行動態查詢(希望通過存儲的過程)來基於可變數量的輸入檢索結果。

如果我有一個表:

(dbo).(People) 
ID Name Age 
1 Joe 28 
2 Bob 32 
3 Alan 26 
4 Joe 27 

我想允許用戶通過任何一個三列的搜索,沒有問題:

DECLARE @ID int, @Name nvarchar(25), @Age int 
SET @ID = 1 
SET @Name = 'Joe' 
SET @Age = null 

SELECT * 
FROM dbo.People 
WHERE 
(ID = @ID or @ID is null) AND 
(Name like @Name or @Name is null) AND 
(Age = @Age or @Age is null) 

我找回我想要的結果。現在

,如果我想搜索在列多個字段,我能做到這一點沒有問題:

DECLARE @text nvarchar(100) 
SET @text = '1, 3' 

DECLARE @ids AS TABLE (n int NOT NULL PRIMARY KEY) 

--//parse the string into a table 
DECLARE @TempString nvarchar(300), @Pos int 
SET @text = LTRIM(RTRIM(@text))+ ',' 
SET @Pos = CHARINDEX(',', @text, 1) 
IF REPLACE(@text, ',', '') <> '' 
BEGIN 
    WHILE @Pos > 0 
    BEGIN 
     SET @TempString = LTRIM(RTRIM(LEFT(@text, @Pos - 1))) 
     IF @TempString <> '' --just: IF @TempString != '' 
     BEGIN 
      INSERT INTO @ids VALUES (@TempString) 
     END 
     SET @text = RIGHT(@text, LEN(@text) - @Pos) 
     SET @Pos = CHARINDEX(',', @text, 1) 
    END 
END 


SELECT * 
FROM dbo.People 
WHERE 
ID IN (SELECT n FROM @ids) 

現在,我的問題是,我似乎無法弄清楚如何將二者結合起來因爲我不能忍受:

WHERE 
(Name like @Name or @Name is null) AND 
(Id IN (SELECT n FROM @ids) or @ids is null) 

因爲@ids永遠不會爲空(因爲它是一個表)

任何幫助將不勝感激!

在此先感謝...讓我知道,如果我可以澄清什麼

回答

0

嘗試:

(Id IN (SELECT n FROM @ids) OR NOT EXISTS (SELECT * FROM @ids)) 
+0

IIRC,而不是[sargable](http://en.wikipedia.org/wiki/Sargable) – 2010-07-15 20:53:09

+0

感謝您的幫助,這是我需要的修復。但是目前我的桌子非常小,而且時間會越來越長,而且很快,所以我想知道這會對性能產生怎樣的負面影響......? – Brett 2010-07-16 03:09:32

+1

@佈雷特 - 我與OMG小馬在整體方法上。這只是與您的方法保持一致的最簡單和最簡單的答案。我決定不提出重構,但通常這種「統一」搜索的執行計劃並不好,而且最好是「手動」展開條件,以便爲每個選項獲得最佳執行計劃。當存在複雜的組合時,動態地生成代碼以便正確地實現所需的代碼最終是最有效的。由於列表而不是單個參數,這對您的案例而言更具挑戰性。 – 2010-07-16 03:23:54

0

你可以試試:

NOT EXISTS (SELECT 1 FROM @ids) 
OR EXISTS (SELECT 1 FROM @ids where n = Id) 

但這些最好是小表 - 此查詢可能不會有很好的發揮你的表上的任何索引。

+0

你介意看看我的問題在這裏> http://stackoverflow.com/questions/4832511/oracle-database-connection-with-vb-net-using-oraoledb-oracle – StealthRT 2011-01-28 21:16:53

1

你可以使用IF語句:

IF LEN(@ids) > 0 
BEGIN 

    SELECT * 
    FROM dbo.People 
    WHERE ID IN (SELECT n FROM @ids) 

END 
ELSE 
BEGIN 

    SELECT * 
    FROM dbo.People 

END 

否則,consider making the query real dynamic SQL (minding pitfalls of course)

+0

如果所有三個我的變量,ID,名稱和年齡都可以有一個列表(可能)。這意味着我必須有9個不同的條件... – Brett 2010-07-16 00:06:31

+2

@Brett:超出一種條件的任何事情都會導致我使用動態SQL。你可以在一個單一的查詢中完成,但它是不可測的(不能理想地執行 - 請參閱我對Cade Roux的評論中的鏈接)。 – 2010-07-16 02:27:13

+0

感謝您的幫助,我計劃在明天閱讀更多的文檔,我今天沒有完成它....再次感謝您的幫助! – Brett 2010-07-16 03:10:25

0

速戰速決:

(`%,' + Id + ',%' like ',' + @ids + ',' or @ids is null) 
and (`%,' + Name + ',%' like ',' + @names + ',' or @names is null) 

因此,如果用戶通過@ids = 1,2,第一行給出:

`%,1,%' like ',1,2,' 

它過濾掉一個好主意逗號前後的空格。 :)