0

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

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

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

4

2 回答 2

4

SQL 服务器 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(Item) > 0
   );
GO

用法:

DECLARE @GUIDs VARCHAR(MAX);

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

SELECT [GUID] FROM dbo.SplitGUIDs(@GUIDs, ',') AS g;

结果:

Item
------------------------------------
E2072E08-84D3-4EEA-A6ED-F38F1E4E34A6
A6B047BA-647E-4B35-8D95-F4A204B860F6

存储过程可能如下所示:

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

(当然,如果您的字符串中的任何元素包含无效的 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);

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

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

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

然后,您的 Web 应用程序可以将诸如 DataTable 之类的集合传递给 @GUIDs 参数。没有混乱的字符串拆分,没有类型转换,没有人为限制您可以传递多少个不同的 GUID。

于 2013-08-16T00:53:06.150 回答
0

在我看来,您正试图通过一个存储过程实现太多目标。我会尝试将搜索算法或查询分解成更小的部分,并将特定搜索实体的特定结果整理到结果集中。

可能的替代方案:

  • 在您的应用程序中动态编写 SQL 查询。
  • 将您的程序分解为多个较小的程序,并仅根据搜索条件调用必要的程序

在大多数情况下,我认为必须在 T-SQL 中(手动)解析 CSV 是代码/架构的味道。

编辑:只需阅读... http://technet.microsoft.com/en-US/library/ms187926(v=sql.90).aspx

一个存储过程最多可以有 2,100 个参数。

所以有什么问题?我以为您出于某种原因遇到了限制。只是使用更多的参数,它比解析 CSV 更可取。另外不要忘记,您可以为存储的 proc 参数提供默认值,这样您就不必在每次调用时提供所有 40 多个参数,前提是它们被命名发送。

也不要忘记表值 UDF ......它们非常好,因为它们可以以下列方式使用

select * from dbo.fn_ProductsByLine('Toasters') pbl inner join dbo.fn_ProductsByPrice(10,20) pbp on pbl.productID = pbp.productID
于 2013-08-15T21:04:32.240 回答