SQL将多个ID作为一个变量传递
我希望将理论上无限数量的ID作为一个变量传递给存储过程,并让它返回所有匹配的记录。当使用list和IN语句时,我得到一个错误,因为SQL将多个ID作为一个变量传递,sql,sql-server,Sql,Sql Server,我希望将理论上无限数量的ID作为一个变量传递给存储过程,并让它返回所有匹配的记录。当使用list和IN语句时,我得到一个错误,因为ProviderIDdatatype是INT,它将我的列表视为字符串 DECLARE @ProviderList varchar(max) SET @ProviderList = '1001,1002' SELECT * FROM tblProviders WHERE ProviderID IN ( @ProviderList ) --Error: Err
ProviderID
datatype是INT,它将我的列表视为字符串
DECLARE @ProviderList varchar(max)
SET @ProviderList = '1001,1002'
SELECT *
FROM tblProviders
WHERE ProviderID IN ( @ProviderList )
--Error: Error converting data type varchar to bigint. when used
像下面这样分离ID是可行的……但由于无法知道一次将搜索多少ID,因此如果有不需要的潜在占位符变量,那就太麻烦了
DECLARE @ProviderOne varchar(max)
SET @ProviderOne = '1001'
DECLARE @ProviderTwo varchar(max)
SET @ProviderTwo = '1002'
SELECT *
FROM tblProviders
WHERE ProviderID IN ( @ProviderOne, @ProviderTwo )
最好的方法可能是使用查询字符串并使用动态SQL。这允许优化器编译查询以获得最佳执行。这种方法是将ID列表直接插入字符串中。当然,如果列表来自用户输入,这可能是一个非常糟糕的主意,因为这种方法引入了SQL注入的风险 另一种方法是拆分字符串。SQL Server(2016+)的最新版本具有
string\u split()
(或者您可以很容易地在web上找到UDF):
最好的方法可能是使用查询字符串并使用动态SQL。这允许优化器编译查询以获得最佳执行。这种方法是将ID列表直接插入字符串中。当然,如果列表来自用户输入,这可能是一个非常糟糕的主意,因为这种方法引入了SQL注入的风险 另一种方法是拆分字符串。SQL Server(2016+)的最新版本具有
string\u split()
(或者您可以很容易地在web上找到UDF):
您可以接受作为csv的输入,然后可以将csv转换为列表并作为参数传递
SELECT *
FROM tblProviders
WHERE ProviderID IN (SELECT * FROM dbo.CSVToLIst(@CSV))
CSV列表功能
CREATE FUNCTION dbo.CSVToList (@CSV varchar(3000))
RETURNS @Result TABLE (Value varchar(30))
AS
BEGIN
DECLARE @List TABLE
(
Value varchar(30)
)
DECLARE
@Value varchar(30),
@Pos int
SET @CSV = LTRIM(RTRIM(@CSV))+ ','
SET @Pos = CHARINDEX(',', @CSV, 1)
IF REPLACE(@CSV, ',', '') <> ''
BEGIN
WHILE @Pos > 0
BEGIN
SET @Value = LTRIM(RTRIM(LEFT(@CSV, @Pos - 1)))
IF @Value <> ''
INSERT INTO @List (Value) VALUES (@Value)
SET @CSV = RIGHT(@CSV, LEN(@CSV) - @Pos)
SET @Pos = CHARINDEX(',', @CSV, 1)
END
END
INSERT @Result
SELECT
Value
FROM
@List
RETURN
END
创建函数dbo.CSVToList(@CSV varchar(3000))
返回@Result表(值varchar(30))
作为
开始
声明@List表
(
varchar值(30)
)
声明
@值varchar(30),
@位置int
设置@CSV=LTRIM(RTRIM(@CSV))+','
设置@Pos=CHARINDEX(“,”,@CSV,1)
如果替换(@CSV,“,”)”
开始
而@Pos>0
开始
设置@Value=LTRIM(RTRIM(左(@CSV,@Pos-1)))
如果@Value''
插入@List(Value)值(@Value)
设置@CSV=RIGHT(@CSV,LEN(@CSV)-@Pos)
设置@Pos=CHARINDEX(“,”,@CSV,1)
结束
结束
插入@Result
挑选
价值
从…起
@名单
返回
结束
您可以接受作为csv的输入,然后可以将csv转换为列表并作为参数传递
SELECT *
FROM tblProviders
WHERE ProviderID IN (SELECT * FROM dbo.CSVToLIst(@CSV))
CSV列表功能
CREATE FUNCTION dbo.CSVToList (@CSV varchar(3000))
RETURNS @Result TABLE (Value varchar(30))
AS
BEGIN
DECLARE @List TABLE
(
Value varchar(30)
)
DECLARE
@Value varchar(30),
@Pos int
SET @CSV = LTRIM(RTRIM(@CSV))+ ','
SET @Pos = CHARINDEX(',', @CSV, 1)
IF REPLACE(@CSV, ',', '') <> ''
BEGIN
WHILE @Pos > 0
BEGIN
SET @Value = LTRIM(RTRIM(LEFT(@CSV, @Pos - 1)))
IF @Value <> ''
INSERT INTO @List (Value) VALUES (@Value)
SET @CSV = RIGHT(@CSV, LEN(@CSV) - @Pos)
SET @Pos = CHARINDEX(',', @CSV, 1)
END
END
INSERT @Result
SELECT
Value
FROM
@List
RETURN
END
创建函数dbo.CSVToList(@CSV varchar(3000))
返回@Result表(值varchar(30))
作为
开始
声明@List表
(
varchar值(30)
)
声明
@值varchar(30),
@位置int
设置@CSV=LTRIM(RTRIM(@CSV))+','
设置@Pos=CHARINDEX(“,”,@CSV,1)
如果替换(@CSV,“,”)”
开始
而@Pos>0
开始
设置@Value=LTRIM(RTRIM(左(@CSV,@Pos-1)))
如果@Value''
插入@List(Value)值(@Value)
设置@CSV=RIGHT(@CSV,LEN(@CSV)-@Pos)
设置@Pos=CHARINDEX(“,”,@CSV,1)
结束
结束
插入@Result
挑选
价值
从…起
@名单
返回
结束
有几种方法可以做到这一点。一种是做一个带分隔符的字符串,然后将其拆分。由于我不确定您使用的是哪个版本的SQL Server,您可以找到Jeff Moden的分隔字符串拆分器的副本
然后,您可以执行以下操作:
SELECT *
FROM MyTable MT
WHERE MT.MyValues IN (SELECT Item FROM dbo.delimitedSplit8k(@DelimString,',');
另一种方法是使用自定义表值类型。在这里,您可以创建表形式的数据类型。例如:
CREATE TYPE IDs AS TABLE (ID int);
GO
DECLARE @ID IDs;
INSERT INTO @ID
VALUES (1),(2),(3)
SELECT *
FROM MyTable MT
WHERE MT.MyValues IN (SELECT ID FROM @ID);
GO
--Clean up
--DROP TYPE IDs;
任何问题,请发表评论。有几种方法可以做到这一点。一种是做一个带分隔符的字符串,然后将其拆分。由于我不确定您使用的是哪个版本的SQL Server,您可以找到Jeff Moden的分隔字符串拆分器的副本 然后,您可以执行以下操作:
SELECT *
FROM MyTable MT
WHERE MT.MyValues IN (SELECT Item FROM dbo.delimitedSplit8k(@DelimString,',');
另一种方法是使用自定义表值类型。在这里,您可以创建表形式的数据类型。例如:
CREATE TYPE IDs AS TABLE (ID int);
GO
DECLARE @ID IDs;
INSERT INTO @ID
VALUES (1),(2),(3)
SELECT *
FROM MyTable MT
WHERE MT.MyValues IN (SELECT ID FROM @ID);
GO
--Clean up
--DROP TYPE IDs;
如有任何问题,请发表评论。如果您使用的是SQL Server 2016或更高版本,或Azure SQL,您可以使用JSON:
DECLARE @ProviderList varchar(max)
SET @ProviderList = '[1001,1002]'
SELECT *
FROM tblProviders
WHERE ProviderID IN ( SELECT CAST(p.[Value] AS INT) FROM OPENJSON(@ProviderList) p )
如果您使用的是SQL Server 2016或更高版本,或Azure SQL,则它是可用的最快、最安全的方法,您只需使用JSON即可:
DECLARE @ProviderList varchar(max)
SET @ProviderList = '[1001,1002]'
SELECT *
FROM tblProviders
WHERE ProviderID IN ( SELECT CAST(p.[Value] AS INT) FROM OPENJSON(@ProviderList) p )
DECLARE @ProviderList varchar(max)
Declare @sqlstring nvarchar(2000)
SET @ProviderList = '100,200,300'
set @sqlstring = 'SELECT * FROM temptable where Num_Key in (' + @ProviderList + ')'
--select @sqlstring
execute sp_executesql @sqlstring
这是可用的最快、最安全的方法您的数据似乎需要整数。您可以在中添加强制转换(选择强制转换(值为int)…您的数据似乎需要整数。您可以在中添加强制转换(选择强制转换(值为int))…我认为string\u split更适合于此项工作,尽管我没有测试bothYep的性能,但string\u也可以。我仍然更喜欢使用json,因为我可以使用ISJSON函数确保在开始在查询中使用数字之前就有一组有效的数字。我认为string\u split更适合于此项工作,尽管我没有st bothYep的性能也可以拆分字符串。我仍然更喜欢使用json,因为我可以使用ISJSON函数来确保我有一组有效的数字,甚至在开始在查询中使用它们之前。SQL Server版本SQL Server版本如果你真的在寻找“理论上无限”的话,这是正确的答案ids.在SQL Server(和大多数数据库)中,一条语句的长度最大。如果有几十个或几百个条目,您可能不会有问题,但如果有几千个条目,您几乎肯定不会有问题,而使用表值参数是唯一的(合理的)向前看。这也不值得。我链接的拆分器最多只能处理8000个字符的分隔字符串。如果您真的在寻找“理论上无限”的ID,这是正确的答案。在SQL Server(和大多数数据库)中,一条语句有一个最大长度。如果你有几十条或几百条语句,你可能没问题,但如果你有几千条语句,你就可以了
DECLARE @ProviderList varchar(max)
Declare @sqlstring nvarchar(2000)
SET @ProviderList = '100,200,300'
set @sqlstring = 'SELECT * FROM temptable where Num_Key in (' + @ProviderList + ')'
--select @sqlstring
execute sp_executesql @sqlstring