我将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。
答案 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)