Most SQL statements generate rows of data called a result set (aka comsor, a COMplete Set Of Rows).
Usually a client wants this result set so he orders and gets a default result set (aka firehose "cursor") is used. The process for default result sets is like Joe calling Uno's for an order for 5-500 pizzas. The restaurant pumps the pizzas out as fast as they can and there is no additional communication between Joe and Uno's. Here is the basic process for a default record set:
Default result sets are extremely efficient. Default result sets can be used with practically all SQL statements and can even execute batches or stored procedures that generate multiple result sets.
Sometimes though, you want to do something different: like access a fraction of the entire result set or use the result set by other code on the server. In that case you may want a cursor. A cursor (aka CURrent Set Of Records) is a mechanism for accessing a row or block of rows from a result set.
The main option for a cursor is whether the data is on the client or the server.
Once the client or server option is selected, the cursor is further specified by Cursor Type or Cursor Behavior, both of which basically do the same thing.
With these definitions in hand, it is possible to say that a fire hose cursor is, in one sense, a client-side cursor that is of Cursor Type Forward-Only and has a Cursor Behavior of non-scrolling and insensitive.
The syntax for specifying a cursor is dependent on the method for making the cursor. SQL Server supports two possible methods for making cursors: via DECLARE CURSOR or via a DB API. Applications should choose one or the other but not both.
Please note that a cursor can be set to close automatically (or not) when a transaction is committed with this T-SQL syntax:
SET CURSOR_CLOSE_ON_COMMIT { ON | OFF }
There are two syntaxes to DECLARE a T-SQL variable of data type cursor, one is SQL-92 compliant, the other is a T-SQL version. The two cannot be mixed.:
DECLARE CursorName [INSENSITIVE] [SCROLL] CURSOR
FOR SelectStatement
[FOR {READ ONLY | UPDATE [OF ColumnName [, ...]]}]
DECLARE CursorName CURSOR [LOCAL | GLOBAL] [FORWARD_ONLY | SCROLL] [STATIC | KEYSET | DYNAMIC | FAST_FORWARD] [READ_ONLY | SCROLL_LOCKS | OPTIMISTIC] [TYPE_WARNING] FOR SelectStatement [FOR UPDATE [OF ColumnName [, ...]]]
There are two ways to use a variable of data type cursor in T-SQL.
DECLARE @MyVariable CURSOR DECLARE MyCursor CURSOR FOR SELECT LastName FROM Northwind.dbo.Employees SET @MyVariable = MyCursor
DECLARE @MyVariable CURSOR SET @MyVariable = CURSOR FOR SELECT LastName FROM Northwind.dbo.Employees
Here is they syntax to FETCH from a T-SQL variable of data type cursor.
FETCH
[ [NEXT | PRIOR | FIRST | LAST | ABSOLUTE {n | @nvar} | RELATIVE {n | @nvar}]
FROM
]
{{[GLOBAL] CursorName} | @CursorVariableName}
[INTO @VariableName [, ...]]
Here are how the different DB APIs fetch from cursors:
IRowset::GetNextRows, IRowsetLocate::GetRowsAt, IRowsetLocate::GetRowsAtBookmark, and IRowsetScroll::GetRowsAtRatio .SQLFetch function (which is the same as a FETCH NEXT for one row), or the SQLFetchScroll function. SQLFetchScroll supports block cursors and all the fetch options (first, last, next, prior, absolute, relative).Move, MoveFirst, MoveLast, MoveNext, and MovePrevious method of the Recordset object to acquire a position in a cursor. The GetRows recordset method is then used to retrieve one or more rows at that position. GetRows can also be called directly with the Start parameter set to the number of the row to fetch.dbcursorfetch and dbcursorfetchex functions.Here is a basic T-SQL implementation of a firehose cursor.
USE pubs GO DECLARE authors_cursor CURSOR FOR SELECT au_lname FROM authors WHERE au_lname LIKE 'D%' ORDER BY au_lname OPEN authors_cursor FETCH NEXT FROM authors_cursor WHILE @@FETCH_STATUS = 0 BEGIN FETCH NEXT FROM authors_cursor END CLOSE authors_cursor DEALLOCATE authors_cursor GO
Here is a cursor nested inside of another to make a report. This example is straight out of the MSDN Library.
SET NOCOUNT ON
DECLARE @au_id varchar(11), @au_fname varchar(20), @au_lname varchar(40),
@message varchar(80), @title varchar(80)
PRINT "-------- Utah Authors report --------"
DECLARE authors_cursor CURSOR FOR
SELECT au_id, au_fname, au_lname
FROM authors
WHERE state = "UT"
ORDER BY au_id
OPEN authors_cursor
FETCH NEXT FROM authors_cursor
INTO @au_id, @au_fname, @au_lname
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT " "
SELECT @message = "----- Books by Author: " +
@au_fname + " " + @au_lname
PRINT @message
-- Declare an inner cursor based
-- on au_id from the outer cursor.
DECLARE titles_cursor CURSOR FOR
SELECT t.title
FROM titleauthor ta, titles t
WHERE ta.title_id = t.title_id AND
ta.au_id = @au_id -- Variable value from the outer cursor
OPEN titles_cursor
FETCH NEXT FROM titles_cursor INTO @title
IF @@FETCH_STATUS <> 0
PRINT " <<No Books>>"
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @message = " " + @title
PRINT @message
FETCH NEXT FROM titles_cursor INTO @title
END
CLOSE titles_cursor
DEALLOCATE titles_cursor
-- Get the next author.
FETCH NEXT FROM authors_cursor
INTO @au_id, @au_fname, @au_lname
END
CLOSE authors_cursor
DEALLOCATE authors_cursor
GO
-------- Utah Authors report --------
----- Books by Author: Anne Ringer
The Gourmet Microwave
Is Anger the Enemy?
----- Books by Author: Albert Ringer
Is Anger the Enemy?
Life Without Fear
Page Modified: (Hand noted: 2007-10-13 15:46:21Z) (Auto noted: 2007-11-17 06:43:43Z)