设置具有多个值的变量并使用IN

oJM*_*86o 24 t-sql sql-server

可能重复:
参数化SQL IN子句?

在SQL Server中,我想为此做些什么......

DECLARE @Values varchar(1000)

SET @Values = 'A, B, C'

SELECT
  blah
FROM 
  foo
WHERE
  myField IN (@Values)
Run Code Online (Sandbox Code Playgroud)

这有可能或如何实现这一目标?

Chr*_*cht 39

你需要一个表变量:

declare @values table
(
    Value varchar(1000)
)

insert into @values values ('A')
insert into @values values ('B')
insert into @values values ('C')

select blah
from foo
where myField in (select value from @values)
Run Code Online (Sandbox Code Playgroud)

  • 警示轶事:我最近做了类似这样的事情,以使查询更易于维护......并且在看到执行时间增加近2000%**,从低于800毫秒到超过16,000毫秒后迅速改变了路线.粗略的调查显示每个`in(select ...)`都涉及一个表扫描; 向表变量添加主键改善了这种情况,但还不够.YMMV,当然. (3认同)
  • SQL Server 2016 或更高版本您可以使用字符串拆分函数 DECLARE @Values varchar(1000) = 'A,B,C,D,E' SELECT * FROM WHERE ColumnName IN (SELECT VALUE FROM STRING_SPLIT(@Values,',')) (3认同)
  • 仅供参考,在 SQL Server 2008 及更高版本中,以下语法对于将多个显式值插入表变量也有效:`insert into @values values ('A'),('B'),('C') (2认同)

Aar*_*and 5

理想情况下,您根本不应该在 T-SQL 中拆分字符串

除非进行该更改,否则在 SQL Server 2016 之前的旧版本上创建拆分函数:

CREATE FUNCTION dbo.SplitStrings
(
    @List      nvarchar(max), 
    @Delimiter nvarchar(2)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
  RETURN ( WITH x(x) AS
    (
      SELECT CONVERT(xml, N'<root><i>' 
        + REPLACE(@List, @Delimiter, N'</i><i>') 
        + N'</i></root>')
    )
    SELECT Item = LTRIM(RTRIM(i.i.value(N'.',N'nvarchar(max)')))
      FROM x CROSS APPLY x.nodes(N'//root/i') AS i(i)
  );
GO
Run Code Online (Sandbox Code Playgroud)

现在你可以说:

DECLARE @Values varchar(1000);

SET @Values = 'A, B, C';

SELECT blah
  FROM dbo.foo
  INNER JOIN dbo.SplitStrings(@Values, ',') AS s
    ON s.Item = foo.myField;
Run Code Online (Sandbox Code Playgroud)

在 SQL Server 2016 或更高版本(或 Azure SQL 数据库)上,它更简单、更高效,但是您必须手动申请LTRIM()以消除任何前导空格:

DECLARE @Values varchar(1000) = 'A, B, C';

SELECT blah
  FROM dbo.foo
  INNER JOIN STRING_SPLIT(@Values, ',') AS s
    ON LTRIM(s.value) = foo.myField;
Run Code Online (Sandbox Code Playgroud)