题
如何将选定的字段值存储到查询中的变量中并在更新语句中使用它?
这是我的程序:
我正在编写一个SQL Server 2005 T-SQL存储过程,它执行以下操作:
- 从发票表中获取发票ID列表并存储到Cursor
- 从光标中获取发票ID - > tmp_key变量
- foreach tmp_key在customer table 中查找发票客户主要联系人ID
- 使用主要联系人ID 更新客户联系人密钥
- 关闭游标 醇>
这是我的代码:
DECLARE @tmp_key int
DECLARE @get_invckey cursor
set @get_invckey = CURSOR FOR
select invckey from tarinvoice where confirmtocntctkey is null and tranno like '%115876'
OPEN @get_invckey
FETCH NEXT FROM @get_invckey into @tmp_key
WHILE (@@FETCH_STATUS = 0)
BEGIN
SELECT c.PrimaryCntctKey as PrimaryContactKey
from tarcustomer c, tarinvoice i
where i.custkey = c.custkey and i.invckey = @tmp_key
UPDATE tarinvoice set confirmtocntctkey = PrimaryContactKey where invckey = @tmp_key
FETCH NEXT FROM @get_invckey INTO @tmp_key
END
CLOSE @get_invckey
DEALLOCATE @get_invckey
如何存储PrimaryContactKey并在以下更新语句的set子句中再次使用它?我是否使用int类型创建游标变量或另一个局部变量?
解决方案
DECLARE @tmp_key int
DECLARE @get_invckey cursor
SET @get_invckey = CURSOR FOR
SELECT invckey FROM tarinvoice WHERE confirmtocntctkey IS NULL AND tranno LIKE '%115876'
OPEN @get_invckey
FETCH NEXT FROM @get_invckey INTO @tmp_key
DECLARE @PrimaryContactKey int --or whatever datatype it is
WHILE (@@FETCH_STATUS = 0)
BEGIN
SELECT @PrimaryContactKey=c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey AND i.invckey = @tmp_key
UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey WHERE invckey = @tmp_key
FETCH NEXT FROM @get_invckey INTO @tmp_key
END
CLOSE @get_invckey
DEALLOCATE @get_invckey
修改强>结果 这个问题比我预期的要大得多。请注意,我不是在我的答案中提倡使用光标,而是展示如何根据问题分配值。
其他提示
我遇到了同样的问题......
declare @userId uniqueidentifier
set @userId = (select top 1 UserId from aspnet_Users)
甚至更短:
declare @userId uniqueidentifier
SELECT TOP 1 @userId = UserId FROM aspnet_Users
试试这个
SELECT @PrimaryContactKey = c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey
AND i.invckey = @tmp_key
UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey
WHERE invckey = @tmp_key
FETCH NEXT FROM @get_invckey INTO @tmp_key
您可以将此变量声明为循环外的标准TSQL变量。
我还应该注意,对于任何类型的select变量,你都会这样做,而不仅仅是在处理游标时。
为什么你需要一个光标? 您的整个代码段都可以替换为此代码,这将在大量行上运行得更快。
UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey
WHERE confirmtocntctkey is null and tranno like '%115876'
为了安全地分配变量,您必须使用SET-SELECT语句:
SET @PrimaryContactKey = (SELECT c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey
AND i.invckey = @tmp_key)
确保你有一个开头括号和一个结束括号!
SET-SELECT版本是设置变量的最安全方式的原因是双重的。
<强> 1。 SELECT返回几个帖子
如果以下选项会产生多个帖子会怎样?
SELECT @PrimaryContactKey = c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey
AND i.invckey = @tmp_key
将在结果中为 @PrimaryContactKey
分配上一篇文章中的值。
实际上 @PrimaryContactKey
将在结果中为每个帖子分配一个值,因此它将包含SELECT命令正在处理的最后一个帖子的值。
哪个帖子是“最后一个”由任何聚簇索引确定,或者如果没有使用聚簇索引或主键是聚簇的,则“最后”是帖子将是最近添加的帖子。在最坏的情况下,每次更改表的索引时,都会更改此行为。
使用SET-SELECT语句,您的变量将设置为 null
。
<强> 2。 SELECT不返回任何帖子
当使用第二版代码时,如果你的选择根本没有返回结果,会发生什么?
与您可能认为的变量的值不会为空相反 - 它将保留它之前的值!
这是因为,如上所述,SQL会为每个帖子分配一个值 - 这意味着如果结果不包含帖子,它将不会对变量做任何事情。因此,变量仍然具有运行语句之前的值。
使用SET-SELECT语句,该值将为 null
。
另请参阅:分配变量时SET与SELECT?