如何向存储过程提交项目列表以限制结果?

cod*_*der 8 sql-server query stored-procedures

可能的重复:将
数组参数传递给存储过程

假设您想通过唯一标识符列表过滤结果,以便您的 SQL 语句读取:

WHERE CustomerID in (@CustomerIDs)
Run Code Online (Sandbox Code Playgroud)

这可能吗?

编辑:

为了澄清和回答尼克的问题,我想将值列表从 C# 传递到 SQL Server,并且能够执行类似于我上面发布的 SQL 的选择。由于存在大量数据,因此这比获取比需要的更多的数据并不得不搜索它更可取。

mrd*_*nny 8

如果您使用 SQL 2008 或更高版本,您可以使用表值参数,它允许您从 .NET 端传入基本上是数组的内容,然后使用表变量作为尼克所说的 in 子句。

如果您不使用 SQL 2008 或更高版本,那么您需要将值作为 XML 文档传递,然后使用 xquery 或 OPENXML 解析 XML 文档并将值放入临时表(或表变量,具体取决于如何您期望的许多值)。然后将临时表用作 WHERE 子句中 IN 的一部分。

  • 我更喜欢使用逗号分隔的 var 并使用 http://www.sommarskog.se/arrays-in-sql-2005.html 他的方法构建一个临时表;) (2认同)
  • CSV 可以工作,直到您需要在字符串中放入逗号。:) (2认同)

Mar*_*ith 5

SQL2008 之前的替代方法是使用 CSV 拆分器。杰夫·莫登 (Jeff Moden) 对此进行了各种方法的详尽测试

你的例子会变成:

DECLARE @CustomerIdList VARCHAR(8000)
SET @CustomerIdList = 
                    'F2D13066-111F-4B85-B85B-2C89F4876D06
                    ,DEF52A31-3272-4296-9C2B-3B3D7DB45BBA
                    ,981BCCF6-D1D2-4F19-B5CF-B4CC4FC6B417'

SELECT
    x, y, z
FROM
    dbo.Customer c
INNER JOIN
    dbo.DelimitedSplit8K(@CustomerIdList, ',') IdList
ON  IdList.Item = c.CustomerId
Run Code Online (Sandbox Code Playgroud)

DelimitedSplit8K 函数:

CREATE FUNCTION [dbo].[DelimitedSplit8K]
        (@pString VARCHAR(8000), @pDelimiter CHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
  WITH E1(N) AS (
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
                ),                          
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), 
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), 
 cteTally(N) AS (
                 SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
                ),
cteStart(N1) AS (
                 SELECT 1 UNION ALL
                 SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
                ),
cteLen(N1,L1) AS(
                 SELECT s.N1,
                        ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
                   FROM cteStart s
                )
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
        Item       = SUBSTRING(@pString, l.N1, l.L1)
   FROM cteLen l
;
Run Code Online (Sandbox Code Playgroud)


Nic*_*mas 2

是的,尽管你可以将其写为:

...
WHERE CustomerID IN (
   SELECT CustomerID
   FROM @table_variable
)
Run Code Online (Sandbox Code Playgroud)

显然,您可以将 中的内容替换IN (...)为返回适当类型的单个列的任何查询。这假设您要过滤的数据已经位于数据库中的某个位置。至于如何将此数据传递到您的存储过程(根据您的更新),我遵循此处的其他答案。

此方法适用于所有版本的 SQL Server。(仅当您使用表变量时才需要 SQL Server 2005+。)