2. Transact SQL Extensions
• Database cursor is a control structure that enables traversal over the
records in a database. Cursors facilitate subsequent processing in
conjunction with the traversal, such as retrieval, addition and removal
of database records.
• The database cursor characteristic of traversal makes cursors akin to
the programming language concept of iterator.
• Cursors are used by database programmers to process individual
rows returned by database system queries.
• In SQL procedures, a cursor makes it possible to define a result set (a
set of data rows) and perform complex logic on a row by row basis.
• A cursor can be viewed as a pointer to one row in a set of rows. The
cursor can only reference one row at a time, but can move to other
rows of the result set as needed.
3. Using of Cursors
To use cursors in SQL procedures, you need to do the following:
• Declare a cursor that defines a result set.
• Open the cursor to establish the result set.
• Fetch the data into local variables as needed from the
cursor, one row at a time.
• Close the cursor when done.
• Deallocate the cursor to freeup resources.
4. Declaring Cursor
DECLARE <cursor_name> CURSOR
[ LOCAL | GLOBAL ]
[ FORWARD_ONLY | SCROLL ]
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
[ TYPE_WARNING ]
FOR <select_statement>
[ FOR UPDATE [ OF <column_name> [ ,...n ] ] ]
5. Declaring Cursor: scope properties
LOCAL - Specifies that the scope of the cursor is local to the batch, stored
procedure, or trigger in which the cursor was created. The cursor name
is only valid within this scope. The cursor can be referenced by local
cursor variables in the batch, stored procedure, or trigger, or a stored
procedure OUTPUT parameter. The cursor is implicitly deallocated when
the batch, stored procedure, or trigger terminates, unless the cursor
was passed back in an OUTPUT parameter.
GLOBAL - Specifies that the scope of the cursor is global to the connection.
(This is the default.) The cursor name can be referenced in any stored
procedure or batch executed by the connection. The cursor is only
implicitly deallocated at disconnect.
6. Declaring Cursor: scrollability properties
FORWARD_ONLY - Specifies that the cursor can only be scrolled from the
first to the last row. FETCH NEXT is the only supported fetch option.
SCROLL - Specifies that the cursor can be scrolled in any direction. The
fetch options become:
NEXT
PRIOR
FIRST
LAST
7. Declaring Cursor: types of cursors 1
STATIC - Defines a cursor that makes a temporary copy of the data to be used
by the cursor. All requests to the cursor are answered from this temporary
table in tempdb; therefore, modifications made to base tables are not
reflected in the data returned by fetches made to this cursor, and this
cursor does not allow modifications. This is not a very useful cursor…
KEYSET - Specifies that the membership and order of rows in the cursor are
fixed when the cursor is opened. The set of keys that uniquely identify the
rows is built into a table in tempdb known as the keyset. Changes to
nonkey values in the base tables, either made by the cursor owner or
committed by other users, are visible as the owner scrolls around the
cursor. Inserts made by other users are not visible (inserts cannot be made
through a Transact-SQL server cursor). If a row is deleted, an attempt to
fetch the row returns an @@FETCH_STATUS of -2. Keyset cursors are
useful as the basis for a cursor that will perform updates to the data. You
must have a unique index on the table from which you take your data.
8. Declaring Cursor: types of cursors 2
DYNAMIC - Defines a cursor that reflects all data changes made to the
rows in its result set as you scroll around the cursor. The data values,
order, and membership of the rows can change on each fetch. The
ABSOLUTE fetch option is not supported with dynamic cursors. These
are overhead hogs… it is best to avoid them, since they have to re-
query the table on every FETCH.
FAST_FORWARD - Specifies a FORWARD_ONLY, READ_ONLY cursor with
performance optimizations enabled. FAST_FORWARD cannot be
specified if SCROLL or FOR_UPDATE is also specified.
FAST_FORWARD and FORWARD_ONLY are mutually exclusive; if one
is specified the other cannot be specified.
9. Declaring Cursor: concurrency options
READ_ONLY - Prevents updates made through this cursor. The cursor cannot
be referenced in a WHERE CURRENT OF clause in an UPDATE or DELETE
statement. This option overrides the default capability of a cursor to be
updated.
SCROLL_LOCKS - Specifies that positioned updates or deletes made through
the cursor are guaranteed to succeed. SQL Server locks the rows as they
are read into the cursor to ensure their availability for later modifications.
SCROLL_LOCKS cannot be specified if FAST_FORWARD is also specified.
OPTIMISTIC - Specifies that positioned updates or deletes made through the
cursor do not succeed if the row has been updated since it was read into
the cursor. SQL Server does not lock rows as they are read into the cursor.
It instead uses comparisons of timestamp column values, or a checksum
value if the table has no timestamp column, to determine whether the row
was modified after it was read into the cursor. If the row was modified, the
attempted positioned update or delete fails. OPTIMISTIC cannot be
specified if FAST_FORWARD is also specified.
10. Declaring Cursor: FOR clause
<select_statement> - Is a standard SELECT statement that defines
the result set of the cursor. The keywords COMPUTE, COMPUTE
BY, FOR BROWSE, and INTO are not allowed within
select_statement of a cursor declaration. SQL Server implicitly
converts the cursor to another type if clauses in select_statement
conflict with the functionality of the requested cursor type.
UPDATE [OF column_name [,...n]] - Defines updatable columns
within the cursor. If OF <column_name> [,...n] is supplied, only
the columns listed allow modifications. If UPDATE is specified
without a column list, all columns can be updated, unless the
READ_ONLY concurrency option was specified. This is used to
restrict what columns may be updated. If this clause is omitted,
all columns in the <select_statement> may be updated.
11. The FETCH Statement
FETCH retrieves a specific row from a Transact-SQL server cursor.
FETCH
[ [ NEXT | PRIOR | FIRST | LAST
| ABSOLUTE { n | @nvar }
| RELATIVE { n | @nvar }
]
FROM
]
{ { [ GLOBAL ] cursor_name } | @cursor_variable_name }
[ INTO @variable_name [ ,...n ] ]
12. FETCH Arguments 1
NEXT - Returns the result row immediately following the current row,
and increments the current row to the row returned. If FETCH NEXT is
the first fetch against a cursor, it returns the first row in the result
set. NEXT is the default cursor fetch option.
PRIOR - Returns the result row immediately preceding the current row,
and decrements the current row to the row returned. If FETCH PRIOR
is the first fetch against a cursor, no row is returned and the cursor is
left positioned before the first row.
FIRST - Returns the first row in the cursor and makes it the current row.
13. FETCH Arguments 2
LAST - Returns the last row in the cursor and makes it the current row.
ABSOLUTE {n | @nvar} - If n or @nvar is positive, returns the row n rows from
the front of the cursor and makes the returned row the new current row. If n
or @nvar is negative, returns the row n rows before the end of the cursor and
makes the returned row the new current row. If n or @nvar is 0, no rows are
returned.
RELATIVE {n | @nvar} - If n or @nvar is positive, returns the row n rows beyond
the current row and makes the returned row the new current row. If n or
@nvar is negative, returns the row n rows prior to the current row and makes
the returned row the new current row. If n or @nvar is 0, returns the current
row.
GLOBAL - Specifies that cursor_name refers to a global cursor.
14. Example
DECLARE @TableName AS varchar(255)
--declaring cursor
DECLARE TableCursor CURSOR FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE'
--opening cursor
OPEN TableCursor
15. ...cont
--fetching data from cursor
FETCH NEXT FROM TableCursor INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Reindexing ' + @TableName
DBCC REINDEX(@TableName)
FETCH NEXT FROM TableCursor INTO @TableName
END
--closing and deallocating cursor
CLOSE TableCursor
DEALLOCATE TableCursor
16. Altering Data with a Cursor
Can alter or delete data in a table underlying a cursor by using
UPDATE or DELETE on the cursor with the WHERE CURRENT OF
statement (still use the select statement in the cursor
declaration). These are called positioned updates or deletes.
-- declaring the cursor…
DECLARE OrdersCursor CURSOR
FOR SELECT OrderID, CustomerID, OrderDate FROM Orders
WHERE OrderID < 10260 FOR UPDATE OF CustomerID
17. ...cont
-- an example of statements to perform a positioned update or
delete inside the processing loop
DELETE Orders WHERE CURRENT OF OrdersCursor
UDPATE Orders SET ShipVia=2 WHERE CURRENT OF
OrdersCursor
-- an example of declaring the cursor to restrict updates to the
CustomerID field only
DECLARE OrdersCursor CURSOR
FOR SELECT OrderID, CustomerID, OrderDate FROM Orders
WHERE OrderID < 10260 FOR UPDATE OF CustomerID