Question

Comment enregistrer une valeur de champ sélectionnée dans une variable à partir d'une requête et l'utiliser dans une instruction de mise à jour?

Voici ma procédure:

J'écris une procédure stockée SQL Server 2005 T-SQL qui effectue les opérations suivantes:

  1. récupère la liste des identifiants de factures de la table de factures et la stocke dans le curseur
  2. Récupérer l'identifiant de la facture à partir du curseur - > variable tmp_key
  3. foreach tmp_key recherche l'ID de contact principal du client de facturation à partir de la table client
  4. met à jour la clé de contact du client avec l'identifiant de contact principal
  5. ferme le curseur

Voici mon code:

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

Comment enregistrer la PrimaryContactKey et la réutiliser dans la clause set de la déclaration de mise à jour suivante? Est-ce que je crée une variable de curseur ou juste une autre variable locale avec un type int?

Était-ce utile?

La solution

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

MODIFIER:
Cette question a eu beaucoup plus de succès que prévu. Notez que je ne préconise pas l’utilisation du curseur dans ma réponse, mais indique plutôt comment attribuer la valeur en fonction de la question.

Autres conseils

Je viens d'avoir le même problème et ...

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

ou même plus court:

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

Essayez ceci

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

Vous déclareriez cette variable en dehors de votre boucle comme une variable TSQL standard.

Je dois également noter que voici comment procéder comme pour tout type de sélection dans une variable, pas seulement lorsque vous utilisez des curseurs.

Pourquoi avez-vous besoin d'un curseur? Votre segment de code entier peut être remplacé par ceci, ce qui fonctionnera beaucoup plus rapidement sur un grand nombre de lignes.

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

Pour affecter une variable en toute sécurité, vous devez utiliser l'instruction SET-SELECT:

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

Assurez-vous d'avoir une parenthèse de début et de fin!

La raison pour laquelle la version de SET-SELECT est le moyen le plus sûr de définir une variable est double.

1. SELECT renvoie plusieurs messages

Que se passe-t-il si les résultats de sélection suivants génèrent plusieurs messages?

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

@PrimaryContactKey se verra attribuer la valeur du dernier message dans le résultat.

En fait, @PrimaryContactKey recevra une valeur par publication dans le résultat. Il contiendra par conséquent la valeur de la dernière publication traitée par la commande SELECT.

Quelle publication est la "dernière" " est déterminé par n'importe quel index clusterisé ou, si aucun index clusterisé n'est utilisé ou si la clé primaire est clusterisée, le "dernier" post sera le dernier post ajouté. Dans le pire des cas, ce comportement pourrait être modifié à chaque modification de l'indexation de la table.

Avec une instruction SET-SELECT, votre variable sera définie sur null .

2. Le SELECT ne renvoie aucun message

Que se passe-t-il lors de l'utilisation de la deuxième version du code si votre sélection ne renvoie aucun résultat?

Contrairement à ce que vous pouvez penser, la valeur de la variable ne sera pas nulle - elle conservera sa valeur précédente!

En effet, comme indiqué ci-dessus, SQL attribue une valeur à la variable une fois par publication , ce qui signifie qu'il ne fera rien avec la variable si le résultat ne contient aucune publication. Ainsi, la variable aura toujours la valeur qu’elle avait avant l’exécution de l’instruction.

Avec l'instruction SET-SELECT, la valeur sera null .

Voir aussi: SET ou SELECT lors de l'attribution de variables?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top