Pergunta

Como faço para armazenar um valor campo selecionado em uma variável de uma consulta e usá-lo em uma instrução de atualização?

Aqui está o meu procedimento:

Eu estou escrevendo um procedimento armazenado 2005 T-SQL SQL Server que faz o seguinte:

  1. recebe lista de facturas id é da tabela factura e lojas para Cursor
  2. Obter id factura de cursor -> variável tmp_key
  3. achados foreach tmp_key factura cliente ID de contato primário da tabela do cliente
  4. atualiza a chave de contato do cliente com ID de contato primário
  5. close cursor

Aqui está o meu código:

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

Como faço para armazenar o PrimaryContactKey e usá-lo novamente na cláusula set da seguinte declaração atualização? Faço para criar uma variável de cursor ou apenas uma outra variável local com um tipo int?

Foi útil?

Solução

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

EDIT:
Esta questão tem obtido um tração muito mais do que eu teria antecipado. Note que não estou defendendo o uso do cursor na minha resposta, mas sim mostrando como atribuir o valor com base na pergunta.

Outras dicas

Eu apenas tive o mesmo problema e ...

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

ou ainda mais curto:

declare @userId uniqueidentifier
SELECT TOP 1 @userId = UserId FROM aspnet_Users

Tente este

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

Você iria declarar esta fora variável do seu ciclo como apenas uma variável TSQL padrão.

Gostaria também de salientar que esta é a forma como você faria para qualquer tipo de seleção em uma variável, não apenas quando se lida com cursores.

Por que você precisa de um cursor em tudo? Todo o seu segmento de código pode ser substituída pela presente, que vai correr muito mais rápido em um grande número de linhas.

UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey 
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey
WHERE confirmtocntctkey is null and tranno like '%115876'

Para atribuir uma variável com segurança você tem que usar a instrução SET-SELECT:

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

Certifique-se de que você tem tanto uma partida e um parêntese final!

A razão a versão SET SELECT é a forma mais segura para definir uma variável é duplo.

1. Os retornos Seleccione várias mensagens

O que acontece se os seguintes resultados selecionados em vários lugares?

SELECT @PrimaryContactKey = c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key

@PrimaryContactKey será atribuído o valor do último post no resultado.

Na verdade @PrimaryContactKey será atribuído um valor por posto no resultado, por isso vai, consequentemente, conter o valor do último post do SELECT-comando estava processando.

Qual post é "passado" é determinada por quaisquer índices de cluster ou, se nenhum índice agrupado é usado ou a chave primária está agrupado, o "último" post será o post mais recentemente adicionado. Este comportamento poderia, na pior das hipóteses, ser alterada cada vez que a indexação da tabela é alterado.

Com uma declaração SET SELECT sua variável será definido para null.

2. O SELECT retorna há mensagens

O que acontece, quando se utiliza a segunda versão do código, se a sua escolha não retorna um resultado em tudo?

Em um ao contrário do que você pode acreditar que o valor da variável não será nulo - ela irá reter é o valor anterior

Isto porque, como dito acima, o SQL irá atribuir um valor à variável uma vez por mensagem - o que significa que não vai fazer nada com a variável se o resultado não contém mensagens. Assim, a variável ainda terá o valor que tinha antes de executar a declaração.

Com a instrução SET-selecionar o valor será null.

Veja também: contra SELECT quando a atribuição de variáveis ??

scroll top