传入一大串Guid

Lar*_*ady 0 sql t-sql sql-server sql-server-2005 query-optimization

我有一个有两个问题的存储过程。

  1. 它有 40 个参数。我知道第一条评论是重新设计我的存储过程,使其没有 40 个参数。然而,这是一个带有大标准部分的搜索表单。因此,用户最多可以指定 40 个不同的搜索条件。然后我们将这些值作为参数传递。现在我有一个 40 个参数的存储过程。将它们作为 XML 参数传递并在内部或表参数中解析它是否会更有效(我们仍在运行 SQL 2k5,但正在考虑升级到 2k12)。

  2. 我的三个参数是由引号和逗号分隔的 Guid 值的长字符串。基本上,用户会看到一个产品线列表,有时有数百个。然后他们单击想要搜索的内容。我们限制了他们可以检查的行数,只是因为字符串太长,但我们传递了一长串由引号和逗号分隔的 Guid。我知道这不是正确的方法。用于传递像这样的 Guid 值的数组或集合的标准 Trans SQl 模式是什么?40 个领域中,我有 3 个独立领域在做这件事。我们希望更有效地做到这一点,并且能够传递超出当前限制的内容。

Aar*_*and 5

SQL Server 2005

在您可以利用表值参数之前,我建议您创建一个专门的表值 UDF 来拆分 GUID 参数。然后,您可以在连接、存在子句、交叉应用等中使用输出。

CREATE FUNCTION dbo.SplitGUIDs
(
   @List       VARCHAR(MAX),
   @Delimiter  VARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
   RETURN 
   (  
      SELECT [GUID] = CONVERT(UNIQUEIDENTIFIER, x) FROM
      ( 
        SELECT x = RTRIM(y.i.value('.[1]', 'nvarchar(4000)'))
        FROM 
        ( 
          SELECT x = CONVERT(XML, '<i>' 
            + REPLACE(@List, @Delimiter, '</i><i>') 
            + '</i>').query('.')
        ) AS a CROSS APPLY x.nodes('i') AS y(i)
      ) AS x WHERE LEN(x) > 0
   );
GO
Run Code Online (Sandbox Code Playgroud)

用法:

DECLARE @GUIDs VARCHAR(MAX);

SET @GUIDs = 'E2072E08-84D3-4EEA-A6ED-F38F1E4E34A6,'
           + 'A6B047BA-647E-4B35-8D95-F4A204B860F6';

SELECT [GUID] FROM dbo.SplitGUIDs(@GUIDs, ',') AS g;
Run Code Online (Sandbox Code Playgroud)

结果:

Item
------------------------------------
E2072E08-84D3-4EEA-A6ED-F38F1E4E34A6
A6B047BA-647E-4B35-8D95-F4A204B860F6
Run Code Online (Sandbox Code Playgroud)

存储过程可能如下所示:

CREATE PROCEDURE dbo.Whatever
  @GUIDs VARCHAR(MAX)
AS 
BEGIN
  SET NOCOUNT ON;

  SELECT t.columns
    FROM dbo.sometable AS t
    INNER JOIN dbo.SplitGUIDs(@GUIDs, ',') AS g
    ON t.key = g.[GUID];
END
GO
Run Code Online (Sandbox Code Playgroud)

(当然,如果字符串中的任何元素包含无效的 GUID,该函数将会失败。在 SQL Server 2012 中,您可以使用该函数,TRY_CONVERT()但之后就不需要这样做了,因为您将使用 TVP,更多内容见下文。)

SQL Server 2008+

稍后,当您从 SQL Server 2005 毕业时(以及对于其他面临此问题但使用 SQL Server 2008+ 的读者),您可以使用表类型更有效地完成此操作:

CREATE TYPE dbo.GUIDs AS TABLE(GUID UNIQUEIDENTIFIER PRIMARY KEY);
Run Code Online (Sandbox Code Playgroud)

然后您的存储过程可以将此类型作为输入而不是大字符串:

CREATE PROCEDURE dbo.Whatever
  @GUIDs dbo.GUIDs READONLY
AS
BEGIN
  SET NOCOUNT ON;

  SELECT t.columns
    FROM dbo.sometable AS t
    INNER JOIN @GUIDs AS g
    ON t.key = g.[GUID];
END
GO
Run Code Online (Sandbox Code Playgroud)

(注意切换到 TVP 是多么容易 - 只需要更改第 2 行和第 9 行。)

然后,您的 Web 应用程序可以将 DataTable 等集合传递给 @GUIDs 参数。没有混乱的字符串分割,没有类型转换,没有对可以传递的不同 GUID 数量的人为限制。