2011-11-17 48 views
2

我有一個執行存儲過程的應用程序。有一個組合框「城市」和用戶可以只選擇一個值,我使用該值作爲My C#代碼中的SQL參數。正確使用IN與SQL

簡化的例子:

Select StudentName, Age 
From dbo.Students 
Where City = @city 

@city通過從組合框中的值所替代。

現在需求發生變化,組合框支持多選。所選元素存儲在一個數組中。現在我正在使用以下方法。

  1. 使用String.Join(「','」)並連接數組元素,結果賦給@city。
  2. 更改查詢以使用IN運算符。

    Select StudentName, Age From dbo.Students Where City IN (@city)

假定選定的城市是倫敦和悉尼然後@city成爲倫敦 '' 悉尼。然後在SP中,它將被用作'倫敦','悉尼',這在句法上是正確的。但是這個查詢失敗。

我該做什麼不正確? 什麼是最好的(尼斯)方法來處理這個問題?

+0

您需要使用某種分裂UDF功能的它拆分逗號分隔字符串,返回表變量,那麼你就可以加入或從這張表中選擇 – sll

+1

你是什麼意思'這個查詢失敗'?它不返回結果,或者有錯誤? – Konerak

回答

3

您想要使用IN的方式不正確,它不起作用。

選項:

  1. 發送CSV字符串到SP則將其分解,並創建一個臨時的數據集(例如表變量),您會那麼做JOIN
  2. 動態SQL

實施例分解函數:

CREATE FUNCTION [dbo].[Split](
    @String nvarchar (4000), 
    @Delimiter nvarchar (10) 
) 
RETURNS @ValueTable TABLE ([Value] nvarchar(4000), [ElementsCount] int) 
BEGIN 
    DECLARE @nextString nvarchar(4000) 
    DECLARE @pos int 
    DECLARE @nextPos int 
    DECLARE @commaCheck nvarchar(1) 
    DECLARE @elementsCount int 

    SET @elementsCount = 0 

    --Initialize 
    SET @nextString = '' 
    SET @commaCheck = RIGHT(@string, 1) 

    --Check for trailing Comma, if not exists, INSERT 
    SET @string = @string + @delimiter 

    --Get position of first Comma 
    SET @pos = CHARINDEX(@delimiter, @string) 
    SET @nextPos = 1 

    --Loop while there is still a comma in the String of levels 
    WHILE (@pos <> 0) 
    BEGIN 
      SET @nextString = SUBSTRING(@string, 1, @pos - 1) 

      INSERT INTO @ValueTable ([Value]) VALUES (@nextString) 

      SET @string = SUBSTRING(@string, @pos +1, LEN(@string)) 

      SET @nextPos = @pos 
      SET @pos = CHARINDEX(@delimiter, @string) 

      SET @elementsCount = @elementsCount + 1 
    END 

    UPDATE @ValueTable SET [ElementsCount] = @elementsCount 

    RETURN 
END 

然後喲u使用它像這樣:

SELECT 
    StudentName, Age 
FROM 
    dbo.Students 
    JOIN [dbo].[Split](@city, ',') Cities ON City = Cities.Value 
0

考慮使用xml來傳遞列表,如in this article。另外,你提到string.Join()。這意味着你將你的SQL參數作爲字符串傳遞。永遠不要這樣做!這導致SQL注入攻擊,而不是你想要的生產。

1

我不知道是哪一個轉換PARAM綁定到多個PARAMS的是需要爲您的示例工作任何DB - 這甚至會破壞「SQL注入防禦」綁定params提供。

您可以使用動態SQL(即將SQL語句創建爲字符串,而不是使用綁定參數 - 再次:這容易受到SQL注入的攻擊!),或者對組合框中的每個選定值使用一個SQL查詢,然後創建一個結果的聯合或者使用一些XML作爲選定的組合框的列表,並使用IN子查詢(子查詢將XML轉換爲行)...

+0

如果您之前正確地轉義輸入,則動態SQL將成爲您的選擇。 – Konerak

+0

@Konerak它肯定是最簡單的選擇,雖然我更喜歡XML選項,因爲它不易受攻擊,也不需要轉義等。 - 可悲的是我不知道如何在SQL Server中執行此操作(對於Oracle,我有這樣的SQL)。 – Yahia

0

如果您將參數傳遞給SP和底層SQL語句,你應該發送格式良好的字符串,如'倫敦','悉尼'。

如果你正在處理這個問題,就像你說的 - 「假設選擇的城市是倫敦和悉尼,然後@City成爲倫敦',悉尼,然後在SP它將被用作'倫敦','悉尼',這是句法正確,但這個查詢失敗。「,那麼你可以更新你的文章。

0

既然你已經表明你正在使用SQL Server 2008,你可能想看看Table Valued Parameters。這些可以讓你通過一張表,每行都有一行。

以下是ADO.Net documentation的相同之處,其中包括如何將這樣的參數傳遞給存儲過程的示例。

0

您有2個選項。

1. 

where city in(@city1, @city2, @City3...) 

2. I am assuming city is an int, which it should be. 

Declare @t table(city int) 

--loop all chosen cities 

insert @t values(city) 
--loopend 
Select s.StudentName, s.Age  
From dbo.Students s 
join @t t 
Where s.City = t.city 
+0

我不能說確切的城市數量(最大值未知),所以方法1不會工作,但2幫助:) –

1

您可以使用動態SQL這樣的場景像下面這樣:

SomeStoredProcedure(@city) 

sp_executesql 'Select StudentName, Age 
From dbo.Students Where City in (' + @city + ')'