为SQL中的参数列表执行存储过程

为SQL中的参数列表执行存储过程,sql,sql-server,sql-server-2008,tsql,sql-scripts,Sql,Sql Server,Sql Server 2008,Tsql,Sql Scripts,我有一个存储过程,它有一个名为Id的参数: CREATE PROCEDURE [TargetSp]( @Id [bigint] ) AS BEGIN Update [ATable] SET [AColumn] = ( Select [ACalculatedValue] From [AnotherTable] ) Where [ATable].[Member_Id] = @Id END 因此,我需要将其用于Id列表,而不是一个Id,如: Exe

我有一个存储过程,它有一个名为
Id
的参数:

CREATE PROCEDURE [TargetSp](
   @Id  [bigint]
)
AS 
BEGIN
   Update [ATable]
   SET [AColumn] = 
   (
     Select [ACalculatedValue] From [AnotherTable]
   )
   Where [ATable].[Member_Id] = @Id
END
因此,我需要将其用于Id列表,而不是一个Id,如:

Exec [TargetSp]
  @Id IN (Select [M].[Id] From [Member] AS [M] Where [M].[Title] = 'Example');
第一:如何为列表执行它


第二:多次执行sp或在目标脚本中重写sp之间是否存在性能差异?

您可以使用表值参数(请参阅)。通常,如果只向服务器发送一个请求而不是请求列表,则执行时间会缩短。

可以使用表值参数(请参阅)。一般来说,如果只向服务器发送一个请求而不是一系列请求,则执行时间会缩短。

我通常将这样的信息作为XML传递,然后您可以像使用表一样使用它。。。根据需要选择、插入、更新

DECLARE @IDS NVARCHAR(MAX), @IDOC INT
SET @IDS = N'<ROOT><ID>1</ID><ID>2<ID></ROOT>'
EXEC sp_xml_preparedocument @IDOC OUTPUT, @IDS
SELECT [ID] FROM OPENXML (@IDOC, '/ROOT/ID', 2) WITH ([ID] INT '.') AS XMLDOC
EXEC sp_xml_removedocument @IDOC
声明@IDS NVARCHAR(MAX),@IDOC INT
设置@IDS=N'12'
EXEC sp_xml_preparedocument@IDOC OUTPUT,@IDS
从OPENXML(@IDOC,'/ROOT/ID',2)中选择[ID],并将([ID]INT.')作为XMLDOC
EXEC sp_xml_removedocument@IDOC

我通常将这样的信息作为XML传递,然后您可以像使用表一样使用它。。。根据需要选择、插入、更新

DECLARE @IDS NVARCHAR(MAX), @IDOC INT
SET @IDS = N'<ROOT><ID>1</ID><ID>2<ID></ROOT>'
EXEC sp_xml_preparedocument @IDOC OUTPUT, @IDS
SELECT [ID] FROM OPENXML (@IDOC, '/ROOT/ID', 2) WITH ([ID] INT '.') AS XMLDOC
EXEC sp_xml_removedocument @IDOC
声明@IDS NVARCHAR(MAX),@IDOC INT
设置@IDS=N'12'
EXEC sp_xml_preparedocument@IDOC OUTPUT,@IDS
从OPENXML(@IDOC,'/ROOT/ID',2)中选择[ID],并将([ID]INT.')作为XMLDOC
EXEC sp_xml_removedocument@IDOC

如果参数为整数,则一次只能传递一个值

你的选择是:

  • 多次调用proc,每个参数调用一次
  • 更改proc以接受一个结构,其中可以传递多个 一个像varchar的id,在这里传递一个分隔的值列表 (不太好)或表值参数

  • 关于性能问题,重新编写过程以遍历id列表要比多次调用更快,每个id调用一次。但是,除非您处理的是大量id列表,否则我认为您不会看到太大的差异。

    如果参数为整数,一次只能传递一个值

    你的选择是:

  • 多次调用proc,每个参数调用一次
  • 更改proc以接受一个结构,其中可以传递多个 一个像varchar的id,在这里传递一个分隔的值列表 (不太好)或表值参数

  • 关于性能问题,重新编写过程以遍历id列表要比多次调用更快,每个id调用一次,但除非您处理的是大量id列表,否则我认为您不会看到与freefaller示例类似的差异,而是使用xml类型并插入到表变量@ParsedIds中

    DECLARE @IdXml XML = N'<root><id value="1"/><id value="2"/></root>'
    
    DECLARE @ParsedIds TABLE (parsedId int not null)
    
    INSERT INTO @ParsedIds (parsedId)
    SELECT v.parsedId.value('@value', 'int')
    FROM @IdXml.nodes('/root/id') as v(parsedId)
    
    SELECT * FROM @ParsedIds
    

    与freefaller的示例类似,但使用xml类型并插入到表变量@ParsedIds中

    DECLARE @IdXml XML = N'<root><id value="1"/><id value="2"/></root>'
    
    DECLARE @ParsedIds TABLE (parsedId int not null)
    
    INSERT INTO @ParsedIds (parsedId)
    SELECT v.parsedId.value('@value', 'int')
    FROM @IdXml.nodes('/root/id') as v(parsedId)
    
    SELECT * FROM @ParsedIds
    

    由于您只关心标题为“Example”的所有行,因此不需要先确定列表,然后再告诉SQL Server您要更新的列表,因为您已经可以通过查询识别这些行。那么为什么不改为这样做呢(我猜这里有一些数据类型):

    现在称之为:

    EXEC dbo.TargetSP @title = 'Example';
    

    由于您只关心标题为“Example”的所有行,因此不需要先确定列表,然后再告诉SQL Server您要更新的列表,因为您已经可以通过查询识别这些行。那么为什么不改为这样做呢(我猜这里有一些数据类型):

    现在称之为:

    EXEC dbo.TargetSP @title = 'Example';
    

    看看这个。您可以创建一个返回ID的函数,并将其连续传递给存储过程。请忽略关于Sybase的注释,但逻辑是类似的。我仍然认为必须有一个非常简单的解决方案来解决您的问题。@Id参数的来源是什么?它是存储在数据库的表中(在这种情况下,您应该能够在存储过程中使用联接),还是从应用程序生成的?看看这个。您可以创建一个返回ID的函数,并将其连续传递给存储过程。请忽略关于Sybase的注释,但逻辑是类似的。我仍然认为必须有一个非常简单的解决方案来解决您的问题。@Id参数的来源是什么?它是存储在数据库中的表中(在这种情况下,您应该能够在存储过程中使用联接)还是从应用程序生成的?我需要为此Id执行它
    Select[M].[Id]from[Member]AS[M],其中[M].[Title]='Example'
    您建议多次调用什么?它返回多少行记录?如果它返回2,我将调用proc两次,但是如果它返回更多,重新编写它可能是一个好主意,但不是因为性能提高,因为它是一个“更干净”的解决方案。我需要为这个Id的
    执行它,从[Member]选择[M].[Id]作为[M]其中[M].[Title]='Example'
    您建议多次调用什么?它返回多少条记录?如果它返回,2我会调用proc两次,但是如果它返回更多,重新编写它可能是一个好主意,但不是因为性能改进,因为它是一个“更干净”的解决方案我不知道这个。。。不幸的是,我们的大部分客户仍在2005年,因此我们无法实施。值得记住though@Dan我读了你提到的链接,并更新了主要问题,我认为根据我的情况,我不能使用表值。不知道这一个。。。不幸的是,我们的大部分客户仍在2005年,因此我们无法实施。值得记住though@Dan我阅读了你提到的链接,并更新了主要问题,我认为根据我的情况,我不能使用表值。我更新了主要问题,我认为根据我的情况,我不能使用表值。我更新了主要问题,我认为根据我的情况,我不能使用表值。