OVH Cloud OVH Cloud

curseur SQL for update

2 réponses
Avatar
jcsiret
Paris, le 050106

Bonjour,

Suite =E0 un transfert b=E2cl=E9, je dois num=E9roter dans des paquets
d'enregistrements (en fait, des =E9critures comptables), les diff=E9rents
=E9l=E9ments (les articles d=E9critures) qui les composent en suivant un
certaine s=E9quence. J'ai r=E9dig=E9 pour cela la proc=E9dure stock=E9e
ci-dessous :

CREATE PROCEDURE ap_Sage_Num=E9roLignes AS

DECLARE @Ligne AS SMALLINT /* compteur de ligne d'une =E9criture */
DECLARE @Pi=E8ce AS CHAR(15) /* m=E9morisation de l'identification de
l'=E9criture pour regrouper tous ses articles */
/* ouvre un cursor aux enregistrements ordonn=E9s (format T SQL)
*/
DECLARE EcrituresLignes CURSOR LOCAL FORWARD_ONLY DYNAMIC OPTIMISTIC
FOR
SELECT S_Journal, S_DEcriture, S_NoPi=E8ce, S_CodeEcriture,
S_NoLigneEcriture
FROM dbo.S_I_Ecritures
WHERE NOT (S_NoPi=E8ce IS NULL)
ORDER BY S_Journal, S_DEcriture, S_NoPi=E8ce, S_CodeEcriture
FOR UPDATE OF S_NoLigneEcriture

SET @Pi=E8ce =3D SPACE(15)

OPEN EcrituresLignes

FETCH NEXT FROM EcrituresLignes
WHILE @@FETCH_STATUS =3D 0
BEGIN
IF 'S_NoPi=E8ce' <> @Pi=E8ce
BEGIN
SET @Pi=E8ce =3D 'S_NoPi=E8ce'
SET @Ligne =3D 1
END
ELSE
SET @Ligne =3D @Ligne + 1
UPDATE dbo.S_I_Ecritures SET S_NoLigneEcriture =3D @Ligne
WHERE CURRENT OF EcrituresLignes
FETCH NEXT FROM EcrituresLignes
END
CLOSE EcrituresLignes
DEALLOCATE EcrituresLignes
GO

.=2E. qui est jug=E9e correcte tant au sein de Entreprise Manager que de
l'analyseur de requ=EAtes. Par contre, =E0 l'ex=E9cution, je re=E7ois le
message suivant :

Serveur : Msg 16957, Niveau 16, =C9tat 4, Proc=E9dure
ap_Sage_Num=E9roLignes, Ligne 8
FOR UPDATE ne peut pas =EAtre sp=E9cifi=E9 sur un curseur READ ONLY.

.=2E. Et donc bien =E9videmment, aucune mise =E0 jour n'est effectu=E9e.

Pour information, je suis le "propri=E9taire" de la base o=F9 tout cela
se d=E9roule. Pourrait-on m'expliquer comment un curseur d=E9clar=E9
"dynamic" peut =EAtre "read only" en fait ? et comment corriger mon code
? D'avance merci.

2 réponses

Avatar
Med Bouchenafa
Tu dois être dans un cas de conversion implicite de curseur
Ces cas de conversion sont nombreux et variés.
Vérifie par exemple que tu as bien un index unique sur cette table

Verifie aussi l'état de ton curseur par sp_describe_cursor
Regarde dans l'Aide en Ligne les cas de Conversions implicites de curseurs

--
Avec mes meilleurs voeux 2006
Med Bouchenafa

a écrit dans le message de news:

Paris, le 050106

Bonjour,

Suite à un transfert bâclé, je dois numéroter dans des paquets
d'enregistrements (en fait, des écritures comptables), les différents
éléments (les articles décritures) qui les composent en suivant un
certaine séquence. J'ai rédigé pour cela la procédure stockée
ci-dessous :

CREATE PROCEDURE ap_Sage_NuméroLignes AS

DECLARE @Ligne AS SMALLINT /* compteur de ligne d'une écriture */
DECLARE @Pièce AS CHAR(15) /* mémorisation de l'identification de
l'écriture pour regrouper tous ses articles */
/* ouvre un cursor aux enregistrements ordonnés (format T SQL)
*/
DECLARE EcrituresLignes CURSOR LOCAL FORWARD_ONLY DYNAMIC OPTIMISTIC
FOR
SELECT S_Journal, S_DEcriture, S_NoPièce, S_CodeEcriture,
S_NoLigneEcriture
FROM dbo.S_I_Ecritures
WHERE NOT (S_NoPièce IS NULL)
ORDER BY S_Journal, S_DEcriture, S_NoPièce, S_CodeEcriture
FOR UPDATE OF S_NoLigneEcriture

SET @Pièce = SPACE(15)

OPEN EcrituresLignes

FETCH NEXT FROM EcrituresLignes
WHILE @@FETCH_STATUS = 0
BEGIN
IF 'S_NoPièce' <> @Pièce
BEGIN
SET @Pièce = 'S_NoPièce'
SET @Ligne = 1
END
ELSE
SET @Ligne = @Ligne + 1
UPDATE dbo.S_I_Ecritures SET S_NoLigneEcriture = @Ligne
WHERE CURRENT OF EcrituresLignes
FETCH NEXT FROM EcrituresLignes
END
CLOSE EcrituresLignes
DEALLOCATE EcrituresLignes
GO

... qui est jugée correcte tant au sein de Entreprise Manager que de
l'analyseur de requêtes. Par contre, à l'exécution, je reçois le
message suivant :

Serveur : Msg 16957, Niveau 16, État 4, Procédure
ap_Sage_NuméroLignes, Ligne 8
FOR UPDATE ne peut pas être spécifié sur un curseur READ ONLY.

... Et donc bien évidemment, aucune mise à jour n'est effectuée.

Pour information, je suis le "propriétaire" de la base où tout cela
se déroule. Pourrait-on m'expliquer comment un curseur déclaré
"dynamic" peut être "read only" en fait ? et comment corriger mon code
? D'avance merci.
Avatar
Fred BROUARD
bonjour,

si j'ai bien compris ton curseur numérote par interligne.

Quelque chose comme :

S_NoPièce S_NoLigneEcriture
----------- -------------------
AAA 1
AAA 2
AAA 3
BBB 1
BBB 2
CCC 1

?

Il est alors inutile de faire cela par un curseur parce que cela peut être fait
directement dans une requête UPDATE. Cela plus performant et transactionné.

Poste le DDL de tes tables et un jeu de données, je te monterais coment faire.

A +



--
Frédéric BROUARD, MVP SQL Server, expert bases de données et langage SQL
Le site sur le langage SQL et les SGBDR : http://sqlpro.developpez.com
Audit, conseil, expertise, formation, modélisation, tuning, optimisation
********************* http://www.datasapiens.com ***********************
a écrit:
Paris, le 050106

Bonjour,

Suite à un transfert bâclé, je dois numéroter dans des paquets
d'enregistrements (en fait, des écritures comptables), les différents
éléments (les articles décritures) qui les composent en suivant un
certaine séquence. J'ai rédigé pour cela la procédure stockée
ci-dessous :

CREATE PROCEDURE ap_Sage_NuméroLignes AS

DECLARE @Ligne AS SMALLINT /* compteur de ligne d'une écriture */
DECLARE @Pièce AS CHAR(15) /* mémorisation de l'identification de
l'écriture pour regrouper tous ses articles */
/* ouvre un cursor aux enregistrements ordonnés (format T SQL)
*/
DECLARE EcrituresLignes CURSOR LOCAL FORWARD_ONLY DYNAMIC OPTIMISTIC
FOR
SELECT S_Journal, S_DEcriture, S_NoPièce, S_CodeEcriture,
S_NoLigneEcriture
FROM dbo.S_I_Ecritures
WHERE NOT (S_NoPièce IS NULL)
ORDER BY S_Journal, S_DEcriture, S_NoPièce, S_CodeEcriture
FOR UPDATE OF S_NoLigneEcriture

SET @Pièce = SPACE(15)

OPEN EcrituresLignes

FETCH NEXT FROM EcrituresLignes
WHILE @@FETCH_STATUS = 0
BEGIN
IF 'S_NoPièce' <> @Pièce
BEGIN
SET @Pièce = 'S_NoPièce'
SET @Ligne = 1
END
ELSE
SET @Ligne = @Ligne + 1
UPDATE dbo.S_I_Ecritures SET S_NoLigneEcriture = @Ligne
WHERE CURRENT OF EcrituresLignes
FETCH NEXT FROM EcrituresLignes
END
CLOSE EcrituresLignes
DEALLOCATE EcrituresLignes
GO

... qui est jugée correcte tant au sein de Entreprise Manager que de
l'analyseur de requêtes. Par contre, à l'exécution, je reçois le
message suivant :

Serveur : Msg 16957, Niveau 16, État 4, Procédure
ap_Sage_NuméroLignes, Ligne 8
FOR UPDATE ne peut pas être spécifié sur un curseur READ ONLY.

... Et donc bien évidemment, aucune mise à jour n'est effectuée.

Pour information, je suis le "propriétaire" de la base où tout cela
se déroule. Pourrait-on m'expliquer comment un curseur déclaré
"dynamic" peut être "read only" en fait ? et comment corriger mon code
? D'avance merci.