Précédent   Forum des professionnels en informatique > Bases de données > MS SQL-Server > Développement
Développement Forum d'entraide sur le Transact-SQL, le CLR, les procédures stockées, les triggers, les requêtes SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 20/09/2011, 10h14   #1
Débutant
 
Avatar de afrodje
 
Homme Jérémy
Développeur Web
Inscription : octobre 2006
Messages : 1 094
Détails du profil
Informations personnelles :
Nom : Homme Jérémy
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : Industrie

Informations forums :
Inscription : octobre 2006
Messages : 1 094
Points : 614
Points : 614
Par défaut [Curseur] Problème de boucle

Bonjour,

J'ai suivi ce tuto pour établir le traitement ci-dessous :

Code :
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
-- Déclaration des variables
DECLARE @numero_facture int
DECLARE @statut VARCHAR(10)
DECLARE @id int
 
-- Déclaration du curseur
DECLARE curseur_facture CURSOR FOR 
SELECT id, cast(numero_facture AS INT) AS num_fact, RTRIM(statut) AS statut FROM Facture_statut_facture WHERE traiter = 0 ORDER BY numero_facture
 
-- Ouverture curseur
OPEN curseur_facture
 
FETCH NEXT FROM curseur_facture INTO @id, @numero_facture , @statut
 
-- Association curseur/variable
--FETCH curseur_facture INTO @numero_facture , @statut
 
-- Boucle
WHILE @@FETCH_STATUS = 0
BEGIN	
	-- erreur = 1
	IF @statut = 'ERR'
	BEGIN
		UPDATE dbo.Facture_entete
		SET erreur = 1
		WHERE numero_facture = @numero_facture
 
		UPDATE dbo.Facture_statut_facture
		SET traiter = 1
		WHERE id = @id
	END
 
	-- recu  = 1 + envoyé vers client = 1
	IF @statut = 'ENV'  
	BEGIN		
		UPDATE dbo.Facture_entete
		SET recu = 1, envoye_vers_client = 1
		WHERE numero_facture = @numero_facture
 
		UPDATE dbo.Facture_statut_facture
		SET traiter = 1
		WHERE id = @id
	END
 
	-- erreur_chez_client = 1
	IF @statut = 'RH2'  
	BEGIN		
		UPDATE dbo.Facture_entete
		SET erreur_chez_client = 1
		WHERE numero_facture = @numero_facture
 
		UPDATE dbo.Facture_statut_facture
		SET traiter = 1
		WHERE id = @id
	END
 
	-- recuperer par le client = 1
	IF @statut = 'REC'  
	BEGIN		
		UPDATE dbo.Facture_entete
		SET recuperer_par_client = 1
		WHERE numero_facture = @numero_facture
 
		UPDATE dbo.Facture_statut_facture
		SET traiter = 1
		WHERE id = @id
	END
 
	-- Ligne suivante
	FETCH NEXT FROM curseur_facture
 
END
 
CLOSE curseur_facture
DEALLOCATE curseur_facture
Mon problème est que, dans mon curseur curseur_facture j'ai 10 lignes par exemple, il faut que le traitement s’exécute 10 fois avant d'être tout traiter.
Alors qu'avec le WHILE @@FETCH_STATUS = 0, une seule exécution suffit normalement...

Merci.
__________________
Évènements dans le 06?
www.sortir06.com
afrodje est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 10h21   #2
Membre Expert
 
Homme Sylvain Devidal
Chef de projets Générix
Inscription : février 2010
Messages : 1 062
Détails du profil
Informations personnelles :
Nom : Homme Sylvain Devidal
Âge : 33
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Chef de projets Générix
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : février 2010
Messages : 1 062
Points : 1 515
Points : 1 515
Normal, tu traîtes 10 fois de suite la première facrture.

Dans ton "fetch next" qui se trouve à la fin de ton code, met bien le "into".
=> Là, il ne fait que consommer une ligne dans le curseur, sans rien faire des données : donc tu refais le même traitement.

En remettant le INTO variables, tu recopies les données du curseur dans les variables, pour traiter ces nouvelles variables dans l'ittération suivante.
StringBuilder est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 11h05   #3
Débutant
 
Avatar de afrodje
 
Homme Jérémy
Développeur Web
Inscription : octobre 2006
Messages : 1 094
Détails du profil
Informations personnelles :
Nom : Homme Jérémy
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : Industrie

Informations forums :
Inscription : octobre 2006
Messages : 1 094
Points : 614
Points : 614
Citation:
Envoyé par StringBuilder Voir le message
Normal, tu traîtes 10 fois de suite la première facrture.

Dans ton "fetch next" qui se trouve à la fin de ton code, met bien le "into".
=> Là, il ne fait que consommer une ligne dans le curseur, sans rien faire des données : donc tu refais le même traitement.

En remettant le INTO variables, tu recopies les données du curseur dans les variables, pour traiter ces nouvelles variables dans l'ittération suivante.
Merci, j'ignorai ce paramètre
__________________
Évènements dans le 06?
www.sortir06.com
afrodje est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 19h24   #4
Modérateur

 
Avatar de elsuket
 
Homme Nicolas Souquet
Administrateur de base de données
Inscription : janvier 2005
Messages : 4 669
Détails du profil
Informations personnelles :
Nom : Homme Nicolas Souquet
Âge : 30
Localisation : Thaïlande

Informations professionnelles :
Activité : Administrateur de base de données
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : janvier 2005
Messages : 4 669
Points : 8 729
Points : 8 729
Bonjour,

Cela étant, il n'est ici nul besoin de curseur, comme bien souvent :

Code :
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
DECLARE @err_msg nvarchar(2048)
 
BEGIN TRY
	BEGIN TRANSACTION
 
	;WITH
		CTE AS
		(
			SELECT	CAST(numero_facture AS int) AS num_fact
				, RTRIM(statut) AS statut
			FROM	dbo.Facture_statut_facture
			WHERE	traiter = 0
		)
	UPDATE		dbo.Facture_entete
	SET		erreur = CASE C.statut WHEN 'ERR' THEN 1 ELSE erreur END
			, recu = CASE C.statut WHEN 'ENV' THEN 1 ELSE recu END
			, envoye_vers_client = CASE C.statut WHEN 'ENV' THEN 1 ELSE envoye_vers_client END
			, erreur_chez_client = CASE C.statut WHEN 'RH2' THEN 1 ELSE erreur_chez_client END
			, recuperer_par_client = CASE C.statut WHEN 'REC' THEN 1 ELSE recuperer_par_client END
	FROM		dbo.Facture_entete AS FE
	INNER JOIN	CTE AS C
				ON FE.numero_facture = C.num_fact
	;WITH
		CTE AS
		(
			SELECT	id
			FROM	dbo.Facture_statut_facture
			WHERE	traiter = 0
		)
	UPDATE		dbo.Facture_statut_facture
	SET		traiter = 1
	FROM		dbo.Facture_statut_facture AS FSF
	INNER JOIN	CTE AS C
				ON C.id = FSF.id
 
	COMMIT TRANSACTION
END TRY
BEGIN CATCH
	SET @err_msg = ERROR_MESSAGE()
 
	IF XACT_STATE() = 0
	BEGIN
		COMMIT TRANSACTION
	END
	ELSE
	BEGIN
		ROLLBACK TRANSACTION
 
		RAISERROR('%s', 16, 1, @err_msg)
	END	
END CATCH
Ce qui s'exécutera bien plus vite qu'avec le curseur.
N'oubliez pas que SQL est un langage ensembliste, et que par conséquent il est conçu pour traiter les données dans leur ensemble, et non dans leur unité comme vous le faites.

Enfin SQL est aussi un langage déclaratif : vous décrivez le résultat que vous souhaitez obtenir, mais pas la façon dont vous souhaitez l'obtenir, comme on le fait dans un langage fonctionnel.

@++
__________________
En bases de données relationnelles SQL, il n'y a ni tableaux, ni enregistrements, ni champs: il y a des tables, des lignes et des colonnes.
Blog | Profil| Consulter ou télécharger les fichiers d'aide de SQL Server, des versions 2000 à 2012
elsuket est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 22/09/2011, 08h03   #5
Débutant
 
Avatar de afrodje
 
Homme Jérémy
Développeur Web
Inscription : octobre 2006
Messages : 1 094
Détails du profil
Informations personnelles :
Nom : Homme Jérémy
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : Industrie

Informations forums :
Inscription : octobre 2006
Messages : 1 094
Points : 614
Points : 614
Citation:
Envoyé par elsuket Voir le message
Bonjour,

Cela étant, il n'est ici nul besoin de curseur, comme bien souvent :

Code :
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
DECLARE @err_msg nvarchar(2048)
 
BEGIN TRY
	BEGIN TRANSACTION
 
	;WITH
		CTE AS
		(
			SELECT	CAST(numero_facture AS int) AS num_fact
				, RTRIM(statut) AS statut
			FROM	dbo.Facture_statut_facture
			WHERE	traiter = 0
		)
	UPDATE		dbo.Facture_entete
	SET		erreur = CASE C.statut WHEN 'ERR' THEN 1 ELSE erreur END
			, recu = CASE C.statut WHEN 'ENV' THEN 1 ELSE recu END
			, envoye_vers_client = CASE C.statut WHEN 'ENV' THEN 1 ELSE envoye_vers_client END
			, erreur_chez_client = CASE C.statut WHEN 'RH2' THEN 1 ELSE erreur_chez_client END
			, recuperer_par_client = CASE C.statut WHEN 'REC' THEN 1 ELSE recuperer_par_client END
	FROM		dbo.Facture_entete AS FE
	INNER JOIN	CTE AS C
				ON FE.numero_facture = C.num_fact
	;WITH
		CTE AS
		(
			SELECT	id
			FROM	dbo.Facture_statut_facture
			WHERE	traiter = 0
		)
	UPDATE		dbo.Facture_statut_facture
	SET		traiter = 1
	FROM		dbo.Facture_statut_facture AS FSF
	INNER JOIN	CTE AS C
				ON C.id = FSF.id
 
	COMMIT TRANSACTION
END TRY
BEGIN CATCH
	SET @err_msg = ERROR_MESSAGE()
 
	IF XACT_STATE() = 0
	BEGIN
		COMMIT TRANSACTION
	END
	ELSE
	BEGIN
		ROLLBACK TRANSACTION
 
		RAISERROR('%s', 16, 1, @err_msg)
	END	
END CATCH
Ce qui s'exécutera bien plus vite qu'avec le curseur.
N'oubliez pas que SQL est un langage ensembliste, et que par conséquent il est conçu pour traiter les données dans leur ensemble, et non dans leur unité comme vous le faites.

Enfin SQL est aussi un langage déclaratif : vous décrivez le résultat que vous souhaitez obtenir, mais pas la façon dont vous souhaitez l'obtenir, comme on le fait dans un langage fonctionnel.

@++
Certes, plus complexe aussi que les curseurs...
Je me pencherai dessus.

Merci
__________________
Évènements dans le 06?
www.sortir06.com
afrodje est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/09/2011, 15h44   #6
Modérateur

 
Avatar de elsuket
 
Homme Nicolas Souquet
Administrateur de base de données
Inscription : janvier 2005
Messages : 4 669
Détails du profil
Informations personnelles :
Nom : Homme Nicolas Souquet
Âge : 30
Localisation : Thaïlande

Informations professionnelles :
Activité : Administrateur de base de données
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : janvier 2005
Messages : 4 669
Points : 8 729
Points : 8 729
Citation:
Certes, plus complexe aussi que les curseurs...
Non, vous avez 6 UPDATE avec un test à chaque fois, et pour chaque ligne.
J'ai deux instructions sans test et une meilleure gestion de la transaction.
A vous de voir, mais pour moi y'a pas photo

@++
__________________
En bases de données relationnelles SQL, il n'y a ni tableaux, ni enregistrements, ni champs: il y a des tables, des lignes et des colonnes.
Blog | Profil| Consulter ou télécharger les fichiers d'aide de SQL Server, des versions 2000 à 2012
elsuket est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 03h29.


 
 
 
 
Partenaires

Hébergement Web