Top Banner
Dinamic SQL & Cursor
26

Dinamic SQL & Cursor

Jan 14, 2016

Download

Documents

Ricky Lien

Dinamic SQL & Cursor. Why Dinamic SQL ?. Sometimes there is a need to dynamically create a SQL statement on the fly and then run that command. - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Dinamic SQL & Cursor

Dinamic SQL&

Cursor

Page 2: Dinamic SQL & Cursor

Why Dinamic SQL ?• Sometimes there is a need to dynamically create a

SQL statement on the fly and then run that command.• This can be done quite simply from the application

perspective where the statement is built on the fly whether you are using ASP.NET or any other programming language. 

• But how do you do this from within a SQL Server stored procedure?

Page 3: Dinamic SQL & Cursor

Dinamic SQL

• Dynamic SQL is a term used to mean SQL code that is generated programatically (in part or fully) by your program before it is executed.

• As a result it is a very flexable and powerful tool. • You can use dynamic SQL to accomplish tasks such

as adding where clauses to a search based on what fields are filled out on a form or to create tables with varying names.

Page 4: Dinamic SQL & Cursor

How To Run Dinamic SQL

SQL Server offers a few ways of running a dynamically built SQL statement.  These ways are:

•Writing a query with parameters •Using EXEC •Using sp_executesql

Page 5: Dinamic SQL & Cursor

Parameters - EXEC – SP_EXECUTESQL

DECLARE @city varchar(75)SET @city = 'London'SELECT * FROM customers WHERE City = @city

DECLARE @sqlCommand varchar(1000)DECLARE @columnList varchar(75)DECLARE @city varchar(75)SET @columnList = 'CustomerID, ContactName, City'SET @city = '''London'''SET @sqlCommand = 'SELECT ' + @columnList + ' FROM customers WHERE City = ' + @cityEXEC (@sqlCommand)

DECLARE @sqlCommand nvarchar(1000)DECLARE @columnList varchar(75)DECLARE @city varchar(75)SET @columnList = 'CustomerID, ContactName, City'SET @city = 'London'SET @sqlCommand = 'SELECT ' + @columnList + ' FROM customers WHERE City = @city'EXECUTE sp_executesql @sqlCommand, N'@city nvarchar(75)', @city = @city

Page 6: Dinamic SQL & Cursor

Dinamic SQL in a Stored Procedure

Create Procedure GenericTableSelect

@TableName VarChar(100)

AS

SELECT * FROM @TableName

Create Procedure GenericTableSelect@TableName VarChar(100)

AS Declare @SQL VarChar(1000) SET @SQL = 'SELECT * FROM ' SET @SQL = @SQL + @TableName EXEC (@SQL)

Create Procedure GenericTableSelect@TableName VarChar(100)

AS Declare @SQL VarChar(1000) SET @SQL = 'SELECT * FROM ' SET @SQL = @SQL + @TableName EXEC (@SQL)

Page 7: Dinamic SQL & Cursor

SP_EXECUTESQL

The system stored procedure sp_executesql behaves very similar to the EXECUTE command, however, it offers two advantages: 1.Parameters can stay in their native data type - with EXECUTE you will have to pass a string; therefore, everything needs to be converted to string data types with EXEC. 2.Query optimizer is more likely to re-use the existing execution plans if you have to run the same query with

different parameters. The reason for this is that the text of the query does not change with sp_executesql - with EXEC you pass a different string each time.

Page 8: Dinamic SQL & Cursor

SP_EXECUTESQL

sp_executesql [@SQLStatement],[@ParameterDefinitionList], [@ParameterValueList]

• The parameters are specified with a name and type.

• We can specify the parameters for both input and output.

Page 9: Dinamic SQL & Cursor

Dinamic SQL Samples (1)CREATE PROCEDURE GENERAL_SELECT

(@TableName nvarchar(100)

,@ColumnList varchar(75))

AS

BEGIN

DECLARE @sqlCommand NVARCHAR(200)

SET @sqlCommand = 'SELECT ' + @columnList + ' FROM ‘

+ @TableName

EXECUTE sp_executesql @sqlCommand

END

EXEC GENERAL_SELECT@TableName='Customers',@ColumnList='*'

Page 10: Dinamic SQL & Cursor

Dinamic SQL Samples (2)CREATE PROCEDURE usp_GetNumberOfRecord

( @TableName NVARCHAR(2000),

@TotalRowsReturned INT OUTPUT )

AS

BEGIN

DECLARE @SelectStatement NVARCHAR(2000)

DECLARE @FullStatement NVARCHAR(4000)

DECLARE @ParameterList NVARCHAR(500)

SET @ParameterList = '@TotalRowsReturned INT OUTPUT'

SET @SelectStatement = 'SELECT @TotalRowsReturned = COUNT(*)+1 FROM '

SET @FullStatement = @SelectStatement + @TableName

PRINT @FullStatement

EXECUTE sp_executesql @FullStatement, @ParameterList,

@TotalRowsReturned = @TotalRowsReturned OUTPUT

END

Page 11: Dinamic SQL & Cursor

Dinamic SQL Samples (3)

DECLARE @TableName NVARCHAR(2000),

@TotalRowsReturned INT

SET @TableName = ‘Customers'

EXECUTE usp_GetNumberOfRecord

@TableName = @TableName,

@TotalRowsReturned = @TotalRowsReturned OUTPUT

SELECT @TotalRowsReturned as NextRow

Page 12: Dinamic SQL & Cursor

Cursor

• Cursor is a database object used by applications to

manipulate data in a set on a row-by-row basis, instead of the typical SQL commands that operate on all the rows in the set at one time.

• There are times when you want to loop through a series of rows a perform processing for each row.

• The should only be used when you truly need to access one row at a time. The only reason for that is to call a stored procedure on each row

• For example, you can use cursor to include a list of all user databases and make multiple operations against eachdatabase by passing each database name as a variable.

Page 13: Dinamic SQL & Cursor

Cursor Life CycleA cursor life cycle can be described as follows: 1.Cursor is declared using the DECLARE CURSOR statement. This statement creates a cursor within SQL Server memory 2.Cursor is activated using OPEN CURSOR statement. At this point you can populate the cursor with a record set. 3.Data is retrieved from the cursor using the FETCH keyword. 4.A WHILE loop is executed within the cursor to perform some operation with the rows in the cursor with the condition that the FETCH command is successful. 5.Cursor is deactivated using CLOSE CURSOR statement. At this point you can't populate the cursor with additional rows. Nor can you work with rows within the cursor. However, you can re-open the cursor with OPEN CURSOR statement and perform additional work with the cursor. 6.The cursor is destroyed using DEALLOCATE CURSOR statement. Once the cursor is de-allocated it cannot be reopened.

Page 14: Dinamic SQL & Cursor

Cursor SyntaxDECLARE cursor_name [INSENSITIVE] [SCROLL] CURSORFOR select_statement[FOR {READ ONLY | UPDATE [OF column_name [,...n]]}]

OPEN { { [GLOBAL] cursor_name } | cursor_variable_name}

FETCH [[ NEXT | PRIOR | FIRST | LAST | ABSOLUTE {n | @nvar} | RELATIVE {n | @nvar} ] FROM ]{ { [GLOBAL] cursor_name } | @cursor_variable_name}[INTO @variable_name[,...n] ]

CLOSE { {[GLOBAL] cursor_name } | cursor_variable_name }

DEALLOCATE { { [GLOBAL] cursor_name } | @cursor_variable_name}

Page 15: Dinamic SQL & Cursor

Cursor SamplesDECLARE @ProductName nvarchar(40)DECLARE @idx intSET @idx=1

DECLARE @getProductName CURSORSET @getProductName = CURSOR FOR SELECT ProductName FROM Products

OPEN @getProductName

FETCH NEXT FROM @getProductName INTO @ProductNameWHILE @@FETCH_STATUS = 0BEGIN

PRINT 'Product #' + CAST(@idx AS char(3)) + @ProductNameSET @idx= @idx+1

FETCH NEXT FROM @getProductName INTO @ProductNameEND

CLOSE @getProductNameDEALLOCATE @getProductName

Page 16: Dinamic SQL & Cursor

Cursor Functions

@@FETCH_STATUS

@@CURSOR_ROWS

CURSOR_STATUS

Page 17: Dinamic SQL & Cursor

@@FETCH_STATUS

@@FETCH_STATUS value Meaning

0 Successful fetch of a row within a cursor

-1

Fetch has failed. This could mean that the cursor has reached the beginning (or end) of the record set. This could also mean that we attempted retrieving a record that does not exist. For instance, if you attempt to grab 51st record within a cursor that has 50 records fetch status will be 1.

-2The fetched row is missing. This means the record you're trying to FETCH has been deleted or its key has been updated since you have opened the cursor.

• The most commonly used cursor function is @@FETCH_STATUS.

• This function determines whether FETCH keyword has successfully retrieved a row from the current cursor.

• @@FETCH_STATUS can take one of the three values:

Page 18: Dinamic SQL & Cursor

@@FETCH_STATUS ExampleDECLARE @employee_full_name VARCHAR(85)

DECLARE employee_cursor CURSOR FOR SELECT TOP 5 FirstName + ' ' + LastName + ' ' + Title FROM Employees

OPEN employee_cursor

FETCH NEXT FROM employee_cursor INTO @employee_full_name

WHILE @@FETCH_STATUS = 0

BEGIN

FETCH NEXT FROM employee_cursor INTO @employee_full_name

SELECT @@FETCH_STATUS AS fetch_status

END

CLOSE employee_cursor

DEALLOCATE employee_cursor

Page 19: Dinamic SQL & Cursor

@@CURSOR_ROWS• @@CURSOR_ROWS function returns the number of rows in the

cursor which was opened last on the current connection. • This means that if you have 3 cursors open @@CURSOR_ROWS will

return the number of rows in the 3rd cursor. • @@CURSOR_ROWS can take the following values:

@@CURSOR_ROWS value

Meaning

-mCursor is being populated asynchronously. "M" is the value of records in the record set.

-1

The cursor is DYNAMIC; that means, it reflects the changes to the data within the cursor. Therefore the number of rows can change due to addition or deletion of rows in the underlying tables. DYNAMIC cursors always return -1 as value of @@CURSOR_ROWS.

0

This can mean one of the following: •Cursor has not been opened •Cursor has no rows •Cursor has been closed

NNumber of rows in the cursor record set. N is reported after the cursor has been fully populated

Page 20: Dinamic SQL & Cursor

@@CURSOR_ROWS ExampleDECLARE @last_name VARCHAR(20),@first_name VARCHAR(20)

DECLARE MY_CURSOR CURSOR FOR SELECT TOP 3 LASTNAME, FIRSTNAME

FROM EMPLOYEES

SELECT 'cursor has ' + CAST(@@CURSOR_ROWS AS VARCHAR) + ' rows'

OPEN MY_CURSOR

FETCH NEXT FROM MY_CURSOR INTO @last_name, @first_name

SELECT 'cursor has ' + CAST(@@CURSOR_ROWS AS VARCHAR) + ' rows'

WHILE @@FETCH_STATUS = 0

BEGIN

FETCH NEXT FROM MY_CURSOR INTO @last_name, @first_name

END

CLOSE MY_CURSOR

SELECT 'cursor has ' + CAST(@@CURSOR_ROWS AS VARCHAR) + ' rows'

DEALLOCATE MY_CURSOR

Page 21: Dinamic SQL & Cursor

CURSOR_STATUS• The CURSOR_STATUS function can be used effectively within a stored

procedure that calls another stored procedure.• Which returns an output parameter of CURSOR data type.• This function can be used with local or global cursors and determines

whether or not the stored procedure has returned a cursor with a result set.

CURSOR_STATUS( 'local' or 'global', cursor name)

CURSOR_STATUS ('variable', cursor variable name)

Page 22: Dinamic SQL & Cursor

The values returned by CURSOR_STATUS function

CURSOR_STAT

US value

Meaning for variable Meaning for cursor name

1

Cursor is open and has at least 1 row DYNAMIC cursors return 1 even if they contain no rows

Cursor is open and has at least 1 row DYNAMIC cursors return 1 even if they contain no rows

0 Cursor is open but has no rows Cursor has no rows

-1 The cursor is closed The cursor is closed

-2

Cursor wasn't returned by the called procedure OR the cursor was deallocated prior to being assigned to this variable

The value of 2 is never returned by CURSOR_STATUS if you refer to cursor name

-3

Cursor variable with the specified name does not exist OR the variable exists, but it hasn't been assigned to a cursor returned from the called procedure

Cursor with the specified name does not exist

Page 23: Dinamic SQL & Cursor

CURSOR_STATUS Example (1)CREATE PROCEDURE RETURN_EMPLOYEE_NAMES(

@last_name VARCHAR(50),

@my_cursor CURSOR VARYING OUTPUT)

AS

BEGIN

SET NOCOUNT ON

SET @my_cursor = CURSOR STATIC FOR

SELECT LastName, FirstName FROM Employees

WHERE LastName = @last_name

OPEN @my_cursor

END

Page 24: Dinamic SQL & Cursor

CURSOR_STATUS Example (2)CREATE PROCEDURE CALL_THE_OTHER_PROCEDURE @last_name VARCHAR(50)

AS

SET NOCOUNT ON

DECLARE @first_name VARCHAR(20)

DECLARE @my_cursor CURSOR

EXECUTE RETURN_EMPLOYEE_NAMES

@last_name,@my_cursor OUTPUT

IF CURSOR_STATUS('variable','@my_cursor') = 0

BEGIN

PRINT 'no records found'

RETURN

END

ELSE

BEGIN

FETCH NEXT FROM @my_cursor

INTO @last_name,

@first_name

WHILE @@FETCH_STATUS = 0

BEGIN

SELECT @last_name,

@first_name

FETCH NEXT FROM @my_cursor

INTO @last_name,

@first_name

END

CLOSE @my_cursor

DEALLOCATE @my_cursor

END

Page 25: Dinamic SQL & Cursor

CURSOR_STATUS Example (3)

EXECUTE call_the_other_procedure 'king'

Page 26: Dinamic SQL & Cursor

Daftar Pustaka

http://www.mssqltips.com/sqlservertip/1160/execute-dynamic-sql-commands-in-sql-server/

http://www.sommarskog.se/dynamic_sql.html

http://www.mssqlcity.com/Articles/General/UseCursor.htm

http://sqlserverpedia.com/wiki/Built-in_Functions_-_Cursor_Functions