Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 71 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
71
Dung lượng
646,7 KB
Nội dung
Microsoft SQL Server 2000 Programming by Example 482 FROM Categories ORDER BY CategoryName ASC Open the cursor OPEN MyCategories Fetch the first row FETCH NEXT FROM MyCategories Close the cursor CLOSE MyCategories Deallocate the cursor DEALLOCATE MyCategories Cursor created was not of the requested type. CategoryID CategoryName Description 1 Beverages Soft drinks, coffees, teas, beers, and ales The cursor must be defined for a SELECT statement. This is a normal SELECT statement with a few exceptions. You cannot use COMPUTE, COMPUTE BY, FOR BROWSE, or INTO in a SELECT statement that defines a cursor. Caution If the SELECT statement produces a result set that is not updatable, the cursor will be READ_ONLY. This can happen because of the use of aggregate functions, insufficient permissions, or retrieving read-only data. You can restrict the columns to update inside the cursor using the FOR UPDATE clause, as shown in Listing 12.15. This clause can be used in two ways: • FOR UPDATE OF Column1, , ColumnN—Use this option to define columns Column1 to ColumnN as updatable through the cursor. • FOR UPDATE—This is the default option, and it declares all the cursor columns as updatable. Listing 12.15 Using the FOR UPDATE Clause Chapter 12. Row-Oriented Processing: Using Cursors 483 DECLARE MyCategories CURSOR KEYSET FOR SELECT CategoryID, CategoryName, Description FROM Categories ORDER BY CategoryName ASC FOR UPDATE OF CategoryName, Description Note When you declare a cursor, SQL Server creates some memory structures to use the cursor, but the data is not retrieved until you open the cursor. Opening Cursors To use a cursor, you must open it. You can open a cursor using the OPEN statement. If the cursor was declared as STATIC or KEYSET, SQL Server must create a worktable in TempDB to store either the full result set, in a STATIC cursor, or the keyset only in a keyset-driven cursor. In these cases, if the worktable cannot be created for any reason, the OPEN statement will fail. SQL Server can optimize the opening of big cursors by populating the cursor asynchronously. In this case, SQL Server creates a new thread to populate the worktable in parallel, returning the control to the application as soon as possible. You can use the @@CURSOR_ROWS system function to control how many rows are contained in the cursor. If the cursor is using asynchronous population, the value returned by @@CURSOR_ROWS will be negative and represents the approximate number of rows returned since the opening of the cursor. For dynamic cursors, @@CURSOR_ROWS returns -1, because it is not possible to know whether the full result set has been returned already, because of potential insertions by other operations affecting the same data. Caution The @@CURSOR_ROWS function returns the number of rows of the last cursor opened in the current connection. If you use cursors inside triggers, the result of this function from the main execution level could be misleading. Listing 12.16 shows an example of this problem. To specify when SQL Server will decide to populate a cursor asynchronously, you can use the sp_configure system-stored procedure to change the server setting "cursor threshold", specifying the maximum number of rows that will be executed directly without asynchronous population. Caution Microsoft SQL Server 2000 Programming by Example 484 Do not fix the "cursor threshold" value too low, because small result sets are more efficiently opened synchronously. Listing 12.16 Using the @@CURSOR_ROWS System Function Create a procedure to open a cursor on Categories CREATE PROCEDURE GetCategories AS DECLARE MyCategories CURSOR STATIC FOR SELECT CategoryID, CategoryName FROM Categories OPEN MyCategories Shows the number of rows in the cursor SELECT @@CURSOR_ROWS 'Categories cursor rows after open' CLOSE MyCategories DEALLOCATE MyCategories GO Create a cursor on Products DECLARE MyProducts CURSOR STATIC FOR SELECT ProductID, ProductName FROM Products OPEN MyProducts Shows the number of rows in the last opened cursor, which is MyProducts SELECT @@CURSOR_ROWS 'Products cursor rows' EXEC GetCategories Shows the number of rows in the last opened cursor in the current connection, which is MyCategories SELECT @@CURSOR_ROWS 'Categories cursor rows after close and deallocated' CLOSE MyProducts Chapter 12. Row-Oriented Processing: Using Cursors 485 DEALLOCATE MyProducts Products cursor rows 77 Categories cursor rows after open 8 Categories cursor rows after close and deallocated 0 Fetching Rows You can use the FETCH statement to navigate an open cursor, as shown in Listing 12.17. Every time you execute the FETCH statement, the cursor moves to a different row. FETCH FROM CursorName retrieves the next row in the cursor. This is a synonym of FETCH NEXT FROM CursorName. If the FETCH statement is executed right after the OPEN statement, the cursor is positioned in the first row. If the current row is the last one in the result set, executing FETCH NEXT again will send the cursor beyond the end of the result set and will return an empty row, but no error message will be produced. Caution After opening a cursor with the OPEN statement, the cursor does not point to any specific row, so you must execute a FETCH statement to position the cursor in a valid row. FETCH PRIOR moves the cursor to the preceding row. If the cursor was positioned already at the beginning of the result set, using FETCH PRIOR will move the pointer before the starting of the result set, retrieving an empty row, but no error message will be produced. FETCH FIRST moves the cursor pointer to the beginning of the result set, returning the first row. FETCH LAST moves the cursor pointer to the end of the result set, returning the last row. FETCH ABSOLUTE n moves the cursor pointer to the n row in the result set. If n is negative, the cursor pointer is moved n rows before the end of the result set. If the new row position does not exist, an empty row will be returned and no error will be produced. If n is 0, no rows are returned and the cursor pointer goes out of scope. Microsoft SQL Server 2000 Programming by Example 486 FETCH RELATIVE n moves the cursor pointer n rows forward from the current position of the cursor. If n is negative, the cursor pointer is moved backward n rows from the current position. If the new row position does not exist, an empty row will be returned and no error will be produced. If n is 0, the current row is returned. You can use the @@FETCH_STATUS system function to test whether the cursor points to a valid row after the last FETCH statement. @@FETCH_SATUS can have the following values: • 0 if the FETCH statement was successful and the cursor points to a valid row. • -1 if the FETCH statement was not successful or the cursor points beyond the limits of the result set. This can be produced using FETCH NEXT from the last row or FETCH PRIOR from the first row. • -2 the cursor is pointing to a nonexistent row. This can be produced by a keyset-driven cursor when one of the rows has been deleted from outside the control of the cursor. Caution @@FETCH_STATUS is global to the connection, so it reflects the status of the latest FETCH statement executed in the connection. That is why it is important to test it right after the FETCH statement. Listing 12.17 Use FETCH to Navigate the Cursor DECLARE MyProducts CURSOR STATIC FOR SELECT ProductID, ProductName FROM Products ORDER BY ProductID ASC OPEN MyProducts SELECT @@CURSOR_ROWS 'Products cursor rows' SELECT @@FETCH_STATUS 'Fetch Status After OPEN' FETCH FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After first FETCH' FETCH NEXT FROM MyProducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH NEXT' FETCH PRIOR FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH PRIOR' Chapter 12. Row-Oriented Processing: Using Cursors 487 FETCH PRIOR FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH PRIOR the first row' FETCH LAST FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH LAST' FETCH NEXT FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH NEXT the last row' FETCH ABSOLUTE 10 FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH ABSOLUTE 10' FETCH ABSOLUTE -5 FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH ABSOLUTE -5' FETCH RELATIVE -20 FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH RELATIVE -20' FETCH RELATIVE 10 FROM Myproducts SELECT @@FETCH_STATUS 'Fetch Status After FETCH RELATIVE 10' CLOSE MyProducts SELECT @@FETCH_STATUS 'Fetch Status After CLOSE' DEALLOCATE MyProducts Products cursor rows 77 Fetch Status After OPEN 0 ProductID ProductName 1 Chai Fetch Status After first FETCH 0 ProductID ProductName Microsoft SQL Server 2000 Programming by Example 488 2 Chang Fetch Status After FETCH NEXT 0 ProductID ProductName 1 Chai Fetch Status After FETCH PRIOR 0 ProductID ProductName Fetch Status After FETCH PRIOR the first row -1 ProductID ProductName 77 Original Frankfurter grüne Soße Fetch Status After FETCH LAST 0 ProductID ProductName Fetch Status After FETCH NEXT the last row -1 ProductID ProductName 10 Ikura Fetch Status After FETCH ABSOLUTE 10 0 ProductID ProductName 73 Röd Kaviar Fetch Status After FETCH ABSOLUTE -5 0 ProductID ProductName 53 Perth Pasties Fetch Status After FETCH RELATIVE -20 0 Chapter 12. Row-Oriented Processing: Using Cursors 489 ProductID ProductName 63 Vegie-spread Fetch Status After FETCH RELATIVE 10 0 Fetch Status After CLOSE 0 At the same time you are moving the cursor with the FETCH statement, you can use the INTO clause to retrieve the cursor fields directly into user-defined variables (see Listing 12.18). In this way, you later can use the values stored in these variables in further Transact-SQL statements. Listing 12.18 Use FETCH INTO to Get the Values of the Cursor Columns into Variables SET NOCOUNT ON GO DECLARE @ProductID int, @ProductName nvarchar(40), @CategoryID int DECLARE MyProducts CURSOR STATIC FOR SELECT ProductID, ProductName, CategoryID FROM Products WHERE CategoryID BETWEEN 6 AND 8 ORDER BY ProductID ASC OPEN MyProducts FETCH FROM Myproducts INTO @ProductID, @ProductName, @CategoryID WHILE @@FETCH_STATUS = 0 BEGIN SELECT @ProductName as 'Product', CategoryName AS 'Category' FROM Categories WHERE CategoryID = @CategoryID FETCH FROM Myproducts INTO @ProductID, @ProductName, @CategoryID END CLOSE MyProducts DEALLOCATE MyProducts Microsoft SQL Server 2000 Programming by Example 490 Product Category Uncle Bob's Organic Dried Pears Produce Product Category Mishi Kobe Niku Meat/Poultry Product Category Ikura Seafood Product Category Konbu Seafood Product Category Tofu Produce Product Category Alice Mutton Meat/Poultry Product Category Carnarvon Tigers Seafood Product Category Rössle Sauerkraut Produce Product Category Thüringer Rostbratwurst Meat/Poultry Product Category Nord-Ost Matjeshering Seafood Product Category Inlagd Sill Seafood Product Category Gravad lax Seafood Product Category Boston Crab Meat Seafood Product Category Chapter 12. Row-Oriented Processing: Using Cursors 491 Jack's New England Clam Chowder Seafood Product Category Rogede sild Seafood Product Category Spegesild Seafood Product Category Manjimup Dried Apples Produce Product Category Perth Pasties Meat/Poultry Product Category Tourti\'e8re Meat/Poultry Product Category Pâté chinois Meat/Poultry Product Category Escargots de Bourgogne Seafood Product Category Röd Kaviar Seafood Product Category Longlife Tofu Produce If the cursor is updatable, you can modify values in the underlying tables sending standard UPDATE or DELETE statements and specifying WHERE CURRENT OF CursorName as a restricting condition (see Listing 12.19). Listing 12.19 Using WHERE CURRENT OFto Apply Modifications to the Current Cursor Row BEGIN TRAN Declare the cursor DECLARE MyProducts CURSOR FORWARD_ONLY FOR [...]... Cursors When a client application requests information from SQL Server using the default settings in ADO, OLE DB, ODBC, or DB-Library, SQL Server must follow this process: 1 2 3 The client application sends a request to SQL Server in a network package This request can be any Transact -SQL statement or a batch containing multiple statements SQL Server interprets the request and creates a query plan to... Application Programming Interface (API) server cursors— These are cursors created in SQL Server, following requests from the database library, such as ADO, OLE DB, ODBC, or DB-Library Listings 12.1 and 12.3 contain examples of this type of cursor Client cursors— These cursors are implemented in the client side by the database library The client cache contains the complete set of rows returned by the cursor,... is unnecessary to have any communication to the server to navigate the cursor Caution Do not mix API cursors with Transact -SQL cursors from a client application, or SQL Server will try to map an API cursor over Transact -SQL cursors, with unexpected results Tip Use Transact -SQL cursors in stored procedures and triggers and as local cursors in Transact -SQL batches, to implement cursors that do not require... application manages transactions and locks 501 Chapter 13 Maintaining Data Consistency: Transactions and Locks SQL Server 2000 is designed to serve multiuser environments If multiple users try to access the same data, SQL Server must protect the data to avoid conflicting requests from different processes SQL Server uses transactions and locks to prevent concurrency problems, such as avoiding simultaneous modifications... transaction boundaries by selecting the transaction starting and ending points You can consider three different types of transactions: • • • Auto commit transactions— SQL Server always starts a transaction whenever any statement needs to modify data SQL Server automatically commits the transaction if the statement finishes its work successfully However, if the statement produces any error, SQL Server will automatically... permanently Every RDBMS uses different ways to enforce these properties SQL Server 2000 uses Transact -SQL statements to control the boundaries of transactions to guarantee which operations must be considered as an atomic unit of work Constraints and other integrity mechanisms are used to enforce logical consistency of every transaction SQL Server internal engines are designed to provide physical internal... automatically roll back all changes produced by this incomplete statement In this way, SQL Server automatically maintains data consistency for every statement that modifies data Explicit transactions— The programmer specifically declares the transaction starting point and decides either to commit or rollback changes depending on programming conditions Implicit transactions— SQL Server starts a transaction automatically... statement by itself is a transaction in SQL Server You can set a connection in Implicit Transactions mode In this mode, the first time you modify data, SQL Server starts a transaction and keeps the transaction open until you decide explicitly to commit or roll back the transaction To set the Implicit Transactions mode in a connection, you must execute the SET IMPLICIT_TRANSACTIONS ON statement Listing 13 .8. .. efficient way to retrieve information from SQL Server, and it is called a default result set It is equivalent to a FORWARD_ONLY READ_ONLY cursor with a row set size set to one row Note Some articles and books refer to the default result set as a "Firehose" cursor, which is considered an obsolete term SQL Server supports three types of cursors: • • • Transact -SQL cursors— These are the cursors you studied... calling procedure or batch It is possible to have any number of nested transactions in SQL Server 2000 The @@TRANCOUNT system function gives you the number of open transactions you have at any given time Any time you execute BEGIN TRAN, the result of the function @@TRANCOUNT is increased by one Listing 13.2 shows an example of how the @@TRANCOUNT function works Listing 13.2 Values of the @@TRANCOUNT . Microsoft SQL Server 2000 Programming by Example 482 FROM Categories ORDER BY CategoryName ASC Open the cursor OPEN MyCategories. Chai Fetch Status After first FETCH 0 ProductID ProductName Microsoft SQL Server 2000 Programming by Example 488 2 Chang Fetch Status After FETCH NEXT 0 ProductID ProductName. is 0, no rows are returned and the cursor pointer goes out of scope. Microsoft SQL Server 2000 Programming by Example 486 FETCH RELATIVE n moves the cursor pointer n rows forward from the