Domanda

Come posso memorizzare un valore di campo selezionato in una variabile da una query e usarlo in un'istruzione di aggiornamento?

Ecco la mia procedura:

Sto scrivendo una stored procedure T-SQL di SQL Server 2005 che esegue le seguenti operazioni:

  1. ottiene l'elenco di ID fatture dalla tabella delle fatture e memorizza nel cursore
  2. Recupera ID fattura dal cursore - > variabile tmp_key
  3. foreach tmp_key trova l'ID contatto principale del cliente della fattura dalla tabella clienti
  4. aggiorna la chiave di contatto client con ID contatto primario
  5. chiudi cursore

Ecco il mio codice:

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

Come posso archiviare PrimaryContactKey e riutilizzarlo nella clausola set della seguente istruzione di aggiornamento? Creo una variabile cursore o solo un'altra variabile locale con un tipo int?

È stato utile?

Soluzione

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

Modifica
Questa domanda ha ottenuto molta più trazione di quanto mi sarei aspettato. Nota che non sto sostenendo l'uso del cursore nella mia risposta, ma piuttosto mostrando come assegnare il valore in base alla domanda.

Altri suggerimenti

Ho appena avuto lo stesso problema e ...

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

o anche più breve:

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

Prova questo

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

Dichiarerai questa variabile al di fuori del tuo loop come solo una variabile TSQL standard.

Dovrei anche notare che è così che faresti per qualsiasi tipo di selezione in una variabile, non solo quando hai a che fare con i cursori.

Perché hai bisogno di un cursore? L'intero segmento di codice può essere sostituito da questo, che verrà eseguito molto più velocemente su un gran numero di righe.

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

Per assegnare una variabile in sicurezza devi usare l'istruzione SET-SELECT:

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

Assicurati di avere una parentesi sia iniziale che finale!

Il motivo per cui la versione SET-SELECT è il modo più sicuro per impostare una variabile è duplice.

1. SELEZIONA restituisce diversi post

Cosa succede se la seguente selezione risulta in più post?

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

@PrimaryContactKey verrà assegnato il valore dall'ultimo post nel risultato.

In effetti a @PrimaryContactKey verrà assegnato un valore per post nel risultato, quindi conterrà di conseguenza il valore dell'ultimo post che il comando SELECT stava elaborando.

Quale post è " ultimo " è determinato da qualsiasi indice cluster o, se non viene utilizzato alcun indice cluster o se la chiave primaria è raggruppata, il "last" il post sarà l'ultimo post aggiunto. Questo comportamento potrebbe, nel peggiore dei casi, essere modificato ogni volta che viene cambiata l'indicizzazione della tabella.

Con un'istruzione SET-SELECT la variabile verrà impostata su null .

2. SELECT non restituisce alcun post

Cosa succede quando si utilizza la seconda versione del codice, se la selezione non restituisce alcun risultato?

Al contrario di quanto si possa pensare, il valore della variabile non sarà nullo - manterrà è il valore precedente!

Questo perché, come indicato sopra, SQL assegnerà un valore alla variabile una volta per post , il che significa che non farà nulla con la variabile se il risultato non contiene post. Pertanto, la variabile avrà ancora il valore che aveva prima di eseguire l'istruzione.

Con l'istruzione SET-SELECT il valore sarà null .

Vedi anche: SET contro SELECT durante l'assegnazione delle variabili?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top