如何根据作为varchar传递的ids列表获得结果?

时间:2014-01-29 14:49:50

标签: c# sql sql-server sql-server-2008

我将ids列表作为varchar(500)传递并基于该ID记录是必需的。我的sql代码是

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

select *
from tblBooks
where BookID in (@Ids)

其中BookID是varchar(50).Ids的数量可以是100.将@Ids转换为int会产生以下错误

  

转换varchar值时转换失败   '12964,12965,12966'到数据类型int

如何找到结果,因为@Id未转换为Int。

5 个答案:

答案 0 :(得分: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中进行拆分的任何方法更有效

答案 1 :(得分:2)

您可以按以下方式编写查询:

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

select *
from tblBooks
where ','+cast(BookID as varchar(500))+',' like '%,'+@Ids+',%';

但是你不想这样做,因为性能不好 - 查询无法使用索引。

其他三个选项。使用动态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 :(得分:2)

这不起作用。 SQL Server不会隐式拆分字符串,并且SQL Server中也没有内置的字符串拆分功能。

如果您通过C#驾驶它,您可以使用表值参数。您也可以通过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

答案 3 :(得分: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,','))

答案 4 :(得分:0)

一种方法是将int转换为varchar。许多其他方式......

选择* 来自tblBooks 其中CAST(BookID为varchar(50))in(@Ids)

相关:Define variable to use with IN operator (T-SQL)