0% found this document useful (0 votes)
2 views

Implementing Batch_stored procedure_UDFfunctions_Cursor

This document provides an overview of implementing batches, stored procedures, functions, and cursors in SQL Server. It explains how to create batches of SQL statements for efficient execution, utilize programming constructs like IF...ELSE and CASE for conditional logic, and handle errors using TRY...CATCH. Additionally, it discusses the benefits of stored procedures for executing precompiled batches multiple times without recompilation.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Implementing Batch_stored procedure_UDFfunctions_Cursor

This document provides an overview of implementing batches, stored procedures, functions, and cursors in SQL Server. It explains how to create batches of SQL statements for efficient execution, utilize programming constructs like IF...ELSE and CASE for conditional logic, and handle errors using TRY...CATCH. Additionally, it discusses the benefits of stored procedures for executing precompiled batches multiple times without recompilation.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

Implementing Batch, Stored Procedures, Functions and Cursor

Objectives
In this Unit, you will learn to:

Implement batches

Implement stored procedures

Implement functions

 Implement Cursor

Implementing Batches

As a database developer, you might need to execute more than one SQL statement to
perform a task. For example, when a new employee joins AdventureWorks, Inc., you
need to insert the employee details in the database. The details of the employees are
stored in more than one table. Therefore, you need to execute multiple insert
statements to store the details in each table. In such a case, you can send all the SQL
statements together to SQL Server to be executed as a unit. This helps in reducing
the network traffic.

At times, you might also need to check conditions before executing the SQL
statements. For example, in a manufacturing unit, the InventoryIssue table stores the
details of an item issued for the manufacturing process. When you insert a record in
this table, you need to check that the quantity on hand is more than or equal to the
quantity issued. In such a case, you can create conditional constructs that check for a
condition before executing a statement.
Creating Batches
A batch is a group of SQL statements submitted together to SQL Server for
execution. While executing batches, SQL Server compiles the statements of a batch
into a single executable unit called an execution plan. This helps in saving execution
time.

For example, you have to execute 10 statements and you are executing them one by one
by sending 10 requests. This process takes time if your queries are in a queue. All the
statements might not get executed together. Instead, if you execute all the 10
statements together in a batch, then the execution process becomes faster as all the
statements are sent to the server together. To create a batch, you can write multiple
SQL statements followed by the keyword GO at the end. The syntax of creating a
batch is:
<T-SQL Statement1>
<T-SQL Statement2>
<T-SQL Statement3>

GO

GO is a command that specifies the end of the batch and sends the SQL statements
for execution. For example, if you want to store the details of new employees in the
AdventureWorks database, you can write multiple INSERT statements in a batch, as
shown in the following statements:

INSERT INTO [AdventureWorks].[Person]. [Contact] VALUES (0, null,


'Robert', 'J', 'Langdon', NULL ,'[email protected]', 0, '1
(11) 500 555-0172' ,'9E685955-ACD0-4218-AD7F-60DDF224C452',
'2a31OEw=', NULL , newid(), getdate())

INSERT INTO [AdventureWorks]. [HumanResources].[Employee] VALUES


('AS01AS25R2E365W', 19978, 'robertl', 16, 'Tool Designer', '1972-05-
15', 'S', 'M', '1996-07-31', 0, 16, 20, 1, newid(), getdate())

GO
When a batch is submitted to SQL Server, it is compiled to create an execution plan.
If any compilation error occurs, such as a syntax error, the execution plan is not
created. Therefore, none of the statements in the batch is executed. However, if a
run-time error occurs after the execution plan is created, the execution of the batch
stops. In such a case, the statements executed before the statement that
encountered the run-time error are not affected.

Using Variables

While creating batches, you might need to store some values temporarily during the
execution time. For example, you might need to store some intermediate values while
performing calculations. To store the intermediate values, you can declare variables
and assign values to them. You can declare a variable by using the DECLARE statement.
A variable name is always preceded by the "@" symbol.

The syntax of the DECLARE statement is:


DECLARE @variable_name data_type

Variables that are declared in a batch and can be used in any statement inside the
batch are called local variables. The following statements declare a variable, @Rate,
and assigns the maximum value of the Rate column from the EmployeePayHistory table
to the variable:
DECLARE @Rate int
SELECT @Rate = max(Rate) FROM HumanResources.EmployeePayHistory
GO

In the preceding statements, the max aggregate function is used to retrieve the
maximum pay rate from the EmployeePayHistory table.

Displaying User-Defined Messages


At times, you need to display values of variables or user-defined messages when the
batch is executed. For this, you can use the PRINT statement.

The following statements display the value of the @Rate variable by using the PRINT
statement:
DECLARE @Rate int
SELECT @Rate = max(Rate) FROM HumanResources.EmployeePayHistory
PRINT @Rate
GO

You can also use comment entries in batches to write a description of the code. This
will help understand the purpose of the code. A comment entry can be written in the
following ways:

Multiple line comment entries enclosed within /* and */

 Single line comment entry starting with --(double hyphens)

Guidelines to Create Batches


While creating batches, you need to consider the following guidelines:

 You cannot combine statements such as CREATE DEFAULT, CREATE


FUNCTION, CREATE PROCEDURE, CREATE RULE, CREATE TRIGGER, and
CREATE VIEW with other statements while creating a batch. Any statement
that follows the create statement is interpreted as part of the definition.
 You can use the EXECUTE statement in a batch when it is not the first
statement of the batch, otherwise the EXECUTE statement works implicitly.

In addition, you need to consider the following restrictions:

You cannot bind rules and defaults to columns and use them in the same batch.

 You cannot define and use the CHECK constraint in the same batch.
 You cannot drop objects and recreate them in the same batch.
 You cannot alter a table by adding a column and then referring to the new column in
the batch created earlier.
Using Constructs
SQL Server allows you to use programming constructs in batches for conditional
execution of statements. For example, you need to retrieve data based on a condition.
If the condition is not satisfied, a message should be displayed. SQL Server allows you
to use the following constructs to control the flow of statements:

IF…ELSE statement

CASE statement

WHILE statement

Using the IF…ELSE Statement


You can use the IF…ELSE statement for conditional execution of SQL statements. A
particular action is performed when the given condition evaluates to TRUE, and another
action is performed when the given condition evaluates to FALSE.

The syntax of the IF…ELSE statement is:

IF boolean_expression
{sql_statement | statement_block}
ELSE
{sql_statement | statement_block}]

where, boolean_expressionspecifies the condition that evaluates to either TRUE or


FALSE. sql_statement specifies a T-SQL statement.

statement_block statements. You need to use the BEGIN and END keywords to define
multiple T-SQL statements.

For example, you can retrieve the pay rate of an employee from the
EmployeePayHistory table to a variable, @Rate. The value of the @Rate variable is
compared with the value 15 by using the < (less than) comparison operator. Based on
the condition, different messages are displayed, as shown in the following statements:
DECLARE @Rate money
SELECT @Rate = Rate FROM HumanResources.EmployeePayHistory WHERE
EmployeeID = 23
IF @Rate < 15
PRINT 'Review of the rate is required'
ELSE
BEGIN
PRINT 'Review of the rate is not required'
PRINT 'Rate =' PRINT @Rate
END
GO

In the preceding statements, the IF statement checks whether the @Rate variable is
storing a value less than 15. If the result is true, the PRINT statement displays
"Review of the rate is required", else it displays "Review of the rate is not required".
Further, the next PRINT statement displays the value of the rate.

Consider another example, where a check is performed to see the existence of the
Sales department, as shown in the following statement:
IF EXISTS (SELECT * FROM HumanResources.Department WHERE Name = 'Sales')
BEGIN
SELECT * FROM HumanResources.Department WHERE Name = 'Sales'
END
ELSE
PRINT 'Department details not available'
GO

In the preceding statement, if the Sales department exists, all the details are
displayed; otherwise, a user-defined message is displayed.

Using the CASE Statement


You can use the CASE statement in situations where several conditions need to be
evaluated. The CASE statement evaluates a list of conditions and returns one of the
possible results. You can use the IF statement to do the same task. However, you can
use a CASE statement when there are more than two conditions that check a common
variable for different values. The syntax of the CASE statement is:
CASE input_expression
WHEN when_expression
THEN
result_expression [
[WHEN when_expression
THEN result_expression] [...]] [
ELSE
else_result_expression]
END

where,

input_expression specifies the input expression that is evaluated. input_expression is


any valid expression.
when_expression is the expression that is compared with input_expression.
result_expression is the expression returned when the comparison of input_expression
with when_expression evaluates to TRUE. This can be a constant, a column name, a
function, a query, or any combination of arithmetic, bit-wise, and string operators.

else_result_expressionis the expression returned if no comparison operation evaluates


to TRUE. If this argument is omitted and no comparison operation evaluates to TRUE,
the result will be NULL.

In a simple CASE construct, a variable or an expression is compared with the


expression in each WHEN clause. If any of these expressions evaluate to TRUE, then
the expression specified with the THEN clause is executed. If the expression does not
evaluate to TRUE, the expression with the ELSE statement is executed.

Consider the following statements, where a CASE construct is included in the SELECT
statement to display the marital status as "Married" or "Single":
SELECT EmployeeID, 'Marital Status' =
CASE MaritalStatus
WHEN 'M'
THEN 'Married'
WHEN 'S'
THEN 'Single'
ELSE
'Not specified'
END
FROM HumanResources.Employee
GO

Using the WHILE Statement


You can use the WHILE statement in a batch to allow a set of T SQL statements to
execute repeatedly as long as the given condition holds true. The syntax of the WHILE
statement is:
WHILE boolean_expression
{sql_statement | statement_block}
[BREAK]
{sql_statement | statement_block}
[CONTINUE]

where, boolean_expressionis an expression that evaluates to TRUE or FALSE.


sql_statementis any SQL statement.statement_block is a group of SQL statements.

BREAK causes the control to exit from the WHILE loop. CONTINUE causes the
WHILE loop to restart, skipping all the statements after the CONTINUE keyword.

SQL Server provides the BREAK and CONTINUE statements to control the
statements within the WHILE loop. The BREAK statement causes an exit from the
WHILE loop. Any statements that appear after the END keyword, which marks the end
of the loop, are executed after the BREAK statement is executed. The CONTINUE
statement causes the WHILE loop to restart, skipping any statements after this
statement inside the loop.

For example, the HR department of AdventureWorks, Inc. has decided to review the
salary of all the employees. As per the current HR policy, the average hourly salary
rate of all the employees should be approximately $20. You need to increase the hourly
salary of all the employees until the average hourly salary reaches near $20. In
addition, you need to ensure that the maximum hourly salary should not exceed $127.
To accomplish this task, you can use the following statement:

WHILE (SELECT AVG(Rate)+1 FROM HumanResources.EmployeePayHistory) < 20


BEGIN
UPDATE HumanResources.EmployeePayHistory
SET Rate = Rate + 1 FROM HumanResources.EmployeePayHistory
IF (SELECT max(Rate)+1 FROM HumanResources.EmployeePayHistory) >127
BREAK
ELSE
CONTINUE
END

Handling Errors and Exceptions


When you execute a query, it is parsed for syntactical errors before execution. If the
syntax is correct, it is compiled and executed. Sometimes, due to factors, such as
incorrect data, an error can occur during execution even if the query is syntactically
correct. The errors that occur at run time are known as exceptions.

For example, there is a primary key constraint applied on the EmployeeID attribute of
the Employee table. When you try to insert an employee ID that already exists in the
table, an error occurs while executing the INSERT statement.

Exceptions can be handled in the following ways:

By using the TRY…CATCH construct

By using the RAISERROR statement and handling the error in the application

Using TRY…CATCH
A TRY…CATCH construct includes a TRY block followed by a CATCH block. A TRY block
is a group of SQL statements enclosed in a batch, stored procedure, trigger, or
function. If an error occurs in any statement of the TRY block, the control is passed to
another group of statements that are enclosed in a CATCH block. A CATCH block
contains SQL statements that perform some operations when an error occurs.
Therefore, an associated CATCH block must immediately follow a TRY block, as shown
in the following syntax:
TRY <SQL statements>

CATCH <SQL statements>

END CATCH
If there are no errors in the code that is enclosed in a TRY block, the control is passed
to the statement immediately after the associated END CATCH statement. In this
case, statements enclosed in the CATCH block are not executed. The TRY…CATCH
construct can be nested. Either a TRY block or a CATCH block can contain nested
TRY… CATCH constructs. A CATCH block can contain an embedded TRY…CATCH
construct to handle errors encountered by the CATCH block.

In the CATCH block, you can use the following system functions to determine the
information about errors:

 ERROR_LINE(): Returns the line number at which the error occurred.

 ERROR_MESSAGE(): Specifies the text of the message that would be returned to


the application.

 ERROR_NUMBER(): Returns the error number.

 ERROR_PROCEDURE(): Returns the name of the stored procedure or trigger in


which the error occurred. This function returns NULL if the error did not occur within
a stored procedure or trigger.

 ERROR_SEVERITY(): Returns the severity.

 ERROR_STATE(): Returns the state of the error.

For example, the EmployeeID attribute of the Employee table in the AdventureWorks
database is an IDENTITY column and its value cannot be specified while inserting a
new record. However, if you specify the value for EmployeeID in the INSERT
statement, an error will occur. To handle such run-time errors, you can include the
insert statement in a TRY block and send the control to the CATCH block where the
error information is displayed, as shown in the following statements:
BEGIN TRY
INSERT INTO [AdventureWorks].[Person]. [Contact] VALUES (0, null, 'Robert',
'J', 'Langdon', NULL ,'[email protected]', 0, '1 (11) 500 555-0172'
,'9E685955-ACD0-4218-AD7F-60DDF224C452', '2a31OEw=', NULL, newid(),
getdate()) INSERT INTO [AdventureWorks]. [HumanResources].[Employee] VALUES
('AS01AS25R2E365W', 19979, 'robertl', 16, 'Tool Designer', '1972-05-15',
'S', 'M', '1996-07-31', 0, 16, 20, 1, newid(), getdate())
END TRY
BEGIN CATCH
SELECT 'There was an error! ' + ERROR_MESSAGE() AS ErrorMessage,
ERROR_LINE() AS ErrorLine,
ERROR_NUMBER() AS ErrorNumber,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState
END CATCH
GO

Implementing Stored Procedures and Functions


As a database developer, you might need to execute a set of SQL statements
together. SQL Server allows you to create batches with multiple statements that can
be executed together. These batches can also contain programming constructs that
include conditional logic to examine conditions before executing the statements. At
times, it might be required to execute a batch repeatedly. In such a case, a batch can
be saved as database objects called stored procedures or functions. These database
objects contain a precompiled batch that can be executed many times without
recompilation.

Implementing Stored Procedures


Batches are temporary in nature. To execute a batch more than once, you need to
recreate SQL statements and submit them to the server. This leads to an increase in
the overhead, as the server needs to compile and create the execution plan for these
statements again. Therefore, if you need to execute a batch multiple times, you can
save it within a stored procedure. A stored procedure is a precompiled object stored in
the database.

Stored procedures can invoke the Data Definition Language (DDL) and Data
Manipulation Language (DML) statements and can return values. If you need to assign
values to the variables declared in the procedures at run time, you can pass parameters
while executing them. You can also execute a procedure from another procedure. This
helps in using the functionality of the called procedure within the calling procedure.

An application is designed in three layers. These layers are the presentation, business,
and data access layers.

An application is well maintained if the stored procedures are used. These procedures
are indeed a part of the data access layer. They are mapped to certain methods of the
business layer. The application can access the required data from the database by
invoking the specific methods of the business layer. These methods, in turn, invoke the
statements or the procedures in the data access layer. Therefore, the entire process
is abstracted. As a database developer, it is important for you to learn how to
implement procedures.

Creating Stored Procedures


You can create a stored procedure by using the CREATE PROCEDURE statement.
The syntax of the CREATE PROCEDURE statement is:

CREATE PROCEDURE proc_name WITH [ENCRYPTION][RECOMPILE][EXECUTE AS]

AS

BEGIN

sql_statement1 sql_statement2

END

where,

proc_name specifies the name of the stored procedure.

ENCRYPTION is used to encrypt the original text of the CREATE PROCEDURE statement.

RECOMPILE specifies that the stored procedure is recompiled every time it executes.

EXECUTE AS specifies the security context under which the stored procedure is executed.

The following statement creates a stored procedure to view the department names from the
Department table:
CREATE PROCEDURE prcDept

AS

BEGIN

SELECT Name FROM HumanResources.Department

END

When the CREATE PROCEDURE statement is executed, the server compiles the
procedure and saves it as a database object. The procedure is then available for
various applications to execute.

The process of compiling a stored procedure involves the following steps:

1. The procedure is compiled and its components are broken into various pieces.
This process is known as parsing.
2. The existence of the referred objects, such as tables and views, are checked.
This process is known as resolving.
3. The name of the procedure is stored in the sysobjects table and the code that
creates the stored procedure is stored in the syscomments table.
4. The procedure is compiled and a blueprint for how the query will run is created.
This blueprint is specified as an execution plan. The execution plan is saved in
the procedure cache.
5. When the procedure is executed for the first time, the execution plan will be
read, fully optimized, and then run. When the procedure is executed again in the
same session, it will be read directly from the cache. This increases
performance, as there is no repeated compilation.

NOTE :- After creating the stored procedure, you can view the code of the procedure by using the
sp_helptext statement.

Guidelines to Create a Stored Procedure


The following points need to be considered before creating a stored procedure:

 You cannot combine the CREATE PROCEDURE statement with other SQL
statements in a single batch.
 You must have the CREATE PROCEDURE permission to create a procedure in the
database and the ALTER permission on the schema, where the procedure is
being created.
 You can create a stored procedure only in the current database.

After creating a stored procedure, you can execute the procedure. You can also alter
the procedure definition or drop it, if the existing procedure is not required.

Executing a Stored Procedure


A procedure can be executed by using the EXECUTE and EXEC statement. The syntax
of the EXECUTE statement is:

EXEC | EXECUTE proc_name

where, proc_name is the name of the procedure that you need to execute. You can
execute the stored procedure, prcDept, as shown in the following statement:

EXEC prcDept

Altering a Stored Procedure


A stored procedure can be modified by using the ALTER PROCEDURE statement. The
syntax of the ALTER PROCEDURE statement is:

ALTER PROCEDURE proc_name

You can alter the stored procedure by using the following statement:

ALTER PROCEDURE prcDept

AS

BEGIN

SELECT DepartmentID, Name FROM HumanResources.Department

END

In the preceding statement, the prcDept stored procedure will be modified to display
department Ids along with the department name. When you execute a stored
procedure, the number of rows affected by it is also returned. If the stored
procedure is getting executed by a Web application, then the database engine returns
the result set along with the number of rows affected. This creates an overhead on
the network and reduces the performance of the application. To avoid this, you can
turn off the message that contains the number of rows affected by the SQL
statement.

You can perform this task by using the SET NOCOUNT statement.

The syntax of this statement is:

SET NOCOUNT { ON | OFF }

where,

ON prevents the message containing the count of the number of rows affected by the
SQL statement or stored procedure from being returned.

OFF allows the message containing the count of the number of rows affected by the
SQL statement or stored procedure to be returned.

For example,

consider the following code snippet:

ALTER PROCEDURE prcDept

AS

BEGIN

SET NOCOUNT ON SELECT DepartmentID, Name FROM

HumanResources.Department

END
When you execute the prcDept stored procedure, the result set does not display the
number of rows affected by the procedure.

Dropping a Stored Procedure


You can drop a stored procedure from the database by using the DROP PROCEDURE
statement. The syntax of the DROP PROCEDURE statement is: DROP PROCEDURE
proc_name You cannot retrieve a procedure once it is dropped. You can drop the
prcDept stored procedure by using the following statement: DROP PROCEDURE
prcDept.

Creating Parameterized Stored Procedures


At times, you need to execute a procedure for different values of a variable that are
provided at run time. For this, you can create a parameterized stored procedure.
Parameters are used to pass values to the stored procedure during run time. These
values can be passed by using standard variables. The parameter that passes the value
to the stored procedure is defined as an input parameter. A stored procedure has the
capability of using a maximum of 2100 parameters. Each parameter has a name, data
type, direction, and a default value.
The following statement creates a stored procedure displaying the employee ID, the
login ID, and the title of employees that have the same title provided as an input
during execution:

CREATE PROC prcListEmployee @title char(50)

AS

BEGIN

PRINT 'List of Employees'

SELECT EmployeeID, LoginID, Title FROM HumanResources.Employee

WHERE Title = @title

END

You can execute the stored procedure, prcListEmployee, by using the following
statement:

EXECUTE prcListEmployee 'Tool Designer'

While executing stored procedures, you can also provide the values for the parameters
by explicitly specifying the name and value of the parameter. In the previous example,
you can also pass the parameter value by using the name of variable, as shown in the
following statement:

EXECUTE prcListEmployee @title = 'Tool Designer'

Returning Values from Stored Procedures


Similar to providing input values to the procedures at run time, you can also return
values as an output from the procedures. The values can be returned to the calling
application through output parameters. To specify a parameter as the output
parameter, you can use the OUTPUT keyword.

The OUTPUT keyword has to be specified in both the CREATE PROCEDURE and the
EXECUTE statements. If the OUTPUT keyword is omitted, the procedure will be
executed but will not return any value. The syntax of declaring an output parameter
using the OUTPUT keyword is:

CREATE PROCEDURE procedure_name [ {@parameter data_type} [OUTPUT] ]

AS

sql_statement [...n]

@parameter data_type [OUTPUT] allows the stored procedure to pass a data value to
the calling procedure. If the OUTPUT keyword is not used, then the parameter is
treated as an input parameter.

You can also return values from the stored procedure by using the RETURN statement.
The RETURN statement allows the stored procedure to return only an integer value to
the calling application. The syntax of the RETURN statement is:

RETURN value

where, value is any integer.

If a value is not specified, then the stored procedure returns a default value of 0 to
specify success and a nonzero value to specify failure.

For example,

you need to display the details of an employee whose employee ID has been provided as
an input. For this, you need to create a procedure prcGetEmployeeDetail that will
accept employee ID as an input and return the department name and ID of the shift in
which the employee works. You can create the procedure, as shown in the following
statement:
CREATE PROCEDURE prcGetEmployeeDetail @EmpId int, @DepName char(50)
OUTPUT, @ShiftId int OUTPUT

AS

BEGIN

IF EXISTS(SELECT * FROM HumanResources.Employee WHERE EmployeeID =


@EmpId)

BEGIN

SELECT @DepName = d.Name, @ShiftId = h.ShiftID

FROM HumanResources.Department d JOIN


HumanResources.EmployeeDepartmentHistory h

ON d.DepartmentID = h.DepartmentID WHERE EmployeeID = @EmpId


AND h.Enddate IS NULL

RETURN 0

END

ELSE

RETURN 1

END

In the preceding statement, the prcGetEmployeeDetail procedure accepts the


employee ID as an input parameter and returns the department name and shift ID as
the output parameters. The procedure first checks the existence of the given
employee ID. If it exists, the procedure returns an integer value 0 along with the
required details.

Calling a Procedure from Another Procedure


At times, you might need to use the values returned by a procedure in another
procedure. For this, you can execute or call one procedure from another procedure. A
procedure that calls or executes another procedure is known as the calling procedure,
and the procedure that is called or executed by the calling procedure is termed as the
called procedure.

You can also execute a procedure from another procedure if you need to use the
functionality provided by one into another.

Consider the previous example where the prcGetEmployeeDetail procedure returns the
employee details for a given employee ID. You can create the
prcDisplayEmployeeStatus procedure, which accepts the employee ID of an employee
as an input and displays the department name and shift ID where the employee is
working along with the manager ID and the title of the employee. To perform this task,
you need to call the prcGetEmployeeDetail procedure from the
prcDisplayEmployeeStatus procedure, as shown in the following statement:

CREATE PROCEDURE prcDisplayEmployeeStatus @EmpId int

AS

BEGIN

DECLARE @DepName char(50)

DECLARE @ShiftId int

DECLARE @ReturnValue int

EXEC @ReturnValue = prcGetEmployeeDetail @EmpId, @DepName OUTPUT,@ShiftId


OUTPUT

IF (@ReturnValue = 0)

BEGIN

PRINT 'The details of an employee with ID: ' + convert(char(10), @EmpId)

PRINT 'Department Name: ' + @DepNamePRINT 'Shift ID: ' + convert( char
(1), @ShiftId)

SELECT ManagerID, Title FROM HumanResources.Employee WHERE


EmployeeID = @EmpID

END
ELSE

PRINT 'No records found for the given employee'

END

To execute the prcDisplayEmployeeStatus procedure, you need to execute the


following statement:

EXEC prcDisplayEmployeeStatus 2

Activity 7.1: Creating Stored Procedures


Problem Statement
You are a database developer at AdventureWorks, Inc. The Human Resource
department needs to revise the payment details of the employees. You need to create
a procedure that obtains the percentage value by which you need to increase the pay
rate. In addition, you need to ensure that the pay is revised for only those employees
whose pay rate was not revised in the last six months.

Exercises
Exercise 1

Create a batch that finds the average pay rate of the employees and then lists the
details of the employees who have a pay rate less than the average pay rate.
Implementing Functions
Similar to stored procedures, you can also create functions to store a set of T-SQL
statements permanently. These functions are also referred to as User-Defined
Functions (UDFs). A UDF is a database object that contains a set of T-SQL
statements, accepts parameters, performs an action, and returns the result of that
action as a value. The return value can be either a single scalar value or a result set.

UDFs have a limited scope as compared to stored procedures. You can create functions
in situations when you need to implement a programming logic that does not involve any
permanent changes to the database objects outside the function. For example, you
cannot modify a database table from a function.

UDFs are of different types, scalar functions and table-valued functions. As a


database developer, you must learn to create and manage different types of UDFs.

Creating UDFs
A UDF contains the following components:

 Function name with optional schema/owner name


 Input parameter name and data type
 Options applicable to the input parameter
 Return parameter data type and optional name
 Options applicable to the return parameter
 One or more T-SQL statements

Creating Scalar Functions


Scalar functions accept a single parameter and return a single data value of the type
specified in the RETURNS clause. A scalar function can return any data type except
text, ntext, image, cursor, and timestamp. Some scalar functions, such as
current_timestamp, do not require any arguments. A function contains a series of T-
SQL statements defined in a BEGIN...END block of the function body that returns a
single value.
For example,
Consider a scalar function that calculates the monthly salary of employees. This
function accepts the pay rate and returns a single value after multiplying the rate with
the number of hours and number of days. You can create this function by using the
following statement:

CREATE FUNCTION HumanResources.MonthlySal (@PayRate float) RETURNS float


AS

BEGIN

RETURN (@PayRate * 8 * 30)

END

You can execute the preceding function by using the following statements:

DECLARE @PayRate float

SET @PayRate = HumanResources.MonthlySal(12.25)

PRINT @PayRate

In the preceding statements, @PayRate is a variable that will store a value returned by
the MonthlySal function.

pay rate and returns a single value after multiplying the rate with the number of hours
and number of days. You can create this function by using the following statement:
CREATE FUNCTION HumanResources.MonthlySal (@PayRate float) RETURNS float
AS

BEGIN RETURN (@PayRate * 8 * 30)

END

You can execute the preceding function by using the following statements:

DECLARE @PayRate float

SET @PayRate = HumanResources.MonthlySal(12.25)

PRINT @PayRate
In the preceding statements, @PayRate is a variable that will store a value returned by
the MonthlySal function.

Creating Table-Valued Functions


A table-valued function returns a table as an output, which can be derived as part of a
SELECT statement. Table-valued functions return the output as a table data type. The
table data type is a special data type used to store a set of rows.

An inline table-valued function returns a variable of a table data type from the result
set of a single SELECT statement. An inline function does not contain a function body
within the BEGIN and END statements.

For example,

the inline table-valued function, fx_Department_GName, accepts a group name as a


parameter and returns the details of the departments that belong to the group from
the Department table. You can create the function by using the following statement:

CREATE FUNCTION fx_Department_GName (@GrName nvarchar(20)) RETURNS table

AS

RETURN ( SELECT * FROM HumanResources.Department WHERE GroupName=@GrName )

You can use the following query to execute the fx_Department_GName function with a
specified argument:

SELECT * FROM fx_Department_GName ('Manufacturing')


Consider another example of an inline function that accepts rate as a parameter and
returns all the records that have a rate greater than the parameter value. You can
create this function, as shown in the following statement:
CREATE FUNCTION HumanResources.Emp_Pay (@Rate int) RETURNS table
AS
RETURN ( SELECT e.EmployeeID, e.Title, er.Rate FROM
HumanResources.Employee AS e JOIN HumanResources.EmployeePayHistory AS er
ON e.EmployeeID=er.EmployeeID WHERE er.Rate>@Rate )
In the preceding statement, the Emp_Pay function will return a result set that displays
all the records of the employees who have the pay rate greater that the parameter.
You can execute the preceding function by using the following query:

SELECT * FROM HumanResources.Emp_Pay (50)

ity 7.2: Creating Functions

Problem Statement

As a database developer at AdventureWorks, Inc., you need to create a


function that accepts the employee ID of an employee and returns the
following details:

 Employee ID
 Name of the employee
 Title of the employee
 Number of other employees working under the employee

How will you create the function?

Implementing Cursors
You have been following a set-based approach to work with data in SQL
Server. This approach allows working on multiple rows together as a single
unit. Being a relational database system, SQL Server is designed to
process the sets, which are an unordered collection of rows, also known as
a result set.

It means that multiple rows are handled together in an unordered manner


during query execution. However, cursors follow an iterative approach.
This means that the database engine handles a single row at a time in a
specific order.
The following list helps you to understand how the set-based approach is
different from an iterative approach:

 In case of the set-based approach, you need to instruct the


database engine what is to be done without specifying the how part.
But in the iterative approach, you also need to specify how you want
the engine to do a particular job.
 The Iterative approach involves the use of the SELECT statement,
loop management, navigation, and state-checking. Therefore, it
involves more of code writing in comparison to the set-based
approach.
 Since the iterative approach allows accessing one row at a time, it is
slower than the set-based approach.

A cursor in SQL Server allows you to work with individual rows of a result
set. Associating a cursor with the result set enables you to process the
result set one row at a time. A cursor allows you to perform the following
operations:

 Navigate to a specific row of the result set.


 Retrieve a row from a particular position.
 Modify a row at a particular position.

Implementing a cursor includes the following tasks:

 Declare a cursor.
 Open the cursor.
 Fetch rows from the cursor.
 Close the cursor.
 Deallocate the cursor.
Declaring a Cursor

A cursor is declared by defining the SQL statement or the query used to


build the result set on which the cursor operates. Additional attributes,
such as the scrolling behavior or the scope of the cursor, are also defined
at the time of declaration. The following syntax is used to declare a
cursor:

DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] [ FORWARD_ONLY |


SCROLL ] [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] [ READ_ONLY |
SCROLL_LOCKS | OPTIMISTIC ] FOR select_statement [ FOR UPDATE [ OF
column_name [ ,...n ] ] ] [;]

where,

Cursor_name is the name of the cursor.

LOCAL specifies that the scope of the cursor is local. It means that the
cursor can be referenced only the batch, stored procedure, or trigger in
which it has been created.

GLOBAL specifies that the scope of the cursor is global. It means that
the cursor can be referenced in any batch, stored procedure, or trigger
executed by the current connection.

FORWARD_ONLY specifies that the cursor can be scrolled in a forward


direction only.

SCROLL specifies that all the fetch options are available and the cursor
can fetch data in all directions.

STATIC specifies that the cursor makes a temporary copy of the data and
all the requests to the cursor are answered from this temporary table. A
static cursor can move in both the directions forward and backward.
However, data cannot be updated or deleted by using static cursors.

DYNAMIC specifies that the cursor reflects all data changes made to the
rows in its result set as you scroll around the cursor.

FAST_FORWARD specifies that the cursor is FORWARD ONLY and


READ ONLY. Such cursors produce the least amount of overhead on SQL
Server.

READ_ONLY specifies that the cursor is read only and cannot be updated.

SCROLL_LOCKS specifies that the rows will be locked as they are read
into the cursor. This is done to ensure that the updates or deletes made
through the cursor succeeds.

OPTIMISTIC specifies that the cursor does not lock rows as they are
read into the cursor. Therefore, if any user changes the data in the rows
being read by the cursor, the updates or deletes made through the cursor
will not succeed.

select_statement specifies the SQL statements to define the result set


of the cursor.

FOR UPDATE [ OF column_name [ ,...n ] specifies the columns that can be


updated within the cursor. If OF column_name [ ,...n ] is specified, then
only the listed columns can be updated. If OF column_name [ ,...n ] is not
specified, then all the columns can be updated.

Opening the Cursor


The OPEN statement is used to open and populate the cursor by executing
the T-SQL statements defined in the DECLARE CURSOR statement.
The following syntax is used to open a cursor:

OPEN [LOCAL|GLOBAL] cursor_name

where,

cursor_name is the name of the cursor you want to open.

Fetching Rows from the Cursor


The FETCH statement is used to retrieve a row from the cursor, one by
one. A row can be fetched from a cursor by using the following syntax:
FETCH [ [ NEXT | PRIOR | FIRST | LAST | ABSOLUTE n
| @nvar| RELATIVE n | @nvar
]
FROM
]
{ { [ GLOBAL ] cursor_name } | @cursor_variable_name }
[ INTO @variable_name [ ,...n ] ]

where,

NEXT is used to return the row immediately following the current row.

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 is used to return the result row immediately preceding the current row.

If FETCH PRIOR is the first fetch against a cursor, no row is returned and the cursor
is positioned left before the first row. FIRST is used to return the first row in the
cursor. LAST is used to return the last row in the cursor.

ABSOLUTE { n| @nvar}is used to return the nth row in the cursor. If n or @nvar is
positive, the rows are counted from top of the result set. If n or @nvar is negative,
the rows are counted from bottom of the result set. If n or @nvar is 0, no rows are
returned. n must be an integer constant and @nvar must be smallint, tinyint, or int.

RELATIVE { n| @nvar}is used to return the nth row related to the current row. If n or
@nvar is positive, the nth row after the current row is returned. If n or @nvar is
negative, nth row prior to the current row is returned. If n or @nvar is 0, the current
row is returned. GLOBAL is used to specify the name of the cursor that refers to a
global cursor.

cursor_name specifies the name of the open cursor from which the fetch should be
made. @cursor_variable_name is used as the name of a cursor variable referencing the
open cursor from which the fetch should be made.

INTO @variable_name[ ,...n]specifies the local variable names used to hold the data
returned from the cursor. The number of these variables must be equal to the number
of columns specified in the cursor select list. Each variable in the list, from left to
right, is associated with the corresponding column in the cursor result set.

Closing the Cursor


A cursor can be closed by using the CLOSE statement. When the cursor is closed, the
current result set is released. A cursor once closed can be reopened if required. The
following syntax is used to close a cursor:

CLOSE cursor_name

Deallocating the cursor


Deallocating removes a cursor reference from the memory. Once deallocated, a cursor
cannot be reopened. A cursor is deallocated by using the following syntax:
DEALLOCATE cursor_name

Consider an example.

You want to retrieve the title of an employee on the basis of EmployeeID. You need to
write the following statements for the same:
CREATE PROCEDURE cursor_demo @id int
AS
BEGIN
DECLARE @Ctitle varchar(50);
DECLARE cur1 CURSOR
FOR
SELECT HumanResources.Employee.Title FROM HumanResources.Employee
WHERE HumanResources.Employee.EmployeeID = @id;
OPEN cur1;
FETCH cur1 INTO @Ctitle;
SELECT @Ctitle;
CLOSE cur1;
END
EXEC cursor_demo 10

The preceding statements displays the title of the employee whose ID is 10, as shown
in the following figure.

Consider another example, where you need to display the first name, middle name, and
the last name of a person on the basis of the contact ID. For this, you have written the
following statements:

DECLARE @firstname varchar (15),@middlename varchar(15), @lastname varchar(15)

DECLARE EmpDetail CURSOR LOCAL SCROLL STATIC

FOR

SELECT firstName, MiddleName, LastName FROM Person.Contact

WHERE ContactID < 10 AND MiddleName IS NOT NULL

OPEN EmpDetail
FETCH NEXT FROM EmpDetail INTO @firstname, @middlename , @lastname

PRINT @firstname + ' ' + @middlename +' ' + @lastname

WHILE @@FETCH_STATUS = 0

BEGIN

FETCH NEXT FROM EmpDetail INTO @firstname,@middlename, @lastName


PRINT @firstname + ' '+@middlename+' ' + @lastname

END

CLOSE EmpDetail

You might also like