77

如何将选定的字段值存储到查询中的变量中并在更新语句中使用它?

这是我的程序:

我正在编写一个 SQL Server 2005 T-SQL 存储过程,它执行以下操作:

  1. 从发票表中获取发票 ID 列表并将其存储到光标
  2. 从光标获取发票 ID -> tmp_key 变量
  3. foreach tmp_key 从客户表中查找发票客户主要联系人 ID
  4. 使用主要联系人 ID 更新客户端联系人密钥
  5. 关闭光标

这是我的代码:

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 类型的局部变量?

4

5 回答 5

109

我只是遇到了同样的问题并且...

declare @userId uniqueidentifier
set @userId = (select top 1 UserId from aspnet_Users)

甚至更短:

declare @userId uniqueidentifier
SELECT TOP 1 @userId = UserId FROM aspnet_Users
于 2011-01-27T13:50:19.653 回答
50
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

编辑:
这个问题比我预期的要多得多。请注意,我并不提倡在回答中使用光标,而是展示如何根据问题分配值。

于 2009-04-30T16:16:48.930 回答
20

试试这个

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 变量。

我还应该注意,这就是您将任何类型的选择放入变量的方式,而不仅仅是在处理游标时。

于 2009-04-30T16:13:39.407 回答
15

为了安全地分配变量,您必须使用 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?

于 2013-10-29T15:16:56.187 回答
14

为什么你需要一个游标?您的整个代码段都可以用它替换,这将在大量行上运行得更快。

UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey 
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey
WHERE confirmtocntctkey is null and tranno like '%115876'
于 2009-05-01T19:08:46.810 回答