Le curseur statique ne permet pas de modifier les données car il est en lecture seule, et lorsqu'il est exécuté avec "où le courant de", il renvoie une erreur comme prévu. Jusqu'ici tout va bien. Mais j'ai été surpris de constater que le curseur statique permet de modifier des données avec une variable comme celle-ci.
DECLARE @nome varchar(100), @salario int,@idemp int
DECLARE contact_cursor CURSOR STATIC FOR
SELECT empno,ename, sal FROM emp
OPEN contact_cursor;
FETCH NEXT from contact_cursor into @idemp,@nome, @salario
WHILE @@FETCH_STATUS=0
BEGIN
If @salario < 5000
Update Emp
Set Sal = Sal * 1.1
where empno=@idemp --No error and do the update
--Where current of contact_cursor; --gives error
print @nome+' '+cast(@salario as varchar(100));
</ code>
Extrait de contact_cursor dans @ idemp, @ nome, @salario [.____] fin Fermer contact_cursor; OffreLocate Contact_cursor;
La principale différence semble être la manière dont chaque approche trouve la ligne à mettre à jour. Le curseur STATIC
Curseur copie le résultat complet défini sur une table temporaire cachée en premier (par conséquent, il est en lecture seule), donc cela serait semble Pour être moins efficace pour être moins efficace Re-interrogez la table principale pour chaque UPDATE
. Cependant, la mise à jour positionnée semble avoir beaucoup plus de lecture logique et d'opérations. Toutefois, un avantage de la mise à jour positionnée est noté dans la page MSDN pour - [~ # ~] [~ # ~ # ~] :
Courant de
Spécifie que la mise à jour est effectuée à la position actuelle du curseur spécifié.
Une mise à jour positionnée utilisant un courant de la clause met à jour la ligne unique à la position actuelle du curseur. Cela peut être plus précis qu'une mise à jour recherchée qui utilise une clause où la clause permettait de qualifier les lignes à mettre à jour. Une mise à jour recherchée modifie plusieurs lignes lorsque la condition de recherche n'identifie pas de manière unique une seule ligne.
Configuration du test
SET NOCOUNT ON;
-- DROP TABLE ##CursorTest;
CREATE TABLE ##CursorTest ([ID] INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
[Val] INT NOT NULL);
INSERT INTO ##CursorTest ([Val]) VALUES (1), (1), (1), (1);
curseur mis à jour et WHERE CURRENT OF
UPDATE ##CursorTest SET [Val] = 1;
SELECT * FROM ##CursorTest;
SET STATISTICS IO ON;
DECLARE curTest CURSOR TYPE_WARNING
LOCAL
FORWARD_ONLY
KEYSET -- removing only reduces logical reads by 4
SCROLL_LOCKS
--OPTIMISTIC
FOR
SELECT [ID] FROM ##CursorTest WHERE [Val] < 5
FOR UPDATE OF [Val];
DECLARE @ID INT;
OPEN curTest;
FETCH NEXT
FROM curTest
INTO @ID;
WHILE (@@FETCH_STATUS = 0)
BEGIN
UPDATE tmp
SET tmp.[Val] = tmp.[Val] + 2
FROM ##CursorTest tmp
WHERE CURRENT OF curTest;
FETCH NEXT
FROM curTest
INTO @ID;
END;
CLOSE curTest;
DEALLOCATE curTest;
SET STATISTICS IO OFF;
SELECT * FROM ##CursorTest;
Résultats:
Table 'Worktable'. Scan count 0, logical reads 8
Table '##CursorTest'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 1, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 0
Table 'Worktable'. Scan count 1, logical reads 2
Suppression de l'option KEYSET
a réduit les lectures logiques de 4 (je crois), mais ce n'est peut-être pas une épargne sur une requête plus compliquée, éventuellement avec des jointures.
En outre, commutation SCROLL_LOCKS
Pour être OPTIMISTIC
Augmentation des lectures logiques.
STATIC
curseur et standard UPDATE
UPDATE ##CursorTest SET [Val] = 1;
SELECT * FROM ##CursorTest;
SET STATISTICS IO ON;
DECLARE curTest CURSOR TYPE_WARNING
LOCAL
FORWARD_ONLY
STATIC
OPTIMISTIC
FOR
SELECT [ID] FROM ##CursorTest WHERE [Val] < 5;
DECLARE @ID INT;
OPEN curTest;
FETCH NEXT
FROM curTest
INTO @ID;
WHILE (@@FETCH_STATUS = 0)
BEGIN
UPDATE tmp
SET tmp.[Val] = tmp.[Val] + 2
FROM ##CursorTest tmp
WHERE tmp.[ID] = @ID;
FETCH NEXT
FROM curTest
INTO @ID;
END;
CLOSE curTest;
DEALLOCATE curTest;
SET STATISTICS IO OFF;
SELECT * FROM ##CursorTest;
Résultats:
Table 'Worktable'. Scan count 0, logical reads 8
Table '##CursorTest'. Scan count 1, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Table '##CursorTest'. Scan count 0, logical reads 2
Table 'Worktable'. Scan count 0, logical reads 2
Ces tests simples semblent montrer le curseur STATIC
_ UPDATE
étant la meilleure option, et une requête plus compliquée pour le curseur pourrait être une différence encore plus grande (en supposant que vous puissiez mettre à jour en fonction de la clé en cluster de la table cible).
Mais, si vous avez une situation où vous ne pouvez pas réduire à une rangée individuelle/n'a pas de valeur clé à utiliser, la mise à jour positionnée serait tout à fait pratique.
Pour mieux comprendre ce comportement de mise à jour, nous devrons peut-être regarder [~ # ~ #] update [~ # ~] Syntaxe, il indique:
Du courant de
Spécifie que la mise à jour est effectuée à la position actuelle du curseur spécifié.
Une mise à jour positionnée utilisant un courant de la clause met à jour la ligne unique à la position actuelle du curseur. Cela peut être plus précis qu'une mise à jour recherchée qui utilise une clause où la clause permettait de qualifier les lignes à mettre à jour. Une mise à jour recherchée modifie plusieurs lignes lorsque la condition de recherche n'identifie pas de manière unique une seule ligne.
Cela signifie donc si vous utilisez "Courant de", c'est une mise à jour sur le curseur spécifié et avec un curseur statique (qui est en lecture seule), Nous obtiendrons l'erreur que vous avez postée.
Cependant, lorsque vous êtes non en utilisant un "courant de", vous effectuez la mise à jour de la table sous-jacente directement, ce qui n'a rien à voir avec Le curseur spécifié n'a donc pas de problème si le curseur est réadien ou non.
Aussi selon la définition du curseur statique sur MSDN
STATIQUE
Définit un curseur qui fait une copie temporaire des données à utiliser par le curseur. Toutes les demandes au curseur sont traitées de cette table temporaire dans TEMPDB; Par conséquent, les modifications apportées aux tables de base ne sont pas reflétées dans les données renvoyées par des extraçons apportées à ce curseur et ce curseur n'autorise pas les modifications.
Donc, dans ce contexte, lorsque vous effectuez des mises à jour de la table sous-jacente de ce curseur statique, les modifications ne seront pas reflétées sur le curseur (c'est-à-dire la table temporaire qui représente le curseur).
Si je peux faire un résumé rapide logique (à ma propre compréhension)
Lorsque vous créez un curseur statique, une table de temporisation dans [TEMPDB] est créée et cette table TEMP est en lecture seule, ce qui signifie que vous ne pouvez pas utiliser le courant de référence pour vous reporter à cette table TEMP et effectuer des mises à jour.
Mais vous pouvez faire ce que vous voulez faire à la table sous-jacente (pour ce curseur statique)