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 :

Utilisation des curseurs et des boucles


Sujet :

Développement SQL Server

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre expérimenté
    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 : 42
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut Utilisation des curseurs et des boucles
    Bonjour à tous,

    Je ne sais pas trop comment présenté le problème de manière claire et concise donc je vais rentrer directement dans le vif du sujet ^^.

    Actuellement, il existe une base de donnée nommée GIFTCARD et qui contient cette table :

    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
    USE [GIFTCARD]
    GO
    /****** Object:  Table [dbo].[ChequeAchatHistory]    Script Date: 07/01/2011 10:12:38 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_PADDING ON
    GO
    CREATE TABLE [dbo].[ChequeAchatHistory](
    	[SeqNrHist] [int] IDENTITY(1,1) NOT NULL,
    	[BarcodeMin] [varchar](13) COLLATE Latin1_General_CI_AS NOT NULL,
    	[BarcodeMax] [varchar](13) COLLATE Latin1_General_CI_AS NOT NULL,
    	[DatTim] [datetime] NOT NULL,
    	[Action] [varchar](1) COLLATE Latin1_General_CI_AS NOT NULL,
    	[Origin] [int] NULL,
    	[DestType] [int] NULL,
    	[Dest] [int] NULL,
    	[Value] [int] NULL,
    	[SaleType] [int] NULL,
    	[UserType] [int] NULL
    ) ON [PRIMARY]
     
    GO
    SET ANSI_PADDING OFF
    Comme vous l'aurez probablement compris, cette table contient l'historique de toutes les transactions concernant des bons d'achat ou des giftcards. Ces bons/cartes étant souvent vendues par lot, l'auteur de la table a jugé bon (probablement à raison) d'écrire un record par lot plutôt que par bon/carte. Lors de la vente d'un lot, comme les barcodes se suivent, il écrit donc le premier (barcodemin) et le dernier (barcodemax).

    Et jusqu'ici, aucun souci.

    Maintenant, pour une demande particulière, j'ai besoin d'avoir un record par bon/carte.
    J'ai donc créé une DB de test qui contient la table suivante :

    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
    USE [test]
    GO
    /****** Object:  Table [dbo].[tbTest]    Script Date: 07/01/2011 10:17:18 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_PADDING ON
    GO
    CREATE TABLE [dbo].[tbTest](
    	[id] [bigint] IDENTITY(1,1) NOT NULL,
    	[type] [char](5) COLLATE Latin1_General_CI_AS NULL,
    	[barcode] [bigint] NOT NULL,
    	[date] [datetime] NOT NULL,
    	[action] [char](1) COLLATE Latin1_General_CI_AS NULL,
    	[origine] [int] NULL,
    	[destType] [int] NULL,
    	[dest] [int] NULL,
    	[valeur] [int] NULL,
    	[saleType] [int] NULL,
    	[userType] [int] NULL,
     CONSTRAINT [PK_tbTest] PRIMARY KEY CLUSTERED 
    (
    	[id] ASC
    )WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
    ) ON [PRIMARY]
     
    GO
    SET ANSI_PADDING OFF
    En gros, il s'agit de la même que précédement à ceci près que la colonne type reprend en fait les 5 premiers digits du barcode et la colonne barcode (le nom est probablement mal choisi) reprend les 7 digits restant (le checkdigit n'étant pas renseigné).


    Sur base d'exemples trouvés sur divers forum et sur le site de MSDN, j'ai écrit le code suivant :

    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
     
    declare @strmin as char(12), @strmax as char(12), @date as datetime, @action as char(1), @origine as int, @destinationType as int, 
    		@destination as int, @valeur as int, @sale as int, @user as int, @minimum as bigint, @maximum as bigint
     
    DECLARE GiftCard_Cursor CURSOR FOR
    SELECT barcodemin, barcodemax, dattim, action, origin, desttype, dest, value, saletype, usertype
    FROM GIFTCARD.dbo.chequeachathistory
    WHERE barcodemin like '24501%';
    OPEN GiftCard_Cursor;
    FETCH NEXT FROM GiftCard_Cursor
    INTO @strmin, @strmax, @date, @action, @origine, @destinationtype, @destination, @valeur, @sale, @user;
     
    set @minimum = cast(substring(@strmin,6,7) as bigint);
    set @maximum = cast(substring(@strmax,6,7) as bigint);
     
    while not (@minimum = @maximum)
    	begin
    	insert into test.dbo.tbTest values('24501',@minimum, @date, @action, @origine, @destinationtype, @destination, @valeur, @sale, @user);
     
    	set @minimum = @minimum+1;
    	end
     
     
    CLOSE GiftCard_Cursor;
    DEALLOCATE GiftCard_Cursor;
    GO
    Il ne m'affiche aucune erreur et lorsque je l'exécute, j'ai bien le message m'informant que la commande a bien été exécutée mais la table tbTest reste invariablement vide.

    Je dois bien avouer que c'est la première fois que j'utilise ce genre d'instruction dans sql server. Mes actions se limitent en général à des requêtes classiques.

    Pourriez-vous donc m'aider à débugger ce bout de code afin que je puisse alimenter ma table tbTest ?

    Voilà, j'espère avoir données toutes les informations nécessaires.

    Merci d'avance,

    Griftou.

  2. #2
    Membre expérimenté
    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 : 42
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Bon, ça m'apprendra à faire des trucs sans trop comprendre le pourquoi du comment...

    En approfondissant, je me suis rendu compte que mon curseur ne lisait que la première ligne de la requête de sélection.

    J'ai modifié comme ci-dessous et ça a l'air de fonctionné.

    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
    declare @strmin as char(12), @strmax as char(12), @date as datetime, @action as char(1), @origine as int, @destinationType as int, 
    		@destination as int, @valeur as int, @sale as int, @user as int, @minimum as bigint, @maximum as bigint
     
    DECLARE GiftCard_Cursor CURSOR FOR
    SELECT barcodemin, barcodemax, dattim, action, origin, desttype, dest, value, saletype, usertype
    FROM GIFTCARD.dbo.chequeachathistory
    WHERE barcodemin like '24501%';
    OPEN GiftCard_Cursor;
    FETCH NEXT FROM GiftCard_Cursor
    INTO @strmin, @strmax, @date, @action, @origine, @destinationtype, @destination, @valeur, @sale, @user;
     
    while @@FETCH_STATUS = 0
    begin
     
    set @minimum = cast(substring(@strmin,6,7) as bigint);
    set @maximum = cast(substring(@strmax,6,7) as bigint)+1;
    while not (@minimum = @maximum)
    	begin
    	insert into test.dbo.tbTest values('24501',@minimum, @date, @action, @origine, @destinationtype, @destination, @valeur, @sale, @user);
     
    	set @minimum = @minimum+1;
    	end
    FETCH NEXT FROM GiftCard_Cursor
    INTO @strmin, @strmax, @date, @action, @origine, @destinationtype, @destination, @valeur, @sale, @user;
    end;
     
    CLOSE GiftCard_Cursor;
    DEALLOCATE GiftCard_Cursor;
    GO
    Je dois juste encore vérifier si les données sont cohérentes.

  3. #3
    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
    Par défaut
    Bonjour


    Il serait plus simple de vous passer de votre curseur et de votre boucle. Ce serait en outre plus performant.

    Il vous suffit pour cela de créer (ou générer à la volée) une table de nombres couvrant l'ensemble de vos barcode, et de faire un jointure dessus

  4. #4
    Membre Expert

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2007
    Messages
    1 216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Suisse

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Août 2007
    Messages : 1 216
    Par défaut
    Lorsque vous dites pour une demande particuliere, est ce que cette demande concerne l'historique aussi ?

    Si oui, je vous suggererais d'utiliser une CTE recursive pour generer vos barcodes.

    Concernant la creation d'une nouvelle table, est ce que l'impact est limite ?
    Sinon une idee serait de fixer barcode min = barcode max et de reutiliser la meme table, ce qui pourrait a mon sens eviter trop de changement colateraux (apres ca depend de votre temps et de l'impact potentiel).

    Suite a cela, vous pourrez supprimer vos rows ou barcode min est different de barcode max - pour autant qu'il n'y ai pas eu de lot de 1 vendu. A verifier.

  5. #5
    Membre expérimenté
    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 : 42
    Localisation : Belgique

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

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

    Déjà, merci de vous intéresser à mon problème :-)

    Par contre, il faut savoir que je suis plutôt débutant. Du coup, même si je vois ce qu'est une CTE et si j'en ai déjà utilisé une fois ou deux, je ne vois pas comment l'utiliser pour le cas qui m'occupe.

    Il vous suffit pour cela de créer (ou générer à la volée) une table de nombres couvrant l'ensemble de vos barcode, et de faire un jointure dessus
    Comment faites-vous cela ?

    Concernant la creation d'une nouvelle table, est ce que l'impact est limite ?
    Sinon une idee serait de fixer barcode min = barcode max et de reutiliser la meme table, ce qui pourrait a mon sens eviter trop de changement colateraux (apres ca depend de votre temps et de l'impact potentiel).
    Je ne comprends pas vraiment la question :-/



    Au passage, le code que j'avais posté ne portait que sur un type de bons/cartes (ceux dont le barcode commence par 24501) et me servait de test. Avec ce code, pas de souci. Par contre après, j'ai donc retiré cette restriction. Tout avait l'air de bien fonctionner jusqu'à un moment où le script continuait de tourner mais plus aucun nouveau messages "1 row(s) affected" n'apparaissait. Est-ce un bug dans mon script ou bien l'onglet message de management studio à une limite de ligne qu'il ne peut dépasser ?

  6. #6
    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
    Par défaut
    non, je pense surtout que vous entrez dans une boucle infinie car vous ne reinitialisez pas @minimum et @maximum entre deux produits.
    Tel que vous le faites, il vous faudrait donc deux boucles :

    Celle que vous aviez dans votre premier post, englobée dans une autre boucle qui fait le fetch et l'initialisation de @minimum et @maximum pour chaque chequeAchat
    Pour être plus clair, une boucle pour chaque ligne de la table source, dans laquelle vous avez une boucle pour chaque ligne insérée dans la table cible.

    pour la génération de la table des nombres, je reviens vers vous avec un exemple que je vous laisserai adapter...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Utiliser JOGL + shader pour des effets sur des images 2D.
    Par nouknouk dans le forum Développement 2D, 3D et Jeux
    Réponses: 2
    Dernier message: 19/12/2007, 10h46
  2. Utiliser des curseurs et des menus popup spéciaux
    Par randriano dans le forum Delphi
    Réponses: 3
    Dernier message: 05/04/2007, 13h04
  3. Réponses: 3
    Dernier message: 23/01/2007, 08h14
  4. Utilisation du Enable avec des combobox ou des listbox
    Par legos dans le forum VB 6 et antérieur
    Réponses: 16
    Dernier message: 19/09/2006, 22h35
  5. Réponses: 2
    Dernier message: 27/04/2006, 16h45

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