UNIT 1
1. Creating and Using Sequences
Question: How can you create, reference, alter, and drop a sequence in SQL Server?
Use and Meaning:
Sequences are used to generate unique numeric values automatically, typically for primary
keys or IDs.
Script:
-- Step 1: Create a sequence
CREATE SEQUENCE TestSeq
START WITH 1 -- Starting value of the sequence
INCREMENT BY 1; -- Step to increment the sequence value
-- Step 2: Create a table to use the sequence
CREATE TABLE SequenceDemo (
ID INT PRIMARY KEY,
Name NVARCHAR(50)
);
-- Step 3: Insert data using the sequence
INSERT INTO SequenceDemo (ID, Name)
VALUES (NEXT VALUE FOR TestSeq, 'Alice'),
(NEXT VALUE FOR TestSeq, 'Bob');
-- Step 4: Alter the sequence to restart at a specific value
ALTER SEQUENCE TestSeq RESTART WITH 100;
-- Step 5: Insert more data using the altered sequence
INSERT INTO SequenceDemo (ID, Name)
VALUES (NEXT VALUE FOR TestSeq, 'Charlie');
-- Step 6: Drop the sequence
DROP SEQUENCE TestSeq;
-- Step 7: View data in the table
SELECT * FROM SequenceDemo;
Explanation:
● Creating the Sequence:
○ The CREATE SEQUENCE statement initializes the sequence with a starting value
and increment step.
○ Example: Starts at 1 and increments by 1 for each call.
● Using the Sequence:
○ The NEXT VALUE FOR clause retrieves the next value of the sequence.
○ This value can be used in INSERT statements to auto-generate IDs.
● Altering the Sequence:
○ The ALTER SEQUENCE statement changes the sequence's behavior (e.g.,
restarting at a specific value).
● Dropping the Sequence:
○ The DROP SEQUENCE statement deletes the sequence from the database.
Outcome:
1. Learn to automate ID generation and modify sequences effectively.
2. Creates a sequence for generating unique IDs automatically.
3. Demonstrates how to use the sequence in a table and alter its behavior.
4. Learners can efficiently automate unique identifier creation for tables.
2. Conditional Selection Using IF...ELSE
Question: How do you implement conditional logic in a stored procedure?
Use and Meaning:
Conditional logic allows dynamic execution based on input parameters or conditions, enabling
decision-making in queries or stored procedures.
The IF...ELSE statement in SQL allows conditional execution of different sets of SQL
statements based on whether a specified condition evaluates to TRUE or FALSE. It is
commonly used to implement decision-making logic in stored procedures or scripts.
Script:
-- Step 1: Declare a variable to store input
DECLARE @Age INT = 20;
-- Step 2: Use IF...ELSE to check the condition
IF @Age >= 18
PRINT 'Eligible to Vote'; -- Execute if the condition is TRUE
ELSE
PRINT 'Not Eligible to Vote'; -- Execute if the condition is FALSE
-- Step 3: Example with multiple conditions using ELSE IF
DECLARE @Marks INT = 85;
IF @Marks >= 90
PRINT 'Grade: A+';
ELSE IF @Marks >= 75
PRINT 'Grade: A';
ELSE IF @Marks >= 50
PRINT 'Grade: B';
ELSE
PRINT 'Grade: Fail';
Explanation:
1. Basic IF...ELSE Logic:
○ The IF block executes a SQL statement if the condition evaluates to TRUE.
○ The ELSE block executes if the IF condition evaluates to FALSE.
2. Nested Conditions (ELSE IF):
○ Allows for multiple conditions to be checked in sequence.
○ Useful for scenarios requiring a graded or tiered response.
3. Variables in Conditions:
○ SQL variables (e.g., @Age, @Marks) allow dynamic evaluation of conditions
based on input.
Outcome:
1. Learners can use IF...ELSE for decision-making in SQL scripts or stored
procedures.
2. Gain insights into executing different SQL statements based on conditions.
3. Understand the flexibility of nested conditions for complex decision-making.
4. Understand conditional statements and execute actions based on input.
3. LOOP Statements
Question: How can loops be used to repeatedly execute a set of statements in SQL?
Use and Meaning:
Loops automate repetitive tasks, such as processing or calculating values over multiple
iterations.
Loops in SQL are used to perform repetitive tasks, such as updating records, calculating
values, or processing rows in a dataset. They provide automation, reducing the need for
manual execution of repetitive operations.
Script:
-- Step 1: Declare a variable for the loop
DECLARE @Counter INT = 1;
-- Step 2: Use a WHILE loop to iterate
WHILE @Counter <= 5
BEGIN
-- Print the current counter value
PRINT 'Counter Value: ' + CAST(@Counter AS NVARCHAR);
-- Increment the counter
SET @Counter = @Counter + 1;
END;
-- Step 3: Example of using a loop for table updates
CREATE TABLE LoopDemo (ID INT, Value NVARCHAR(50));
INSERT INTO LoopDemo (ID, Value)
VALUES (1, 'Initial'), (2, 'Initial'), (3, 'Initial');
DECLARE @ID INT = 1;
-- Update table rows in a loop
WHILE @ID <= 3
BEGIN
UPDATE LoopDemo
SET Value = 'Updated Value ' + CAST(@ID AS NVARCHAR)
WHERE ID = @ID;
-- Increment the ID
SET @ID = @ID + 1;
END;
-- Step 4: View updated table
SELECT * FROM LoopDemo;
Explanation:
1. Basic Looping with WHILE:
○ The WHILE loop executes the block of statements as long as the condition
evaluates to TRUE.
○ Example: Iterating through values from 1 to 5.
2. Incrementing Variables:
○ Variables (e.g., @Counter, @ID) are incremented or modified in each iteration to
avoid infinite loops.
3. Practical Use Case – Updating Rows:
○ Loops can iterate over rows in a table to apply updates dynamically, as
demonstrated in the second example.
4. Ending the Loop:
○ The loop ends when the condition evaluates to FALSE. For instance, @Counter
<= 5 becomes FALSE when @Counter is 6.
Outcome:
1. Efficiently execute repetitive processes using loops.
2. Understand the syntax and implementation of WHILE loops in SQL.
3. Learn to perform repetitive operations like updating or processing rows
dynamically.
4. Efficiently automate tasks, reducing manual workload and errors.
4. Creating and Using Stored Procedures
Question: What are stored procedures, and how can you create and execute them in SQL?
Use and Meaning:
Stored procedures encapsulate reusable SQL code for modularity, efficiency, and reduced
redundancy.
A stored procedure is a precompiled collection of SQL statements and logic, stored in the
database. It can be reused, parameterized, and optimized for efficiency. Stored procedures
improve performance, enforce business logic, and simplify complex operations.
Script:
-- Step 1: Create a stored procedure
CREATE PROCEDURE GetEmployeeDetails
@EmployeeID INT
AS
BEGIN
-- Fetch details of the employee with the given ID
SELECT EmployeeID, FirstName, LastName, Department, Salary
FROM Employees
WHERE EmployeeID = @EmployeeID;
END;
-- Step 2: Execute the stored procedure
EXEC GetEmployeeDetails @EmployeeID = 101;
-- Step 3: Create a stored procedure with an INSERT operation
CREATE PROCEDURE AddNewEmployee
@FirstName NVARCHAR(50),
@LastName NVARCHAR(50),
@Department NVARCHAR(50),
@Salary DECIMAL(10, 2)
AS
BEGIN
-- Insert a new employee record
INSERT INTO Employees (FirstName, LastName, Department, Salary)
VALUES (@FirstName, @LastName, @Department, @Salary);
END;
-- Step 4: Execute the INSERT stored procedure
EXEC AddNewEmployee @FirstName = 'John', @LastName = 'Doe', @Department = 'IT',
@Salary = 75000.00;
-- Step 5: View updated table data
SELECT * FROM Employees;
-- Step 6: Alter a stored procedure
ALTER PROCEDURE GetEmployeeDetails
@EmployeeID INT
AS
BEGIN
-- Fetch details with additional columns
SELECT EmployeeID, FirstName, LastName, Department, Salary, HireDate
FROM Employees
WHERE EmployeeID = @EmployeeID;
END;
-- Step 7: Drop the stored procedure
DROP PROCEDURE GetEmployeeDetails;
Explanation:
1. Creating a Stored Procedure:
○ CREATE PROCEDURE defines a procedure with optional parameters.
○ Example: Fetch employee details based on @EmployeeID.
2. Executing a Stored Procedure:
○ EXEC or EXECUTE runs the procedure with required parameters.
○ Example: Fetching data or inserting records.
3. Parameterized Procedures:
○ Allow dynamic input for flexibility, such as inserting or retrieving specific data.
4. Altering a Stored Procedure:
○ ALTER PROCEDURE modifies the definition of an existing procedure.
5. Dropping a Stored Procedure:
○ DROP PROCEDURE removes the procedure from the database.
Outcome:
1. Enhance modular programming and code reuse in SQL.
2. Learners can create and manage reusable SQL scripts with stored procedures.
3. Understand how stored procedures simplify tasks like querying, inserting, and
updating data.
4. Gain insights into dynamic operations through parameterization.
5. Using Functions and Recursion
Question: How do you create a user-defined function and use it for calculations?
Use and Meaning:
Functions simplify repetitive calculations and encapsulate logic for reuse.
Functions in SQL are used to encapsulate reusable logic and computations.
Recursive functions are a special type of function that calls itself to solve problems that can
be broken down into simpler sub-problems, such as calculating factorials, Fibonacci
sequences, or hierarchical data traversal.
Script:
-- Step 1: Create a scalar function to calculate factorial using recursion
CREATE FUNCTION CalculateFactorial (@Number INT)
RETURNS INT
AS
BEGIN
-- Base case: if the number is 0 or 1, return 1
IF @Number = 0 OR @Number = 1
RETURN 1;
-- Recursive case: multiply the number by the factorial of (number - 1)
RETURN @Number * dbo.CalculateFactorial(@Number - 1);
END;
-- Step 2: Use the function to calculate factorial
SELECT dbo.CalculateFactorial(5) AS FactorialValue; -- Output: 120
-- Step 3: Create a table-valued function for Fibonacci series
CREATE FUNCTION GenerateFibonacci (@Count INT)
RETURNS @FibonacciTable TABLE (SequenceNumber INT, FibonacciValue INT)
AS
BEGIN
DECLARE @First INT = 0, @Second INT = 1, @Next INT, @Index INT = 1;
WHILE @Index <= @Count
BEGIN
INSERT INTO @FibonacciTable (SequenceNumber, FibonacciValue)
VALUES (@Index, @First);
-- Calculate the next Fibonacci value
SET @Next = @First + @Second;
SET @First = @Second;
SET @Second = @Next;
SET @Index = @Index + 1;
END;
RETURN;
END;
-- Step 4: Use the table-valued function to get the Fibonacci series
SELECT * FROM dbo.GenerateFibonacci(10);
-- Step 5: Drop the functions when no longer needed
DROP FUNCTION CalculateFactorial;
DROP FUNCTION GenerateFibonacci;
Explanation:
1. Scalar Function for Factorial Calculation:
○ The CalculateFactorial function recursively calculates the factorial of a number.
○ Base case ensures the recursion terminates, and the recursive case reduces the
problem size.
2. Table-Valued Function for Fibonacci Series:
○ Generates a sequence of Fibonacci numbers and returns a table of results.
○ Uses a WHILE loop to iterate until the desired count is reached.
3. Using Functions:
○ Functions are called within SELECT statements for scalar results or as table
sources for tabular results.
4. Dropping Functions:
○ Use DROP FUNCTION to remove user-defined functions when they are no longer
required.
Outcome:
● Learners understand how to create scalar and table-valued functions for computations
and series generation.
● Gain insights into using recursion for solving mathematical and hierarchical problems.
● Learn how functions simplify complex logic and enhance code reusability.
6. Working with Associative Arrays
Question: How can you simulate an associative array using tables in SQL?
Use and Meaning:
Associative arrays provide key-value pair mappings for quick lookups.
Associative arrays, also known as key-value pairs or hash maps, store data as a collection of
unique keys and associated values. In SQL, associative arrays are typically implemented using
collections such as TABLE or ASSOCIATIVE ARRAY types in PL/SQL (Oracle) or SQL Server's
XML and JSON data types. They allow for quick lookups and efficient data storage when
key-value relationships are needed.
Script:
-- Step 1: Declare an XML variable to represent the associative array
DECLARE @AssociativeArray XML;
-- Step 2: Initialize the XML variable with key-value pairs (representing the associative array)
SET @AssociativeArray =
'<Items>
<Item>
<Key>1</Key>
<Value>Apple</Value>
</Item>
<Item>
<Key>2</Key>
<Value>Banana</Value>
</Item>
<Item>
<Key>3</Key>
<Value>Orange</Value>
</Item>
</Items>';
-- Step 3: Query the associative array using XML methods to extract data
SELECT
Item.value('(Key)[1]', 'INT') AS Key,
Item.value('(Value)[1]', 'NVARCHAR(50)') AS Value
FROM @AssociativeArray.nodes('/Items/Item') AS X(Item);
-- Step 4: Retrieve a specific key-value pair
SELECT
Item.value('(Key)[1]', 'INT') AS Key,
Item.value('(Value)[1]', 'NVARCHAR(50)') AS Value
FROM @AssociativeArray.nodes('/Items/Item') AS X(Item)
WHERE Item.value('(Key)[1]', 'INT') = 2;
-- Step 5: Update a value in the associative array
SET @AssociativeArray.modify('
replace value of (/Items/Item[Key="2"]/Value)[1] with "Grapes"');
-- Step 6: View the updated associative array
SELECT @AssociativeArray AS UpdatedAssociativeArray;
Explanation:
1. Using XML for Associative Arrays:
○ XML can be used to create key-value pairs in SQL Server, where the <Key>
element stores the key and the <Value> element stores the corresponding value.
This allows SQL to mimic the behavior of associative arrays.
2. Querying the XML Data:
○ The nodes() method is used to extract each <Item> element.
○ The value() method retrieves the values for the <Key> and <Value>.
3. Filtering Data:
○ You can filter based on the key by specifying the key in the WHERE clause, which
is useful for retrieving a specific key-value pair.
4. Modifying the Array:
○ The modify() method allows you to update a value for a given key in the XML
structure. This simulates the process of updating a value in an associative array.
5. XML Representation:
○ XML is particularly useful for managing hierarchical or nested data and can be a
good fit for situations where associative arrays or key-value stores are required.
Outcome:
● Learners understand how to create and work with associative arrays using SQL Server’s
XML data type.
● Gain knowledge on querying, updating, and managing key-value pairs in SQL.
● Learn to use XML-based associative arrays to handle and store data in a flexible and
efficient way.
7. Error Handling and Exception Propagation
Question: How can you handle errors using TRY...CATCH in SQL Server?
Use and Meaning:
1. Error handling ensures program stability by catching and responding to runtime errors.
2. Error handling in SQL allows you to manage runtime errors gracefully without
terminating the execution of your SQL statements.
3. Exception propagation ensures that errors are passed up the call stack, enabling proper
error management in stored procedures, functions, and triggers.
4. This is especially useful in complex systems where multiple layers of logic are involved,
and errors need to be caught and handled at different levels.
Script:
-- Step 1: Create a stored procedure with error handling
CREATE PROCEDURE HandleErrorExample
AS
BEGIN
BEGIN TRY
-- Simulating an error (dividing by zero)
DECLARE @Result INT;
SET @Result = 10 / 0; -- This will cause a divide-by-zero error
PRINT 'This will not be printed if an error occurs.';
END TRY
BEGIN CATCH
-- Catch the error and handle it
PRINT 'An error occurred: ' + ERROR_MESSAGE(); -- Print the error message
-- Optionally, you can re-throw the error to propagate it
THROW; -- This rethrows the error, propagating it to the caller
END CATCH;
END;
-- Step 2: Execute the stored procedure
EXEC HandleErrorExample;
-- Step 3: Handling errors in a transaction
BEGIN TRY
BEGIN TRANSACTION;
-- Insert a record into a table (Assume a table named Employees)
INSERT INTO Employees (EmployeeID, FirstName, LastName)
VALUES (NULL, 'John', 'Doe'); -- This might cause an error due to NULL EmployeeID
-- Commit the transaction if no errors occur
COMMIT;
END TRY
BEGIN CATCH
-- Rollback the transaction if an error occurs
ROLLBACK;
PRINT 'Error in transaction: ' + ERROR_MESSAGE();
END CATCH;
Explanation:
1. Error Handling with TRY...CATCH:
○ The TRY...CATCH block is used to catch exceptions that occur in the TRY
section and handle them in the CATCH section.
○ If an error occurs, control is passed to the CATCH block, where you can log the
error, print a message, or even propagate the error further.
2. Re-throwing Errors with THROW:
○ The THROW statement is used to propagate the caught exception back to the
calling environment. This is useful when you want to catch an error but still want
it to be handled further up the stack, such as in a calling application or another
procedure.
3. Transaction Management with Error Handling:
○ In the case of a transaction, if an error occurs during any operation (e.g.,
INSERT), the entire transaction can be rolled back using ROLLBACK to maintain
data consistency.
○ The COMMIT statement is only executed if all operations in the TRY block
succeed without errors.
4. Error Functions:
○ ERROR_MESSAGE(): Returns the error message that occurred.
○ ERROR_NUMBER(): Returns the error number.
○ ERROR_SEVERITY(): Returns the severity of the error.
○ ERROR_STATE(): Returns the state number associated with the error.
Outcome:
● Learners can use TRY...CATCH for robust error handling in SQL, ensuring errors are
caught and managed properly.
● Gain knowledge about propagating errors back to the calling environment with THROW.
● Understand how to manage transactions in SQL, ensuring data integrity and
consistency even in case of errors.
8. Using NULL Statements
Question: How do you handle NULL values in SQL queries?
Use and Meaning: NULL handling ensures robust logic when dealing with undefined or
missing data.
Script:
Explanation and Outcome:
● Explanation: Demonstrates handling NULL scenarios in conditional logic.
● Outcome: Prevent errors caused by undefined or missing data.
9. Creating Multidimensional Collections
Question: How can you create and manipulate multidimensional collections in SQL?
Use and Meaning:
Multidimensional collections store complex datasets requiring a row-column structure.
Multidimensional collections allow you to store data in a format where multiple levels of
information are maintained within a single collection. These are commonly used to represent
tabular data, grids, or matrices. In SQL, multidimensional collections can be implemented
using arrays, tables, or nested collections within PL/SQL (Oracle) or SQL Server's XML/JSON
structures. These collections are useful when you need to model data with more than one
dimension, such as a list of lists (2D array) or more complex structures.
-- Step 1: Create a table to simulate a 2D matrix structure using XML
DECLARE @MultiDimensionalCollection XML;
-- Step 2: Initialize the XML variable with multidimensional data (simulating a 2D array)
SET @MultiDimensionalCollection =
'<Matrix>
<Row>
<Column>1</Column>
<Column>2</Column>
<Column>3</Column>
</Row>
<Row>
<Column>4</Column>
<Column>5</Column>
<Column>6</Column>
</Row>
<Row>
<Column>7</Column>
<Column>8</Column>
<Column>9</Column>
</Row>
</Matrix>';
-- Step 3: Query the multidimensional collection to extract data
SELECT
Row.value('(Column)[1]', 'INT') AS Column1,
Row.value('(Column)[2]', 'INT') AS Column2,
Row.value('(Column)[3]', 'INT') AS Column3
FROM @MultiDimensionalCollection.nodes('/Matrix/Row') AS X(Row);
-- Step 4: Access specific row or column data
SELECT
Row.value('(Column)[2]', 'INT') AS Column2
FROM @MultiDimensionalCollection.nodes('/Matrix/Row') AS X(Row)
WHERE Row.exist('(Column[2] = "5")') = 1; -- Find the row where Column2 is 5
-- Step 5: Update an element in the multidimensional collection (modifying the XML)
SET @MultiDimensionalCollection.modify('
replace value of (/Matrix/Row[2]/Column[2])[1] with "10"'); -- Change value from 5 to 10
-- Step 6: View the updated multidimensional collection
SELECT @MultiDimensionalCollection AS UpdatedMatrix;
Explanation:
1. Using XML to Simulate Multidimensional Arrays:
○ In this example, we use XML to represent a 2D array (matrix) with rows and
columns. Each <Row> element contains multiple <Column> elements,
simulating the structure of a 2D array.
2. Accessing Data in the Matrix:
○ The nodes() method is used to iterate over each <Row> in the matrix.
○ The value() method retrieves the value from each column within the row.
Here, we extract all columns for each row.
3. Filtering Data in the Matrix:
○ We use the exist() method to filter rows based on a condition (e.g., looking
for a column value of 5 in the second column).
4. Updating Values in the Matrix:
○ The modify() method is used to change an element's value within the XML
structure, simulating an update to a specific cell in the matrix.
5. Multidimensional Data Representation:
○ Using XML for multidimensional collections allows you to store, query, and
manipulate data in multiple dimensions (like rows and columns) effectively.
Outcome:
● Learners will understand how to use XML to create multidimensional collections in SQL
Server, simulating 2D arrays or matrices.
● Gain knowledge on how to query, filter, and update data in a structured,
multidimensional format.
● Learn how to leverage XML’s powerful querying and modification features for complex
data structures within SQL.
10. Exception Handling for User-Defined Errors
Question: How can you create and handle user-defined exceptions in SQL Server?
Use and Meaning:
User-defined exceptions allow tailored error management for specific scenarios.
User-defined errors allow you to create specific exceptions for custom scenarios in SQL,
which may not be captured by predefined errors. This is useful when you need to handle
specific business logic violations, constraints, or conditions that are unique to your
application or database schema.
Using RAISEERROR in SQL Server (or RAISE in PL/SQL), you can raise custom errors with
detailed messages, error numbers, and state values, and then handle these errors within
TRY...CATCH blocks or exception handling routines.
Script :(Using RAISEERROR)
-- Step 1: Create a stored procedure that checks for a specific condition and raises a
user-defined error
CREATE PROCEDURE CheckSalary
@EmployeeID INT,
@Salary DECIMAL(10, 2)
AS
BEGIN
-- Step 2: Check if the salary provided is negative
IF @Salary < 0
BEGIN
-- Raise a custom error with a message, error number, and state
RAISERROR('Salary cannot be negative.', 16, 1); -- Error severity 16: General errors
RETURN; -- Exit the procedure
END
-- Step 3: Perform a task if the salary is valid (e.g., updating employee salary)
UPDATE Employees
SET Salary = @Salary
WHERE EmployeeID = @EmployeeID;
PRINT 'Salary updated successfully.';
END;
-- Step 4: Execute the stored procedure with valid and invalid input
EXEC CheckSalary @EmployeeID = 1, @Salary = -5000.00; -- This will raise an error
-- Step 5: Handle the error using TRY...CATCH
BEGIN TRY
-- Call the stored procedure with invalid salary
EXEC CheckSalary @EmployeeID = 2, @Salary = -1000.00;
END TRY
BEGIN CATCH
-- Step 6: Catch the error and handle it (e.g., print the error message)
PRINT 'An error occurred: ' + ERROR_MESSAGE();
END CATCH;
-- Step 7: Call with a valid salary to see success
EXEC CheckSalary @EmployeeID = 2, @Salary = 4000.00; -- This will succeed
Explanation:
1. Creating the Procedure:
○ The CheckSalary stored procedure accepts EmployeeID and Salary as
parameters.
○ It checks if the salary is valid (non-negative). If the salary is negative, it raises a
custom error using RAISEERROR.
2. Raising a Custom Error with RAISEERROR:
○ RAISEERROR('message', error_number, state) is used to raise a
user-defined error with a specific message, error number, and state.
■ Example: RAISEERROR('Salary cannot be negative.', 16, 1)
raises an error if the salary is negative.
○ The error severity (16) indicates a general error, and the state (1) can be used to
represent the instance of the error.
3. Handling Errors with TRY...CATCH:
○ The TRY...CATCH block is used to catch and handle errors raised in the
procedure.
○ In the CATCH block, you can retrieve the error message using
ERROR_MESSAGE() and handle the error accordingly.
4. Executing the Procedure:
○ When the procedure is called with a negative salary (-5000 or -1000), the
custom error is raised, and the control jumps to the CATCH block where the error
message is printed.
○ If the salary is valid, the procedure updates the salary and prints a success
message.
Outcome:
● Learners will understand how to create and handle user-defined errors in SQL.
● Gain hands-on experience with using RAISEERROR in SQL Server to raise custom
exceptions for specific business logic errors.
● Learn how to handle these errors using TRY...CATCH and capture detailed
information about the errors that occur during execution.
UNIT 2
1. Cursors: Overview of Cursor, Types of Cursors, Invalid Cursor Exception
Question:
How can you create and use explicit cursors to fetch data, handle cursor exceptions, and
demonstrate invalid cursor handling?
Meaning:
A cursor is a pointer to a context area in SQL that allows you to process query result sets
row by row.
Uses:
Cursors are used when you need to fetch and process rows one at a time, often for complex
logic or row-specific processing.
Script:
-- Step 1: Declare an explicit cursor to fetch employee data
DECLARE @EmployeeID INT, @FirstName NVARCHAR(50), @LastName NVARCHAR(50);
DECLARE employee_cursor CURSOR FOR
SELECT EmployeeID, FirstName, LastName
FROM Employees;
-- Step 2: Open the cursor and fetch data
OPEN employee_cursor;
FETCH NEXT FROM employee_cursor INTO @EmployeeID, @FirstName, @LastName;
-- Step 3: Loop through the cursor and display results
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'EmployeeID: ' + CAST(@EmployeeID AS NVARCHAR) + ', Name: ' + @FirstName + ' ' +
@LastName;
FETCH NEXT FROM employee_cursor INTO @EmployeeID, @FirstName, @LastName;
END;
-- Step 4: Close and deallocate the cursor
CLOSE employee_cursor;
DEALLOCATE employee_cursor;
-- Step 5: Example of an invalid cursor exception (trying to fetch after deallocation)
BEGIN TRY
FETCH NEXT FROM employee_cursor INTO @EmployeeID, @FirstName, @LastName; --
This will raise an error
END TRY
BEGIN CATCH
PRINT 'Error: Invalid cursor operation.';
END CATCH;
Explanation:
● An explicit cursor is declared to fetch employee data from the Employees table.
● The cursor processes rows and prints the employee details.
● An error is generated by trying to fetch data after the cursor is deallocated,
demonstrating the invalid cursor exception.
Outcome:
The cursor fetches data correctly until deallocated. When an invalid cursor operation occurs,
the error handling catches and prints the exception message.
2. Static SQL: Description of Static SQL, Cursors Overview
Question:
How can you process query result sets using static SQL with cursors?
Meaning:
Static SQL refers to SQL queries that are predefined and executed without change each time
they run, as opposed to dynamic SQL which can change at runtime.
Uses:
Used when SQL queries are known in advance and do not need to be altered dynamically
during execution.
Script:
-- Step 1: Declare a cursor to fetch all employee data
DECLARE @EmployeeID INT, @FirstName NVARCHAR(50), @Salary DECIMAL(10, 2);
DECLARE employee_cursor CURSOR STATIC FOR
SELECT EmployeeID, FirstName, Salary
FROM Employees;
-- Step 2: Open and fetch data from the cursor
OPEN employee_cursor;
FETCH NEXT FROM employee_cursor INTO @EmployeeID, @FirstName, @Salary;
-- Step 3: Display results
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'EmployeeID: ' + CAST(@EmployeeID AS NVARCHAR) + ', FirstName: ' + @FirstName
+ ', Salary: ' + CAST(@Salary AS NVARCHAR);
FETCH NEXT FROM employee_cursor INTO @EmployeeID, @FirstName, @Salary;
END;
-- Step 4: Close and deallocate the cursor
CLOSE employee_cursor;
DEALLOCATE employee_cursor;
Explanation:
● This script demonstrates the use of a STATIC cursor that fetches all employee
records.
● A WHILE loop is used to process and display each row retrieved by the cursor.
Outcome:
It prints each employee’s details. The cursor is static, which means the query doesn’t change
during execution, making the execution efficient.
3. Transaction Processing and Control: Autonomous Transactions, Commit Protocol
Question:
How can you implement autonomous transactions and control commits in SQL?
Meaning:
Autonomous transactions are independent transactions within a main transaction, allowing
operations like commit or rollback without affecting the parent transaction.
Uses:
Used when a transaction must execute independently, for example, logging data while
performing a primary task.
Script:
-- Step 1: Create a stored procedure for autonomous transaction
CREATE PROCEDURE UpdateEmployeeSalary
@EmployeeID INT, @NewSalary DECIMAL(10, 2)
AS
BEGIN
-- Start an autonomous transaction
SAVE TRANSACTION SavePoint;
-- Update the employee salary
UPDATE Employees
SET Salary = @NewSalary
WHERE EmployeeID = @EmployeeID;
-- Commit the autonomous transaction
COMMIT TRANSACTION SavePoint;
END;
-- Step 2: Call the procedure to update salary
EXEC UpdateEmployeeSalary @EmployeeID = 1, @NewSalary = 70000.00;
Explanation:
● A stored procedure is created to update an employee's salary with an autonomous
transaction, ensuring the salary update is committed independently.
● A SAVE TRANSACTION is used to set a point for commit.
Outcome:
The salary update occurs without being affected by the surrounding transaction,
demonstrating the autonomous transaction.
4. Deadlocks Handling
Question:
How can you handle deadlocks in SQL Server?
Meaning:
A deadlock occurs when two transactions are waiting for each other to release resources,
causing the transactions to be stuck indefinitely.
Uses:
Handling deadlocks ensures that a system can recover gracefully from situations where
transactions are stuck.
Script:
-- Step 1: Simulate two transactions causing a deadlock
BEGIN TRANSACTION;
UPDATE Employees SET Salary = 50000 WHERE EmployeeID = 1;
WAITFOR DELAY '00:00:05'; -- Simulate delay
UPDATE Employees SET Salary = 60000 WHERE EmployeeID = 2;
BEGIN TRANSACTION;
UPDATE Employees SET Salary = 60000 WHERE EmployeeID = 2;
WAITFOR DELAY '00:00:05'; -- Simulate delay
UPDATE Employees SET Salary = 50000 WHERE EmployeeID = 1;
-- Step 2: Deadlock will occur, SQL Server will automatically handle and resolve it by
terminating one of the transactions.
Explanation:
● The script simulates a deadlock scenario by having two transactions simultaneously
trying to update different rows that each other hold.
● SQL Server automatically resolves deadlocks by terminating one of the transactions.
Outcome:
A deadlock error is raised, and SQL Server resolves the conflict by terminating one of the
transactions.
5. Dynamic SQL: Native Dynamic SQL, SQL Injection
Question:
How can you prevent SQL injection and implement native dynamic SQL?
Meaning:
Dynamic SQL refers to SQL code that is constructed at runtime, allowing flexibility in query
execution.
Uses:
Used to execute SQL commands that are determined dynamically, such as queries where
table names or column names are provided by the user.
Script:
-- Step 1: Using sp_executesql for dynamic SQL to avoid SQL injection
DECLARE @TableName NVARCHAR(50), @SQL NVARCHAR(1000);
SET @TableName = 'Employees';
SET @SQL = 'SELECT * FROM ' + QUOTENAME(@TableName);
-- Step 2: Execute the dynamic SQL
EXEC sp_executesql @SQL;
Explanation:
● sp_executesql is used to execute dynamic SQL safely, avoiding SQL injection.
● The query is built dynamically to select from a table name defined at runtime.
Outcome:
The dynamic SQL executes successfully without causing SQL injection, as input is properly
sanitized.
6. Triggers: Creating Insert Trigger
Question:
How can you create an insert trigger to enforce data integrity?
Meaning:
A trigger is a database object that automatically executes or fires when certain events occur
in the database, like INSERT, UPDATE, or DELETE.
Uses:
Triggers are useful for enforcing data integrity, logging changes, or auditing database
modifications.
Script:
-- Step 1: Create a trigger to enforce a rule when a new employee is inserted
CREATE TRIGGER trg_insert_employee
ON Employees
AFTER INSERT
AS
BEGIN
DECLARE @Salary DECIMAL(10, 2);
SELECT @Salary = Salary FROM inserted;
-- Step 2: Enforce rule: salary must be greater than 0
IF @Salary <= 0
BEGIN
RAISERROR('Salary must be greater than 0.', 16, 1);
ROLLBACK TRANSACTION;
END;
END;
-- Step 3: Insert a record to test the trigger
INSERT INTO Employees (EmployeeID, FirstName, LastName, Salary)
VALUES (6, 'Tom', 'Hanks', -500); -- This will cause an error due to the trigger
Explanation:
● This trigger ensures that any inserted employee record has a salary greater than 0,
enforcing business rules.
● If the condition fails, the transaction is rolled back with an error message.
Outcome:
If an invalid salary (<= 0) is inserted, the trigger raises an error and prevents the insertion,
maintaining data integrity
7. Triggers: Delete Trigger
Question:
How can you create a delete trigger to enforce data integrity?
Meaning:
A delete trigger fires after a delete operation is executed on a table, often used for auditing or
maintaining integrity.
Uses:
Triggers are used to track deleted data or prevent data from being deleted improperly.
Script:
-- Step 1: Create a delete trigger to log deleted employees
CREATE TRIGGER trg_delete_employee
ON Employees
AFTER DELETE
AS
BEGIN
DECLARE @EmployeeID INT, @FirstName NVARCHAR(50), @LastName NVARCHAR(50);
SELECT @EmployeeID = EmployeeID, @FirstName = FirstName, @LastName = LastName
FROM deleted;
-- Step 2: Log the deleted employee to a separate table
INSERT INTO DeletedEmployeesLog (EmployeeID, FirstName, LastName, DeletedDate)
VALUES (@EmployeeID, @FirstName, @LastName, GETDATE());
END;
-- Step 3: Delete a record to test the trigger
DELETE FROM Employees WHERE EmployeeID = 5;
Explanation:
● The trigger logs deleted employee records into a DeletedEmployeesLog table.
● The delete operation on the Employees table triggers this event.
Outcome:
The employee data is logged into the DeletedEmployeesLog table, providing an audit trail
for deleted records.
8. Packages: Overview of Packages
Question:
How can you create and use a package in PL/SQL?
Meaning:
A package in PL/SQL is a collection of related procedures, functions, variables, and types that
are stored together in the database.
Uses:
Packages provide modularization and easier management of related procedures and
functions, improving performance and reusability.
Script:
-- Step 1: Create a package specification
CREATE OR REPLACE PACKAGE EmployeePackage AS
PROCEDURE UpdateSalary(EmployeeID IN INT, NewSalary IN DECIMAL);
FUNCTION GetEmployeeName(EmployeeID IN INT) RETURN VARCHAR2;
END EmployeePackage;
-- Step 2: Create the package body
CREATE OR REPLACE PACKAGE BODY EmployeePackage AS
PROCEDURE UpdateSalary(EmployeeID IN INT, NewSalary IN DECIMAL) IS
BEGIN
UPDATE Employees
SET Salary = NewSalary
WHERE EmployeeID = EmployeeID;
END UpdateSalary;
FUNCTION GetEmployeeName(EmployeeID IN INT) RETURN VARCHAR2 IS
EmployeeName VARCHAR2(100);
BEGIN
SELECT FirstName || ' ' || LastName INTO EmployeeName
FROM Employees
WHERE EmployeeID = EmployeeID;
RETURN EmployeeName;
END GetEmployeeName;
END EmployeePackage;
-- Step 3: Execute the package procedure
EXEC EmployeePackage.UpdateSalary(1, 80000);
SELECT EmployeePackage.GetEmployeeName(1) FROM dual;
Explanation:
● This script defines a Package with a procedure to update salary and a function to
retrieve employee names.
● The package body implements the logic for these operations.
Outcome:
The procedure updates the salary of an employee, and the function retrieves the full name.
The package encapsulates related functionality.
9. Nested Tables: Creating and Using Nested Tables
Question:
How can you create and work with nested tables in PL/SQL?
Meaning:
A nested table is a table data type that allows you to store multiple values in a single column.
Uses:
Nested tables are used when you need to store collections of items (e.g., a list of employees
within a department) within a row.
Script:
-- Step 1: Create a nested table type
CREATE OR REPLACE TYPE EmployeeTable AS TABLE OF VARCHAR2(50);
-- Step 2: Create a table that uses the nested table type
CREATE TABLE DepartmentEmployees (
DepartmentID INT,
Employees EmployeeTable
) NESTED TABLE Employees STORE AS EmployeesTable;
-- Step 3: Insert data into the nested table
INSERT INTO DepartmentEmployees (DepartmentID, Employees)
VALUES (1, EmployeeTable('John', 'Alice', 'Bob'));
-- Step 4: Query the nested table
SELECT * FROM TABLE((SELECT Employees FROM DepartmentEmployees WHERE DepartmentID
= 1));
Explanation:
● A Nested Table type is created for employee names.
● The DepartmentEmployees table stores a nested table of employees for each department.
Outcome:
The nested table stores employee names and allows querying of the employee list for each
department.
10. Triggers: Update Trigger
Question:
How can you create an update trigger to prevent salary modifications to a specific value?
Meaning:
An update trigger is executed automatically when a record is updated in a table. It can be used to
enforce business rules.
Uses:
Used to prevent certain updates or enforce additional logic during record modification.
Script:
-- Step 1: Create an update trigger
CREATE TRIGGER trg_update_employee_salary
ON Employees
AFTER UPDATE
AS
BEGIN
IF UPDATE(Salary)
BEGIN
DECLARE @OldSalary DECIMAL(10, 2), @NewSalary DECIMAL(10, 2);
SELECT @OldSalary = Salary FROM deleted;
SELECT @NewSalary = Salary FROM inserted;
-- Step 2: Prevent salary modification to a specific value
IF @NewSalary = 100000
BEGIN
RAISERROR('Salary cannot be set to 100000.', 16, 1);
ROLLBACK TRANSACTION;
END;
END;
END;
-- Step 3: Update the salary to test the trigger
UPDATE Employees SET Salary =
Explanation:
● This trigger prevents updates to the salary field if the new salary value is 100000.
● It raises an error and rolls back the transaction if the condition is met.
Outcome:
The update is blocked if the salary is set to 100000, ensuring that the business rule is maintained.