2010-05-21 6 views
2

J'essaie de voir s'il est possible d'effectuer une mise à jour dans une boucle de curseur et que ces données mises à jour sont réfléchies lors de la deuxième itération dans la boucle.Comment valider dans une boucle CURSOR?

DECLARE cur CURSOR 
FOR SELECT [Product], [Customer], [Date], [Event] FROM MyTable 
WHERE [Event] IS NULL 

OPEN cur 
FETCH NEXT INTO @Product, @Customer, @Date, @Event 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    SELECT * FROM MyTable WHERE [Event] = 'No Event' AND [Date] < @DATE 
    -- Now I update my Event value to 'No Event' for records whose date is less than @Date 
    UPDATE MyTable SET [Event] = 'No Event' WHERE [Product] = @Product AND [Customer] = @Customer AND [Date] < @DATE 
    FETCH NEXT INTO @Product, @Customer, @Date, @Event 
END 
CLOSE cur 
DEALLOCATE cur 

On suppose quand le sql exécute la colonne de l'événement est NULL pour tous les enregistrements Dans le sql ci-dessus, je suis en train de faire une sélection dans la boucle du curseur pour interroger MyTable où la valeur de l'événement est « aucun événement », mais retourne la requête pas de valeur même si je fais une mise à jour dans la ligne suivante. Donc, je pense qu'il est même possible de mettre à jour une table et que les données mises à jour sont reflétées dans l'itération suivante de la boucle du curseur.

Merci pour toute aide, Javid

Répondre

0

Même si cela a fonctionné, cela ne garantit pas le résultat correct puisque vous manquez une clause ORDER BY dans votre requête. En fonction de cela, tous les enregistrements, aucun enregistrement ou tout sous-ensemble aléatoire d'enregistrements pourraient être mis à jour.

Pourriez-vous expliquer en langage clair ce que votre procédure stockée devrait faire?

+0

Salut, La raison pour laquelle je devais utiliser le curseur est je dois calculer la moyenne mobile pour chaque enregistrement en fonction de la valeur de la colonne de l'événement (à savoir aucun événement) des dossiers antérieurs. La moyenne mobile est calculée pour déterminer une anomalie et je l'utilise pour définir la valeur de l'événement à quelque chose comme «anormal».Mais, si je trouve trois ou plus consécutifs «anormaux», je dois tous les réinitialiser à «aucun événement», ainsi quand la moyenne est calculée pour l'enregistrement suivant, les points de données précédents doivent être utilisés. Désolé si je vous avais dérouté. Espérons que cette information aide .. – user320587

+1

@user: pourriez-vous s'il vous plaît poster un exemple de jeu d'enregistrements et la sortie désirée? – Quassnoi

+0

Les résultats finaux seraient déterministes, il serait juste indéterministe comment ils ont été atteints. S'il arrivait de traiter les lignes dans l'ordre décroissant de la date, cela nécessiterait beaucoup moins d'opérations que dans l'ordre croissant. –

4

Premièrement Vous ne devriez pas avoir besoin d'un curseur ici. Quelque chose comme le suivant aurait la même sémantique (à partir d'une position de départ où tous Event sont NULL) et être plus efficace. Deuxièmement, en ce qui concerne la question dans le titre à commettre à l'intérieur d'une boucle de curseur est le même que partout ailleurs. Vous avez juste besoin d'une instruction COMMIT. Toutefois, si vous ne l'exécutez pas dans une transaction plus importante, l'instruction UPDATE sera automatiquement validée.

Troisièmement Votre vraie question ne semble pas être sur l'engagement de toute façon. Il s'agit du curseur reflétant les mises à jour des données sur les itérations suivantes. Pour le cas dans la question que vous auriez besoin d'un DYNAMIC curseur

Définit un curseur qui reflète toutes les modifications de données apportées aux lignes son jeu de résultats que vous faites défiler autour du curseur. Les valeurs de données, l'ordre et l'appartenance aux lignes peuvent changer à chaque extraction.

Toutes les requêtes ne prennent pas en charge les curseurs dynamiques. Le code dans la question serait mais sans un ORDER BY il est indéterministe quel ordre les lignes seraient traitées et donc si vous verriez des résultats visibles. J'ai ajouté un ORDER BY et un index pour le supporter afin de permettre l'utilisation d'un curseur dynamique. Si vous essayez ce qui suit, vous verrez que le curseur ne récupère qu'une ligne à mesure que les dates sont traitées dans l'ordre décroissant et lorsque la première ligne est traitée, la table est mise à jour de sorte que plus aucune ligne n'est qualifiée pour la prochaine extraction. Si vous commentez le UPDATE à l'intérieur de la boucle du curseur, toutes les trois lignes sont récupérées.

CREATE TABLE MyTable 
    (
    [Product] INT, 
    [Customer] INT, 
    [Date]  DATETIME, 
    [Event] VARCHAR(10) NULL, 
    PRIMARY KEY ([Date], [Product], [Customer]) 
) 


INSERT INTO MyTable 
VALUES (1,1,'20081201',NULL), 
     (1,1,'20081202',NULL), 
     (1,1,'20081203',NULL) 

DECLARE @Product INT, 
     @Customer INT, 
     @Date  DATETIME, 
     @Event VARCHAR(10) 

DECLARE cur CURSOR DYNAMIC TYPE_WARNING FOR 
    SELECT [Product], 
     [Customer], 
     [Date], 
     [Event] 
    FROM MyTable 
    WHERE [Event] IS NULL 
    ORDER BY [Date] DESC 

OPEN cur 

FETCH NEXT FROM cur INTO @Product, @Customer, @Date, @Event 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SELECT @Product, 
      @Customer, 
      @Date, 
      @Event 

     -- Now I update my Event value to 'No Event' for records whose date is less than @Date 
     UPDATE MyTable 
     SET [Event] = 'No Event' 
     WHERE [Product] = @Product 
      AND [Customer] = @Customer 
      AND [Date] < @Date 

     FETCH NEXT FROM cur INTO @Product, @Customer, @Date, @Event 
    END 

CLOSE cur 

DEALLOCATE cur 

DROP TABLE MyTable 
+0

cela ne répond pas à la question. – dansan

+0

@dansan - Vous avez raison. Rectifié. –

+0

même s'il n'a pas répondu à la question, j'ai appris beaucoup plus avec cette réponse que je l'aurais fait avec une courte réponse directe ... allez martin! – jambriz