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

时间:2012-04-23 12:00:41

标签: 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:

Exec [TargetSp]
  @Id IN (Select [M].[Id] From [Member] AS [M] Where [M].[Title] = 'Example');

首先:我如何为列表执行它?

第二:我执行sp多次或在目标脚本中重写它有什么性能差异?

6 个答案:

答案 0 :(得分:3)

您可以使用表值参数(请参阅http://msdn.microsoft.com/en-us/library/bb510489.aspx)。通常,如果您只向服务器发送一个请求而不是请求列表,则会看到更短的执行时间。

答案 1 :(得分:1)

我通常会传递像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

答案 2 :(得分:1)

与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

有趣的是,我已经开发了一个拥有1000个用户的大规模系统,我们发现使用这种方法可以为小的id列表(不超过5个id)执行表值参数方法。对于较大的Id列表,表值参数方法更快。

编辑问题后编辑:

查看您的示例,您似乎希望根据Title参数更新ATable。如果除了title参数之外,你可以从重写存储过程中受益。

create procedure [TargetSP](
   @title varchar(50)
)
as 
begin

update [ATable]
set [AColumn] = 
(
    select [ACalculatedValue] from [AnotherTable]
)
where [ATable].[Member_Id] in (select [M].[Id] from [Member] as [M] where [M].[Title] = @title);

end

答案 3 :(得分:1)

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

ALTER PROCEDURE dbo.TargetSP
  @title VARCHAR(255)
AS
BEGIN
  SET NOCOUNT ON;

  -- only do this once instead of as a subquery:
  DECLARE @v VARCHAR(255) = (SELECT [ACalculatedValue] From [AnotherTable]);

  UPDATE a
    SET AColumn = @v
    FROM dbo.ATable AS a
    INNER JOIN dbo.Member AS m
    ON a.Member_Id = m.Id
    WHERE m.Title = @title;
END
GO

现在称之为:

EXEC dbo.TargetSP @title = 'Example';

答案 4 :(得分:1)

 DECLARE @VId BIGINT;

 DECLARE [My_Cursor] CURSOR FAST_FORWARD READ_ONLY FOR
 Select [M].[Id] From [Member] AS [M] Where [M].[Title] = 'Example'
 OPEN [My_Cursor]
    FETCH NEXT FROM [My_Cursor] INTO @VId
    WHILE @@FETCH_STATUS = 0
    BEGIN
        EXEC [TargetSp]
        @Id = @VId
    FETCH NEXT FROM [My_Cursor] INTO @VId
END
CLOSE [My_Cursor]
DEALLOCATE [My_Cursor];
GO

答案 5 :(得分:0)

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

您的选择是:

  1. 多次调用proc,每个参数一个
  2. 更改proc以接受可以传递超过的结构 一个id就像一个varchar,你传递一个逗号分隔的值列表 (不太好)或表值参数
  3. 关于性能问题,重新编写proc以迭代id列表比调用它几次更快,每个id一次,但是除非你正在处理一个巨大的id列表,我不认为你会看到很多不同