我几乎完成了将基于游标的存储过程更改为基于集合的过程。差不多,因为我只有一件事要弄明白。
他们使用名为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语句中执行存储过程来设置列值。
有没有人尝试过类似的东西,但是成功了?
答案 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存储过程由“同时”的不同进程调用,我建议你要么
虽然我当然支持前一种解决方案,但它需要更改看似非常核心的存储过程,这是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语句中使用存储过程或函数的问题。
还有一件事,我不认为你可以自定义表格的主要ID / PK(如果你发现,你可以,也请让我知道)。因此,客户ID将始终是第二个/单独的列。