如何将选择结果分配给变量?

phi*_*ill 70 t-sql cursor

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

这是我的程序:

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

  1. 获取发票表中的发票ID列表并存储到Cursor
  2. 从游标 - > tmp_key变量获取发票ID
  3. foreach tmp_key从customer表中查找invoice client主要联系人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
Run Code Online (Sandbox Code Playgroud)

如何存储PrimaryContactKey并在以下更新语句的set子句中再次使用它?我是否使用int类型创建游标变量或另一个局部变量?

小智 93

我刚遇到同样的问题......

declare @userId uniqueidentifier
set @userId = (select top 1 UserId from aspnet_Users)
Run Code Online (Sandbox Code Playgroud)

甚至更短:

declare @userId uniqueidentifier
SELECT TOP 1 @userId = UserId FROM aspnet_Users
Run Code Online (Sandbox Code Playgroud)

  • 我不知道因为`set @userId =(从aspnet_Users中选择前1个UserId)`**没有括号**会导致"选择不正确的语法"! (3认同)
  • 请注意,上面光标的使用与如何分配给变量的问题无关.不幸的是,这使得这个问题变得令人困惑 (3认同)

squ*_*man 45

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
Run Code Online (Sandbox Code Playgroud)

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


The*_*TXI 19

试试这个

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
Run Code Online (Sandbox Code Playgroud)

您可以将此变量声明为循环外的标准TSQL变量.

我还应该注意,这是你为任何类型的select变量做的,而不仅仅是在处理游标时.


Gil*_*ter 14

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

UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey 
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey
WHERE confirmtocntctkey is null and tranno like '%115876'
Run Code Online (Sandbox Code Playgroud)

  • 他们很慢.SQL Server针对基于集合的查询进行了优化.它在一个查询中以百万行操作比在一行上操作一百万次更快.除此之外还有游标所带来的开销,并且您要求使用游标而不是基于集合的操作来解决主要的性能问题测试游标解决方案和我的查询,看看两者的执行时间是什么. (4认同)

Erk*_*Erk 11

为了安全地分配变量,您必须使用SET-SELECT语句:

SET @PrimaryContactKey = (SELECT c.PrimaryCntctKey
    FROM tarcustomer c, tarinvoice i
    WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key)
Run Code Online (Sandbox Code Playgroud)

确保你有一个开始和结束括号!

SET-SELECT版本是设置变量最安全的方式的原因是双重的.

1. SELECT返回几个帖子

如果以下选择导致多个帖子会发生什么?

SELECT @PrimaryContactKey = c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key
Run Code Online (Sandbox Code Playgroud)

@PrimaryContactKey将从结果中的最后一个帖子中分配值.

事实上@PrimaryContactKey,在结果中每个帖子将分配一个值,因此它将包含SELECT命令正在处理的最后一个帖子的值.

哪个帖子是"最后"由任何聚簇索引确定,或者如果没有使用聚簇索引或主键是聚类,则"最后"帖子将是最近添加的帖子.在最坏的情况下,每次更改表的索引时,都可以更改此行为.

使用SET-SELECT语句,您的变量将设置为null.

2. SELECT不返回任何帖子

当使用第二版代码时,如果您的选择根本不返回结果,会发生什么?

与您可能认为的变量值不为空相反- 它将保留它以前的值!

这是因为,如上所述,SQL将为每个帖子一次为变量赋值- 这意味着如果结果不包含任何帖子,它将不会对变量执行任何操作.因此,变量仍然具有运行语句之前的值.

使用SET-SELECT语句,值将是null.

另请参阅:分配变量时SET与SELECT?