UPDATE语句使用EXEC执行存储过程来设置列值

时间:2010-11-03 15:23:22

标签: sql-server exec

我几乎完成了将基于游标的存储过程更改为基于集合的过程。差不多,因为我只有一件事要弄明白。

他们使用名为GetSequence的存储过程来查询表,使用新的序列号(old + 1)更新它并返回新的序列号值。当他们使用游标时,这不是问题,因为他们将输出值分配给变量,然后使用变量。

我能想到保留新存储过程集的唯一方法是在INSERT或UPDATE语句中执行GetSequence。但是,当我尝试这个时,我得到了奇怪的特定错误,“关键字'EXEC'附近的语法不正确”。

这是旧代码:

  DECLARE @new_UD_campaignID BIGINT -- Get the new ud_lead_id for the new lead set
  EXEC ppGlobal.dbo.Getsequence
    'ud_campaign_id',
    @new_UD_campaignID OUTPUT
  DECLARE @OrderNum VARCHAR(9);
  IF @corpCamp LIKE '%LEP%'
    BEGIN
        SELECT @OrderNum = ( 'L' + RIGHT('00000000' + CAST(@new_UD_campaignID AS VARCHAR(8)), 8) )
    END
  ELSE
    BEGIN
        SELECT @OrderNum = ( 'C' + RIGHT('00000000' + CAST(@new_UD_campaignID AS VARCHAR(8)), 8) )
    END

这很有效,但实际上很慢,因为它在游标中并且更新了超过两百万行。

我正在尝试的新代码如下:

  UPDATE @List
  SET   OrderNumBigInt = EXEC (ipCore.dbo.Getsequence
                                     'ud_campaign_id',
                                     @new_UD_campaignID OUTPUT)

我找不到任何特定文档,表明您无法在SELECT或UPDATE语句中执行存储过程来设置列值。

有没有人尝试过类似的东西,但是成功了?

3 个答案:

答案 0 :(得分:2)

记录了这一点 - UPDATE in BOL(摘录)的BNF读取

...
UPDATE 
    ...
    SET
        { column_name = { expression | DEFAULT | NULL }
    ...

expression的定义是:

  

表达

     

是变量,文字值,表达式还是子选择语句   (括在括号内)   返回单个值。价值   由表达式返回替换   column_name或中的现有值   @variable。

SP执行不是这些。

您需要找到另一种应用逻辑的方法 - 正如JNK在评论中建议的那样,您可以将SP逻辑转换为函数以在更新中使用它。

或者,是否可以重新编写SP(或编写新的SP)以在一组记录中以基于集合的方式工作?

答案 1 :(得分:2)

您建议的内容无法在MSSQL(AFAIK)中完成。事实上,我怀疑将GetSequence转换为函数的建议可能不会起作用,因为最新的ud_campaing_id可能存储在某个“全局”表中......

假设GetSequence存储过程由“同时”的不同进程调用,我建议你要么

  • 需要调整所述sp,这样你就可以一次请求一堆代码(额外的参数,例如@number_of_ids,默认为1),这样输出参数就会返回所请求的第一个id,但内部也会保留下n个为您所用,然后您可以使用它来更新您的@list
  • 需要创建一个紧密的循环来获取id的数量,然后将它们一次性应用到目标表中。

虽然我当然支持前一种解决方案,但它需要更改看似非常核心的存储过程,这是dba可能不喜欢或不允许的。然而,它会使事情变得更快。 第二个解决方案仍然需要一些循环,并且在将结果数据应用到端表时也有一些严重的索引要求,因此它远非完美但可能至少比直接循环更快一些目标表,并按记录提取和应用新数据记录。

根据您正在使用的UPDATE @list方法判断我认为您已经按照第二个建议进行了操作。 假设你在@list中有一个标识字段(对它有一个UNIQUE或PK约束,没有间隙),你可以尝试这些方法:

DECLARE @RecordID, @LastRecordID int
DECLARE @new_UD_campaignID bigint

SELECT @RecordID = Min(RecordID), 
       @LastRecordID = Max(RecordID)
  FROM @list

DECLARE @newCampaingIDs TABLE (RecordID int PRIMARY KEY, new_UD_campaignID varchar(8))

WHILE @RecordID <= @LastRecordID
    BEGIN

        EXEC ppGlobal.dbo.Getsequence 'ud_campaign_id', @new_UD_campaignID OUTPUT

        INSERT @newCampaingIDs (RecordID, new_UD_campaignID) VALUES (@RecordID, RIGHT('00000000' + CAST(@new_UD_campaignID AS VARCHAR(8)), 8))

        SELECT @RecordID = @RecordID + 1
    END

UPDATE @list
   SET OrderNum = (CASE WHEN corpCamp LIKE '%LEP%' THEN 'L' ELSE 'C' END) + new_UD_campaignID
  FROM @list upd
  JOIN @newCampaingIDs new
    ON new.RecordID = upd.RecordID

认为这个原因会更快,因为顺序插入比(按记录更新原始表记录)的开销要少(很多?)。然后,你仍然会一再停止反复调用GetSequence存储过程,这可能是你的主要时间消费者。

无论如何,唯一可以确定的方法是测试它=)

祝你好运。

答案 2 :(得分:0)

您无法从UPDATE语句调用函数或存储过程(如果有人在MS SQL中找到,请告诉我如何),但您可以在代码之间运行UPDATE。

因此无论您尝试使用函数或存储过程实现什么,都可以在函数或存储过程块中运行UPDATE语句。

例如:一旦我的客户端需要数据库中的自定义ID以及通用ID。所以我用数据类型字符串烘焙自定义ID并在烘焙中运行UPDATE。我将在下面发布示例代码...

INSERT INTO ID (
F_Name
, L_Name
, [Date]
)
VALUES(
'Josie'
, 'Smith'
, getdate()
)

BEGIN
DECLARE @VAR int    -- after all other columns have been populated @VAR holds generic ID
        , @ID VARCHAR(8)    -- the INT value @VAR holds is passed down as string to @ID 
        , @R VARCHAR(8)     -- @R holds custome value, what ever you want to customise
        , @RID VARCHAR(16); -- @RID holds the string value of @ID and @R togather
SET @VAR = (SELECT MAX( ID) FROM ID)
SET @ID = @VAR
SET @R = 'RID-000'
SET @RID = @R+@ID
Update ID   -- I am running update statement right inside this block, to update custom ID column with customised ID
SET RID = @RID
WHERE ID = @VAR -- in where clause I am bounding this customised ID to populate only current ID filed
END

SELECT * FROM ID

The results are as follows:
    ID  F_Name  L_Name  Date        RID
1   218 Joe     Smith   2018-05-29  RID-000218
2   219 Jane    Smith   2018-05-29  RID-000219
3   220 Jane    Smith   2018-05-29  RID-000220
4   221 Josie   Smith   2018-05-29  RID-000221

或者我可以在BEGIN和END之间获取整个代码块并将其放入存储过程并运行它&#34;在&#34;之后INSERT语句。只是记住这个原则我已经使用这个技巧来解决需要在UPDATE语句中使用存储过程或函数的问题。

enter image description here

还有一件事,我不认为你可以自定义表格的主要ID / PK(如果你发现,你可以,也请让我知道)。因此,客户ID将始终是第二个/单独的列。