IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement SQL Server Discussion :

Question sur le fonctionnement des jobs en cas d'erreur


Sujet :

Développement SQL Server

  1. #1
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut Question sur le fonctionnement des jobs en cas d'erreur
    Bonjour,

    Je rencontre un phénomène que je ne comprends pas...

    J'ai un job d'importation d'une vieille DB non normalisée dans une nouvelle DB normalisée.

    Ce job crée un curseur avec les lignes de l'ancienne DB (qui n'est en fait constituée que d'une seule table) et les traite une à une pour les répartir dans les tables appropriée de la nouvelle DB.

    Vu l'état de la vieille DB, vous vous doutez qu'il y a pas mal d'incohérence et donc que le job se plante de temps en temps. En général, pas de souci, je détecte le problème, corrige la donnée dans la vieille DB pour retrouver qqch de cohérent et ça repart sans souci.

    Seulement ici, quand je regarde l'erreur dans le historique du job, l'erreur rapportée est une clef alternative dupliquée dans une table. En effet, je retrouve bien cela dans la vieille DB mais ce que je ne comprends pas, c'est pourquoi les 10 lignes se trouvant après la ligne fautive ont été traité par le job ? Le curseur a bien entendu une clause order by qui m'assure l'ordre dans lequel les lignes sont traitées.

    Est-ce normal qu'un job ne s'arrête tout de suite après avoir rencontré une erreur ? Y a-t-il quelque chose à paramétrer ?

    Voici le code du job (qui n'est constitué que d'un step) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    SET ANSI_WARNINGS OFF;
     
    DECLARE @SEQNRHIST    INT;
    DECLARE @BARCODE    VARCHAR(13);
    DECLARE @DATE        DATETIME;
    DECLARE @ACTION        VARCHAR(1);
    DECLARE    @ORIGIN        INT;
    DECLARE @DESTTYPE    INT;
    DECLARE    @DEST        INT;
    DECLARE @VALUE        INT;
    DECLARE    @SALETYPE    INT;
    DECLARE    @USERTYPE    INT;    
     
    DECLARE @GFT_ID        INT;
    DECLARE @STR_ID        INT;
    DECLARE @DOS_ID        INT;
    DECLARE @DECIMAL_VALUE    DECIMAL(6,2);
    DECLARE @TMP        VARCHAR(100);
    DECLARE @TRN_TILL    SMALLINT;
    DECLARE @TRN_TICKET    SMALLINT;
    DECLARE @USERNAME    VARCHAR(50);
     
    DECLARE C CURSOR FOR
     
    SELECT
            SEQNRHIST,
            BARCODE,
            DATTIM,
            ACTION,
            ORIGIN,
            DESTTYPE,
            DEST,
            VALUE,
            SALETYPE,
            USERTYPE
    FROM
            DBO.T_CHEQUE_ACHAT_HISTORY
    ORDER BY
            SeqNrHist,
            Barcode,
            DatTim
     
    OPEN C;
     
    FETCH NEXT FROM C INTO @SEQNRHIST, @BARCODE, @DATE, @ACTION, @ORIGIN, @DESTTYPE, @DEST, @VALUE, @SALETYPE, @USERTYPE;
     
    WHILE @@FETCH_STATUS = 0
    BEGIN
        --ON RECUPERE L'ID DU GIFT
        EXEC TMP_UP_CREATE_GIFT_IF_NOT_EXISTS @BARCODE, @GFT_ID OUTPUT, @VALUE;
     
        --ON NOTE LA LIGNE EN COURS DE TRAITEMENT POUR IDENTIFIER SI PLANTAGE
        UPDATE DBO.T_CURRENT_LINE_PROCESSING_CLP
        SET
                SEQNRHIST = @SEQNRHIST,
                BARCODE = @BARCODE,
                ACTION = @ACTION
     
        --ON DEFINIT SI L'UTILISATEUR EST NORMAL OU ADMIN
        IF @USERTYPE <> 0
            SET @USERNAME = 'ADMIN';
        ELSE
            SET @USERNAME = 'NORMAL';
     
        --UTILISE A LA CAISSE (TTR_ID = 1)
        IF @ACTION = 'P'
        BEGIN
            --ON RECUPERE L'ID DU MAGASIN
            SET @ORIGIN = @ORIGIN * 10000
            IF @ORIGIN = 0
                SET @ORIGIN = 17
            ELSE 
                EXEC TMP_UP_GET_STORE_ID @ORIGIN, @STR_ID OUTPUT;
     
            --ON RECUPERE LA CAISSE ET LE TICKET
            IF @USERTYPE <> 0 --SI L'UTILISATION EST SIMULEE PAR UN ADMIN --> CAISSE ET TICKET = 0
            BEGIN
                SET @TRN_TICKET = 0;
                SET @TRN_TILL = 0;
            END
            ELSE
            BEGIN
                SET @TMP =  RIGHT('000000'+CAST(@DEST AS VARCHAR(6)),6);
                SET @TRN_TILL = CAST(LEFT(@TMP,2) AS SMALLINT);
                SET @TRN_TICKET = CAST(RIGHT(@TMP,4) AS SMALLINT);
            END
     
            --ON INSERE LA TRANSACTION
            SET @DECIMAL_VALUE = CAST(@VALUE AS DECIMAL(10,2)) / 100;
            INSERT INTO DBO.T_TRANSACTION_TRN(    TTR_ID, GFT_ID, STR_ID, TRN_DATE, TRN_TILL, TRN_TICKET, TRN_VALUE, TRN_CREATED_BY)
            VALUES(1, @GFT_ID, @STR_ID, @DATE, @TRN_TILL, @TRN_TICKET, @DECIMAL_VALUE, @USERNAME);
        END
     
        FETCH NEXT FROM C INTO @SEQNRHIST, @BARCODE, @DATE, @ACTION, @ORIGIN, @DESTTYPE, @DEST, @VALUE, @SALETYPE, @USERTYPE;
    END
     
    CLOSE C;
    DEALLOCATE C;
    Je n'ai laissé que le le traitement de l'action qui provoque l'erreur. (le code complet se trouve dans le fichier en pièce jointe).

    La clef alternative portant sur les colonnes GFT_ID et TRN_DATE où GFT_ID est l'id du gift qui subit la transaction et TRN_DATE est la date de la transaction. A ce niveau-là, pas de souci, je sais comment régler le problème mais j'aimerais comprendre pourquoi les lignes se trouvant après dans le curseur par rapport à la ligne fautive sont traitées.

    Merci d'avance.
    Fichiers attachés Fichiers attachés
    Kropernic

  2. #2
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    N'avez-vous pas une autre erreur derrière qui mettrait fin à la transaction ?

    Pour que votre transaction prenne systématiquement fin en cas d'erreur, vous pouvez spécifier un SET XACT_ABORT ON

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 448
    Points : 1 234
    Points
    1 234
    Par défaut
    Est ce que vous n'insérez pas une ligne, puis 10 autres et finalement à nouveau une ligne qui fait doublon avec la première ?
    Ensuite vous seriez convaincu que le programme a planté à l'insertion de la première ligne.
    Most Valued Pas mvp

  4. #4
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    @aieeeuuuu : Un job ne s'arrête pas directement à la première rencontrée ?

    @Sergejack : Non, le curseur traite les lignes une par une. Du moins, c'est ce que je crois ^^. C'est important qu'il traite les lignes les unes après les autres et dans l'ordre indiquée par la clause order by sans quoi, j'aurais des problèmes de cohérences.

    La suite n'est que pure spéculation...

    Est-ce qu'il est possible que le curseur traite plusieurs lignes en parallèles pour gagner du temps ?

    J'ai déjà remarqué quand j'essaie d'exécuter une requête qui provoque une erreur, il y a un petit délai avant de recevoir le message d'erreur alors que lorsque tout va bien, la confirmation est instantanée. Serait-il possible que durant le délai nécessaire au renvoi de l'erreur, le job ait continuée à traiter les lignes suivantes ?
    Kropernic

  5. #5
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    @aieeeuuuu : Un job ne s'arrête pas directement à la première rencontrée ?
    Pas forcément, et a priori pas sur une violation de contrainte d'unicité : sauf erreur de ma part, l'instruction en cours est annulée, mais le traitement continu à l'instruction suivante.

    Je vois en revanche dans votre cartouche que vous avez des trigger. En cas d'erreur dans un trigger par contre, le lot complet peut être arrêté, et la transaction en cours annulée.

    Enfin, je crois que vous avez mal interprété ce que vous a dit sergejack :
    si dans vos données vous avez :
    1 - A
    2 - B
    3 - C
    4 - D
    5 - B
    6 - F
    donc avec B qui est dupliqué.
    Peut etre vous attendez vous a ce qu'il n'y ait que la ligne 1 d'insérée, et que ça plante à la ligne 2, or c'est lors du traitement de ligne ligne 5 que l'erreur arrivera... les lignes 3 et 4 seront correctement traitées, alors qu'elles se trouvent après une ligne contenant la clef dupliquée.

  6. #6
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Citation Envoyé par aieeeuuuuu Voir le message
    Pas forcément, et a priori pas sur une violation de contrainte d'unicité : sauf erreur de ma part, l'instruction en cours est annulée, mais le traitement continu à l'instruction suivante.
    Ah, c'est ennuyeux ça... Il va donc falloir que j'ajoute l'instruction que vous avez donnée pour forcer l'arrêt lors d'une erreur.
    Citation Envoyé par aieeeuuuuu Voir le message
    Je vois en revanche dans votre cartouche que vous avez des trigger. En cas d'erreur dans un trigger par contre, le lot complet peut être arrêté, et la transaction en cours annulée.
    C'est le comportement attendu. Histoire de pouvoir investiguer sur l'erreur rencontrée, la corrigée et faire en sorte que cela n'arrive plus.

    Citation Envoyé par aieeeuuuuu Voir le message
    Enfin, je crois que vous avez mal interprété ce que vous a dit sergejack :
    si dans vos données vous avez :


    donc avec B qui est dupliqué.
    Peut etre vous attendez vous a ce qu'il n'y ait que la ligne 1 d'insérée, et que ça plante à la ligne 2, or c'est lors du traitement de ligne ligne 5 que l'erreur arrivera... les lignes 3 et 4 seront correctement traitées, alors qu'elles se trouvent après une ligne contenant la clef dupliquée.
    J'avais bien compris. La ligne 2 n'a évidemment aucune raison de provoquée une erreur. Mais vous me faites doutes... P-e ai-je mal regardé lors de mon investigation suite à cette erreur. Mais si j'avais bien les yeux en face des trous à ce moment-là, ce que j'ai vu c'est :
    1 - A
    2 - B
    3 - C
    ...
    21 - D
    22 - B
    23 - F
    24 - G
    25 - H
    26 - I
    27 - J
    28 - K
    29 - L
    30 - M
    31 - N
    Avec dans le message d'erreur, la valeur de clef que le job tente de dupliquée et dans la table qui trace la ligne en cours de traitement, le numéro de la ligne 31.
    Kropernic

  7. #7
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Voilà, je rencontre de nouveau la même problème avec le même type d'erreur (duplicate key) et sur une autre table.

    J'ai mis un exemple de donnée en pièce jointe (je n'ai pas mis toutes les colonnes pcq c'est juste horrible sinon).

    Voici le message exacte de l'erreur que je peux trouver dans le log file viewer:
    Violation of UNIQUE KEY constraint 'AK_T_TRANSACTION_TRN'. Cannot insert duplicate key in object 'dbo.T_TRANSACTION_TRN'. The duplicate key value is (670930, 1, Nov 7 2007 11:08AM). [SQLSTATE 23000] (Error 2627) The statement has been terminated. [SQLSTATE 01000] (Error 3621). The step failed.
    Et voici la définition de la clef:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    /****** Object:  Index [AK_T_TRANSACTION_TRN]    Script Date: 02/19/2013 09:28:05 ******/
    ALTER TABLE [dbo].[T_TRANSACTION_TRN] ADD  CONSTRAINT [AK_T_TRANSACTION_TRN] UNIQUE NONCLUSTERED 
    (
        [GFT_ID] ASC,
        [TTR_ID] ASC,
        [TRN_DATE] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [NDX]
    GO
    Le gift ayant pour ID 670930 est le premier dans le fichier d'exemple. On voit bien que la même transaction se répète quelques lignes plus loin et provoque donc cette erreur.

    Et en fait, les 2 lignes d'après sont aussi des doublons (3 gifts chèques utilisés lors de la même transaction caisse).

    Pourtant, dans la DB, mis à part les lignes fautives, je retrouve bien les transactions jusque à la ligne portant le numéro de séquence 1175540 incluse.

    C'est assez frustrant...

    Pour n'avoir qu'une seule erreur et pouvoir avoir continuer quelques lignes ? Je ne comprends pas.
    Fichiers attachés Fichiers attachés
    Kropernic

  8. #8
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 736
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 736
    Points : 52 447
    Points
    52 447
    Billets dans le blog
    5
    Par défaut
    On ne sait pas ce que vous faites dans vos procédure et comme vous ouvrez un curseur dynamique sur les données, si vous modifiez le contenu de la la table visée par le curseur, cela va réagir sur le contenu du curseur !

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  9. #9
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Bonjour,

    En fait c'est simple. J'ai dans une table sans aucune contrainte, l'équivalent de l'ancienne DB (et oui, ça tient dans une seule table, j'vous raconte pas l'horreur...). Du coup, histoire de tout bien séparer histoire de pouvoir appliquer des contraintes adéquates (car c'est évidemment un beau foutoir cette vieille DB), je crée un curseur sur cette table qui va donc lire les lignes une à une pour les éclater dans les tables adéquates de la DB correctement normalisée (du moins je l'espère qu'elle l'est).

    La colonne ACTION de la grosse table toute moche me permet de savoir quoi faire de la ligne en cours de lecture par le curseur. C'est d'ailleurs pour cela qu'il y a autant de IF qui se suivent dans le corps du curseur.

    Le code complet de ce que fait le curseur se trouve dans le premier message.

    Voilà en gros. Après si vous voulez, je peux expliquer chaque action mais je doute que cela vous avance à grand chose...
    Kropernic

Discussions similaires

  1. Question sur le fonctionnement des "fichiers ouverts"
    Par Lung dans le forum API, COM et SDKs
    Réponses: 9
    Dernier message: 17/03/2012, 16h28
  2. Question sur le fonctionnement des "fichiers ouverts"
    Par Lung dans le forum Windows Serveur
    Réponses: 0
    Dernier message: 08/03/2012, 09h33
  3. Question sur le fonctionnement des liste lié
    Par DeeVoiD dans le forum Ruby on Rails
    Réponses: 2
    Dernier message: 19/05/2009, 13h14
  4. Question sur le fonctionnement des sessions
    Par kuja2053 dans le forum Langage
    Réponses: 3
    Dernier message: 26/06/2007, 19h15
  5. [EJB] Question sur le fonctionnement des EJB
    Par derek.mf dans le forum Java EE
    Réponses: 9
    Dernier message: 28/03/2006, 12h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo