2014-01-29 46 views
2

我傳遞的ID列表作爲一個varchar(500),並基於這樣的ID記錄required.My SQL代碼如何獲得基於ids列表作爲varchar傳遞的結果?

declare @Ids varchar(500) = '12964,12965,12966' 

select * 
from tblBooks 
where BookID in (@Ids) 

其中的BookID是IDS的VARCHAR(50)。數可以100.Converting @ IDS轉換成int給出以下錯誤VARCHAR值 「12964,12965,12966」轉換爲數據類型爲int時

轉換失敗

如何找到結果作爲@Id不是在轉換到詮釋。

+0

如果你的'id'是一個整數,你爲什麼嘗試通過他們作爲'varchar'? –

+0

我正在通過c#應用程序。 – Mickel

+2

http://www.sommarskog.se/arrays-in-sql-2008.html –

回答

7

使用表變量:

DECLARE @Ids TABLE (ID INT); 
INSERT @Ids VALUES (12964),(12965),(12966); 

SELECT * 
FROM tblBooks 
WHERE BookID in (SELECT ID FROM @Ids); 

如果您需要將此傳遞給一個過程,那麼你可以使用一個表值參數:

CREATE TYPE dbo.ListOfInt AS TABLE (ID INT); 
GO 
CREATE PROCEDURE dbo.GetBooks @IDs dbo.ListOfInt READONLY 
AS 
BEGIN 
    SELECT * 
    FROM tblBooks 
    WHERE BookID in (SELECT ID FROM @Ids); 
END 
GO 

DECLARE @IDs dbo.ListofInt; 
INSERT @Ids VALUES (12964),(12965),(12966); 
EXECUTE dbo.GetBooks @Ids; 

或來自c#

var table = new DataTable(); 
table.Columns.Add("ID", typeof(int)); 

// ADD YOUR LIST TO THE TABLE 

using (var connection = new SqlConnection("Connection String")) 
using (var command = new SqlCommand("dbo.GetBooks", connection)) 
{ 
    command.CommandType = CommandType.StoredProcedure; 
    var param = new SqlParameter("@Ids", SqlDbType.Structured); 
    param.TypeName = "dbo.ListofInt"; 
    param.Value = table; 
    command.Parameters.Add(table); 
    connection.Open(); 

    using (var reader = command.ExecuteReader()) 
    { 
     while (reader.Read()) 
     { 
      // do something 
     } 
    } 
} 

一旦TYPE就位,您甚至不需要使用存儲過程。您只需撥打一個普通查詢:

using (var connection = new SqlConnection("Connection String")) 
using (var command = new SqlCommand("SELECT * FROM tblBooks WHERE BookID IN (SELECT ID FROM @IDs)", connection)) 
{ 
    var param = new SqlParameter("@Ids", SqlDbType.Structured); 
    param.TypeName = "dbo.ListofInt"; 
    param.Value = table; 
    command.Parameters.Add(table); 
    connection.Open(); 

    // ETC 
} 

使用String.Split()做在C#中分離並通過列表來SQL將比確實在SQL分裂

+0

這是首選的方法。儘管如此,你還沒有展示過如何從C#應用程序調用它。這將是OP的下一個問題。 – Yuck

+1

@Yuck是的,我剛剛看到,當你評論時已經在編輯編輯。 – GarethD

2

您可以編寫查詢,因爲這:

declare @Ids varchar(500) = '12964,12965,12966' 

select * 
from tblBooks 
where ','+cast(BookID as varchar(500))+',' like '%,'[email protected]+',%'; 

但你不想這樣做,因爲業績不好 - 查詢不能使用索引。

其他三個選項。使用動態SQL並將列表直接插入到查詢中。或者使用split函數來分割字符串。或者用表變量:

declare @ids table (id int); 
insert into @ids(id) 
    select 12964 union all select 12965 union all select 12966; 

select b.* 
from tblBooks b 
where b.BookId in (select id from @ids); 
2

這是行不通的任何方法更有效。 SQL Server不會隱式地爲您分割字符串,並且SQL Server中也沒有內置的字符串分割函數。

如果您是通過C#開車,您可以使用Table值參數。您也可以通過Dapper-Dot-Net傳遞您的查詢,這將自動參數化「In」查詢。

如果你真的必須在T-SQL中做到這一點,你也可以使用字符串拆分邏輯,這裏是一個比較簡潔的邏輯。

SELECT i.value('./text()[1]', 'int') [id] into #ids 
FROM(values(CONVERT(xml,'<r>' + REPLACE(@Ids+left(@@dbts,0),',','</r><r>') + '</r>'))) a(_) 
CROSS APPLY _.nodes('./r') x(i) 
select * 
from tblBooks a 
join #ids i on i.id = a.bookId 
0

創建此功能:

CREATE FUNCTION [dbo].[SplitDelimiterString] (@StringWithDelimiter VARCHAR(8000), @Delimiter VARCHAR(8)) 

RETURNS @ItemTable TABLE (Item VARCHAR(8000)) 

AS 
BEGIN 
    DECLARE @StartingPosition INT; 
    DECLARE @ItemInString VARCHAR(8000); 

    SELECT @StartingPosition = 1; 
    --Return if string is null or empty 
    IF LEN(@StringWithDelimiter) = 0 OR @StringWithDelimiter IS NULL RETURN; 

    WHILE @StartingPosition > 0 
    BEGIN 
     --Get starting index of delimiter .. If string 
     --doesn't contain any delimiter than it will returl 0 
     SET @StartingPosition = CHARINDEX(@Delimiter,@StringWithDelimiter); 

     --Get item from string   
     IF @StartingPosition > 0     
      SET @ItemInString = SUBSTRING(@StringWithDelimiter,0,@StartingPosition) 
     ELSE 
      SET @ItemInString = @StringWithDelimiter; 
     --If item isn't empty than add to return table  
     IF(LEN(@ItemInString) > 0) 
      INSERT INTO @ItemTable(Item) VALUES (@ItemInString);    

     --Remove inserted item from string 
     SET @StringWithDelimiter = SUBSTRING(@StringWithDelimiter,@StartingPosition + 
        LEN(@Delimiter),LEN(@StringWithDelimiter) - @StartingPosition) 

     --Break loop if string is empty 
     IF LEN(@StringWithDelimiter) = 0 BREAK; 
    END 

    RETURN 
END 

然後調用它像這樣:

declare @Ids varchar(500) = '12964,12965,12966' 

select * 
from tblBooks 
where BookID in (SELECT * FROM dbo.SplitDelimiterString(@ids,',')) 
+0

有趣的解決方案。可能不是世界上最有效率的東西,但可以完成工作。 – RubberDuck

相關問題