NOT IN 用于解析 CSV

Die*_*ira 1 sql-server t-sql functions

我正在尝试传递要在NOT IN操作中使用的项目数组:

ALTER FUNCTION [dbo].[fnTEST] (@CODES VARCHAR)
RETURNS TABLE 
AS
RETURN 
(
    SELECT
        T1.CODE AS 'CODE',
    (SELECT COUNT(*)
        FROM TABLE1 AS T2 WITH (NOLOCK)
        WHERE T2.CODE NOT IN (@CODES)
    ) AS 'COUNT'
    FROM TABLE1 T1 WITH (NOLOCK)
)
Run Code Online (Sandbox Code Playgroud)

然后我这样称呼它:

SELECT * FROM fnTEST ('500,250,202,900,204,200,300,400,600,800')
Run Code Online (Sandbox Code Playgroud)

那行不通。如果我尝试在没有引号的情况下调用它,则会收到参数过多的错误(这是预期的)。

有解决方案吗?

Aar*_*and 5

在 SQL Server 2008 中,执行此操作的最佳方法是首先不传入 CSV 列表。这组以逗号分隔的值从何而来?

首先,创建一个表类型:

CREATE TYPE dbo.myFoo AS TABLE(id INT PRIMARY KEY);
GO
Run Code Online (Sandbox Code Playgroud)

现在,创建一个将其作为 TVP 的函数:

CREATE FUNCTION dbo.fnTest
(
  @codes dbo.myFoo READONLY
)
RETURNS TABLE
AS
RETURN 
(
    SELECT
        T1.CODE AS [CODE],
    (SELECT COUNT(*)
        FROM dbo.TABLE1 AS T2 WITH (NOLOCK)
        WHERE NOT EXISTS (SELECT 1 FROM @codes
          WHERE id = T2.CODE)
    ) AS [COUNT]
    FROM dbo.TABLE1 T1 WITH (NOLOCK)
);
Run Code Online (Sandbox Code Playgroud)

要在本地测试它...

DECLARE @x dbo.myFoo;
INSERT @x(id) VALUES(500),(250),(202);...
SELECT * FROM dbo.fnTest(@x);
Run Code Online (Sandbox Code Playgroud)

...但最终您将从 C# 代码或其他任何地方作为 DataTable 或其他基于集合的结构传递该组值。

对于 SQL Server 2005

您不能使用 TVP。所以下一个最好的选择是拆分功能,例如

CREATE FUNCTION dbo.SplitInts
(
    @List       VARCHAR(MAX),
    @Delimiter  VARCHAR(32)
)
RETURNS TABLE
AS
    RETURN 
    (
      SELECT Item = CONVERT(INT, Item) 
        FROM (SELECT Number, Item = LTRIM(RTRIM(SUBSTRING(@List, Number, 
          CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number)))
        FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
          FROM sys.all_objects) AS n(Number)
        WHERE Number <= CONVERT(INT, LEN(@List))
        AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
      ) AS y
    );
Run Code Online (Sandbox Code Playgroud)

那么你的功能可以是:

CREATE FUNCTION dbo.fnTest
(
  @codes VARCHAR(MAX)
)
RETURNS TABLE
AS
RETURN 
(
    SELECT
        T1.CODE AS [CODE],
    (SELECT COUNT(*)
        FROM dbo.TABLE1 AS T2 WITH (NOLOCK)
        WHERE NOT EXISTS (SELECT 1 FROM dbo.SplintInts(@codes, ',')
          WHERE Item = T2.CODE)
    ) AS [COUNT]
    FROM dbo.TABLE1 T1 WITH (NOLOCK)
);
Run Code Online (Sandbox Code Playgroud)

如果您可以在 CLR 中执行此操作,它的性能可能会好一些。请参阅以下博客系列 - 他们处理分割字符串,但在大多数情况下,观察结果也适用于分割整数字符串。

http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-follow-up http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql