Kud Venkat SQL Server Notes
Kud Venkat SQL Server Notes
1|Page
Part 100 - Send datatable as parameter to stored procedure ................................................... 80
Part 101 - Grouping Sets in SQL Server ...................................................................................... 84
Part 102 - Rollup in SQL Server .................................................................................................... 90
Part 103 - Cube in SQL Server ...................................................................................................... 93
Part 104 - Difference between cube and rollup in SQL Server ................................................. 96
Part 105 - Grouping function in SQL Server .............................................................................. 101
Part 106 - GROUPING_ID function in SQL Server ................................................................... 104
Part 107 - Debugging sql server stored procedures ................................................................. 107
Part 108 - Over clause in SQL Server ........................................................................................ 114
Part 109 - Row_Number function in SQL Server ...................................................................... 117
Part 110 - Rank and Dense_Rank in SQL Server..................................................................... 119
Part 111 - Difference between rank dense_rank and row_number in SQL .......................... 123
Part 112 - Calculate running total in SQL Server 2012 ............................................................ 126
Part 113 - NTILE function in SQL Server ................................................................................... 129
Part 114 - Lead and Lag functions in SQL Server 2012 .......................................................... 132
Part 115 - FIRST_VALUE function in SQL Server .................................................................... 135
Part 116 - Window functions in SQL Server .............................................................................. 136
Part 117 - Difference between rows and range ......................................................................... 140
Part 118 - LAST_VALUE function in SQL Server ..................................................................... 143
Part 119 - UNPIVOT in SQL Server ............................................................................................ 145
Part 120 - Reverse PIVOT table in SQL Server ........................................................................ 147
Part 121 - Choose function in SQL Server ................................................................................. 150
Part 122 - IIF function in SQL Server .......................................................................................... 152
Part 123 - TRY_PARSE function in SQL Server 2012 ............................................................. 154
Part 124 - TRY_CONVERT function in SQL Server 2012 ....................................................... 157
Part 125 - EOMONTH function in SQL Server 2012 ............................................................... 161
Part 126 - DATEFROMPARTS function in SQL Server ........................................................... 164
Part 127 - Difference between DateTime and SmallDateTime in SQL Server ..................... 165
Part 128 - DateTime2FromParts function in SQL Server 2012............................................... 166
Part 129 - Difference between DateTime and DateTime2 in SQL Server............................. 167
Part 130 - Offset fetch next in SQL Server 2012 ....................................................................... 170
Part 131 - Identifying object dependencies in SQL Server ...................................................... 173
Part 132 - sys.dm_sql_referencing_entities in SQL Server ..................................................... 176
2|Page
Part 133 - sp_depends in SQL Server ........................................................................................ 177
Part 134 - Sequence object in SQL Server 2012 ...................................................................... 179
Part 135 - Difference between sequence and identity in SQL Server.................................... 182
3|Page
Part 69 - Merge in SQL Server
The merge statement joins the target table to the source table by using a common column in
both the tables. Based on how the rows match up as a result of the join, we can then perform
insert, update, and delete on the target table.
Example 1 : In the example below, INSERT, UPDATE and DELETE are all performed in one
statement
1. When matching rows are found, StudentTarget table is UPDATED (i.e WHEN MATCHED)
2. When the rows are present in StudentSource table but not in StudentTarget table those rows
are INSERTED into StudentTarget table (i.e WHEN NOT MATCHED BY TARGET)
3. When the rows are present in StudentTarget table but not in StudentSource table those rows
are DELETED from StudentTarget table (i.e WHEN NOT MATCHED BY SOURCE)
4|Page
Create table StudentSource
(
ID int primary key,
Name nvarchar(20)
)
GO
5|Page
Insert into StudentTarget values (1, 'Mike M')
Insert into StudentTarget values (3, 'John')
GO
MERGE StudentTarget AS T
USING StudentSource AS S
ON T.ID = S.ID
WHEN MATCHED THEN
UPDATE SET T.NAME = S.NAME
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, NAME) VALUES(S.ID, S.NAME)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
Please Note : Merge statement should end with a semicolon, otherwise you would get an error
stating - A MERGE statement must be terminated by a semi-colon (;)
In real time we mostly perform INSERTS and UPDATES. The rows that are present in target
table but not in source table are usually not deleted from the target table.
Example 2 : In the example below, only INSERT and UPDATE is performed. We are not
deleting the rows that are present in the target table but not in the source table.
6|Page
Truncate table StudentSource
Truncate table StudentTarget
GO
MERGE StudentTarget AS T
USING StudentSource AS S
ON T.ID = S.ID
WHEN MATCHED THEN
7|Page
UPDATE SET T.NAME = S.NAME
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, NAME) VALUES(S.ID, S.NAME);
What is a transaction
A transaction is a group of commands that change the data stored in a database. A transaction,
is treated as a single unit of work. A transaction ensures that, either all of the commands
succeed, or none of them. If one of the commands in the transaction fails, all of the commands
fail, and any data that was modified in the database is rolled back. In this way, transactions
maintain the integrity of data in a database.
Example : The following transaction ensures that both the UPDATE statements succeed or
both of them fail if there is a problem with one UPDATE statement.
Databases are powerful systems and are potentially used by many users or applications at the
8|Page
same time. Allowing concurrent transactions is essential for performance but may introduce
concurrency issues when two or more transactions are working with the same data at the same
time.
Dirty Reads
Lost Updates
Nonrepeatable Reads
Phantom Reads
We will discuss what these problems are in detail with examples in our upcomning videos
One way to solve all these concurrency problems is by allowing only one user to execute, only
one transaction at any point in time. Imagine what could happen if you have a large database
with several users who want to execute several transactions. All the transactions get queued
and they may have to wait a long time before they could get a chance to execute their
transactions. So you are getting poor performance and the whole purpose of having a powerful
database system is defeated if you serialize access this way.
At this point you might be thinking, for best performance let us allow all transactions to execute
concurrently. The problem with this approach is that it may cause all sorts of concurrency
problems (i.e Dirty Reads, Lost Updates, Nonrepeatable Reads, Phantom Reads) if two or more
transactions work with the same data at the same time.
SQL Server provides different transaction isolation levels, to balance concurrency problems
and performance depending on our application needs.
Read Uncommitted
Read Committed
Repeatable Read
Snapshot
Serializable
The isolation level that you choose for your transaction, defines the degree to which one
transaction must be isolated from resource or data modifications made by other transactions.
Depending on the isolation level you have chosen you get varying degrees of performance and
concurrency problems. The table here has the list of isoltaion levels along with concurrency side
effects.
Isolation Level Dirty Reads Lost Update Nonrepeatable Reads Phantom Reads
Read Uncommitted Yes Yes Yes Yes
Read Committed No Yes Yes Yes
Repeatable Read No No No Yes
Snapshot No No No No
Serializable No No No No
9|Page
If you choose the lowest isolation level (i.e Read Uncommitted), it increases the number of
concurrent transactions that can be executed at the same time, but the down side is you have
all sorts of concurrency issues. On the other hand if you choose the highest isolation level (i.e
Serializable), you will have no concurrency side effects, but the downside is that, this will reduce
the number of concurrent transactions that can be executed at the same time if those
transactions work with same data.
In our upcoming videos we will discuss the concurrency problems in detail with examples
In this video we will discuss, dirty read concurrency problem with an example. This is
continuation to Part 70. Please watch Part 70 from SQL Server tutorial for beginners.
A dirty read happens when one transaction is permitted to read data that has been modified by
another transaction that has not yet been committed. In most cases this would not cause a
problem. However, if the first transaction is rolled back after the second reads the data, the
second transaction has dirty data that does not exist anymore.
Table tblInventory
Dirty Read Example : In the example below, Transaction 1, updates the value of ItemsInStock
to 9. Then it starts to bill the customer. While Transaction 1 is still in progress, Transaction 2
starts and reads ItemsInStock value which is 9 at the moment. At this point, Transaction 1 fails
because of insufficient funds and is rolled back. The ItemsInStock is reverted to the original
value of 10, but Transaction 2 is working with a different value (i.e 10).
10 | P a g e
Transaction 1 :
Begin Tran
Update tblInventory set ItemsInStock = 9 where Id=1
Rollback Transaction
Transaction 2 :
Set Transaction Isolation Level Read Uncommitted
Select * from tblInventory where Id=1
Read Uncommitted transaction isolation level is the only isolation level that has dirty read side
effect. This is the least restrictive of all the isolation levels. When this transaction isolation level
is set, it is possible to read uncommitted or dirty data. Another option to read dirty data is by
using NOLOCK table hint. The query below is equivalent to the query in Transaction 2.
In this video we will discuss, lost update problem in sql server with an example.
Lost update problem happens when 2 transactions read and update the same data. Let's
11 | P a g e
understand this with an example. We will use the following table tblInventory for this example.
As you can see in the diagram below there are 2 transactions - Transaction 1 and Transaction
2. Transaction 1 starts first, and it is processing an order for 1 iPhone. It sees ItemsInStock as
10.
At this time Transaction 2 is processing another order for 2 iPhones. It also sees ItemsInStock
as 10. Transaction 2 makes the sale first and updates ItemsInStock with a value of 8.
At this point Transaction 1 completes the sale and silently overwrites the update of Transaction
2. As Transaction 1 sold 1 iPhone it has updated ItemsInStock to 9, while it actually should have
updated it to 7.
Example : The lost update problem example. Open 2 instances of SQL Server Management
studio. From the first window execute Transaction 1 code and from the second window, execute
Transaction 2 code. Transaction 1 is processing an order for 1 iPhone, while Transaction 2 is
processing an order for 2 iPhones. At the end of both the transactions ItemsInStock must be 7,
but we have a value of 9. This is because Transaction 1 silently overwrites the update of
Transaction 2. This is called the lost update problem.
-- Transaction 1
Begin Tran
12 | P a g e
Declare @ItemsInStock int
Update tblInventory
Set ItemsInStock = @ItemsInStock where Id=1
Print @ItemsInStock
Commit Transaction
-- Transaction 2
Begin Tran
Declare @ItemsInStock int
Update tblInventory
Set ItemsInStock = @ItemsInStock where Id=1
Print @ItemsInStock
Commit Transaction
Both Read Uncommitted and Read Committed transaction isolation levels have the lost update
side effect. Repeatable Read, Snapshot, and Serializable isolation levels does not have this
side effect. If you run the above Transactions using any of the higher isolation levels
(Repeatable Read, Snapshot, or Serializable) you will not have lost update problem. The
repeatable read isolation level uses additional locking on rows that are read by the current
transaction, and prevents them from being updated or deleted elsewhere. This solves the lost
update problem.
13 | P a g e
For both the above transactions, set Repeatable Read Isolation Level. Run Transaction 1 first
and then a few seconds later run Transaction 2. Transaction 1 completes successfully, but
Transaction 2 competes with the following error.
Transaction was deadlocked on lock resources with another process and has been chosen as
the deadlock victim. Rerun the transaction.
In this video we will discuss non repeatable read concurrency problem with an example.
Non repeatable read problem happens when one transaction reads the same data twice and
another transaction updates that data in between the first and second read of transaction one.
The following diagram explains the problem : Transaction 1 starts first. Reads ItemsInStock.
Gets a value of 10 for first read. Transaction 1 is doing some work and at this point Transaction
2 starts and UpdatesItemsInStock to 5. Transaction 1 then makes a second read. At this point
Transaction 1 gets a value of 5, reulting in non-repeatable read problem.
14 | P a g e
Non-repeatable read example : Open 2 instances of SQL Server Management studio. From
the first window execute Transaction 1 code and from the second window, execute Transaction
2 code. Notice that when Transaction 1 completes, it gets different values for read 1 and read 2,
resulting in non-repeatable read.
-- Transaction 1
Begin Transaction
Select ItemsInStock from tblInventory where Id = 1
-- Do Some work
waitfor delay '00:00:10'
-- Transaction 2
Update tblInventory set ItemsInStock = 5 where Id = 1
Repeatable read or any other higher isolation level should solve the non-repeatable read
problem.
Fixing non repeatable read concurrency problem : To fix the non-repeatable read problem,
set transaction isolation level of Transaction 1 to repeatable read. This will ensure that the data
that Transaction 1 has read, will be prevented from being updated or deleted elsewhere. This
15 | P a g e
solves the non-repeatable read problem.
When you execute Transaction 1 and 2 from 2 different instances of SQL Server management
studio, Transaction 2 is blocked until Transaction 1 completes and at the end of Transaction 1,
both the reads get the same value for ItemsInStock.
-- Transaction 1
Set transaction isolation level repeatable read
Begin Transaction
Select ItemsInStock from tblInventory where Id = 1
-- Do Some work
waitfor delay '00:00:10'
-- Transaction 2
Update tblInventory set ItemsInStock = 5 where Id = 1
In this video we will discuss phantom read concurrency problem with examples.
Phantom read happens when one transaction executes a query twice and it gets a different
number of rows in the result set each time. This happens when a second transaction inserts a
new row that matches the WHERE clause of the query executed by the first transaction.
16 | P a g e
Go
The following diagram explains the problem : Transaction 1 starts first. Reads from Emp
table where Id between 1 and 3. 2 rows retrieved for first read. Transaction 1 is doing some
work and at this point Transaction 2 starts and inserts a new employee with Id = 2. Transaction
1 then makes a second read. 3 rows retrieved for second read, reulting in phantom read
problem.
Phantom read example : Open 2 instances of SQL Server Management studio. From the first
window execute Transaction 1 code and from the second window, execute Transaction 2 code.
Notice that when Transaction 1 completes, it gets different number of rows for read 1 and read
2, resulting in phantom read.
-- Transaction 1
Begin Transaction
Select * from tblEmployees where Id between 1 and 3
-- Do Some work
waitfor delay '00:00:10'
Select * from tblEmployees where Id between 1 and 3
Commit Transaction
-- Transaction 2
Insert into tblEmployees values(2, 'Marcus')
17 | P a g e
Serializable or any other higher isolation level should solve the phantom read problem.
Fixing phantom read concurrency problem : To fix the phantom read problem, set
transaction isolation level of Transaction 1 to serializable. This will place a range lock on the
rows between 1 and 3, which prevents any other transaction from inserting new rows with in that
range. This solves the phantom read problem.
When you execute Transaction 1 and 2 from 2 different instances of SQL Server management
studio, Transaction 2 is blocked until Transaction 1 completes and at the end of Transaction 1,
both the reads get the same number of rows.
-- Transaction 1
Set transaction isolation level serializable
Begin Transaction
Select * from tblEmployees where Id between 1 and 3
-- Do Some work
waitfor delay '00:00:10'
Select * from tblEmployees where Id between 1 and 3
Commit Transaction
-- Transaction 2
18 | P a g e
In this video we will discuss, snapshot isolation level in sql server with examples.
As you can see from the table below, just like serializable isolation level, snapshot isolation level
does not have any concurrency side effects.
Snapshot isolation doesn't acquire locks, it maintains versioning in Tempdb. Since, snapshot
isolation does not lock resources, it can significantly increase the number of concurrent
transactions while providing the same level of data consistency as serializable isolation does.
Let us understand Snapshot isolation with an example. We will be using the following table
tblInventory for this example.
Open 2 instances of SQL Server Management studio. From the first window execute
Transaction 1 code and from the second window execute Transaction 2 code. Notice that
Transaction 2 is blocked until Transaction 1 is completed.
--Transaction 1
Set transaction isolation level serializable
Begin Transaction
Update tblInventory set ItemsInStock = 5 where Id = 1
waitfor delay '00:00:10'
Commit Transaction
-- Transaction 2
Set transaction isolation level serializable
Select ItemsInStock from tblInventory where Id = 1
Now change the isolation level of Transaction 2 to snapshot. To set snapshot isolation level, it
must first be enabled at the database level, and then set the transaction isolation level to
19 | P a g e
snapshot.
-- Transaction 2
-- Enable snapshot isloation for the database
Alter database SampleDB SET ALLOW_SNAPSHOT_ISOLATION ON
-- Set the transaction isolation level to snapshot
Set transaction isolation level snapshot
Select ItemsInStock from tblInventory where Id = 1
From the first window execute Transaction 1 code and from the second window, execute
Transaction 2 code. Notice that Transaction 2 is not blocked and returns the data from the
database as it was before Transaction 1 has started.
Modifying data with snapshot isolation level : Now let's look at an example of what happens
when a transaction that is using snapshot isolation tries to update the same data that another
transaction is updating at the same time.
In the following example, Transaction 1 starts first and it is updating ItemsInStock to 5. At the
same time, Transaction 2 that is using snapshot isolation level is also updating the same data.
Notice that Transaction 2 is blocked until Transaction 1 completes. When Transaction 1
completes, Transaction 2 fails with the following error to prevent concurrency side effect - Lost
update. If Transaction 2 was allowed to continue, it would have changed the ItemsInStock value
to 8 and when Transaction 1 completes it overwrites ItemsInStock to 5, which means we have
lost an update. To complete the work that Transaction 2 is doing we will have to rerun the
transaction.
Snapshot isolation transaction aborted due to update conflict. You cannot use snapshot
isolation to access table 'dbo.tblInventory' directly or indirectly in database 'SampleDB' to
update, delete, or insert the row that has been modified or deleted by another transaction. Retry
the transaction or change the isolation level for the update/delete statement.
--Transaction 1
Set transaction isolation level serializable
Begin Transaction
Update tblInventory set ItemsInStock = 5 where Id = 1
waitfor delay '00:00:10'
Commit Transaction
-- Transaction 2
-- Enable snapshot isloation for the database
Alter database SampleDB SET ALLOW_SNAPSHOT_ISOLATION ON
-- Set the transaction isolation level to snapshot
Set transaction isolation level snapshot
Update tblInventory set ItemsInStock = 8 where Id = 1
20 | P a g e
Part 76 - Read committed snapshot isolation level in sql server
In this video we will discuss Read committed snapshot isolation level in sql server. This is
continuation Part 75. Please watch Part 75 from SQL Server tutorial before proceeding.
Read committed snapshot isolation level is not a different isolation level. It is a different way of
implementing Read committed isolation level. One problem we have with Read Committed
isloation level is that, it blocks the transaction if it is trying to read the data, that another
transaction is updating at the same time.
The following example demonstrates the above point. Open 2 instances of SQL Server
Management studio. From the first window execute Transaction 1 code and from the second
window execute Transaction 2 code. Notice that Transaction 2 is blocked until Transaction 1 is
completed.
--Transaction 1
Set transaction isolation level Read Committed
Begin Transaction
Update tblInventory set ItemsInStock = 5 where Id = 1
waitfor delay '00:00:10'
Commit Transaction
-- Transaction 2
Set transaction isolation level read committed
Begin Transaction
Select ItemsInStock from tblInventory where Id = 1
Commit Transaction
We can make Transaction 2 to use row versioning technique instead of locks by enabling Read
committed snapshot isolation at the database level. Use the following command to enable
READ_COMMITTED_SNAPSHOT isolation
Alter database SampleDB SET READ_COMMITTED_SNAPSHOT ON
Please note : For the above statement to execute successfully all the other database
connections should be closed.
21 | P a g e
Transaction 2 is now using Read committed snapshot isolation level.
Let's see if we can achieve the same thing using snapshot isolation level instead of read
committed snapshot isolation level.
Step 3 : Execute Transaction 1 first and then Transaction 2 simultaneously. Just like in the
previous example, notice that the Transaction 2 is not blocked. It immediately returns the
committed data that is in the database before Transaction 1 started.
--Transaction 1
Set transaction isolation level Read Committed
Begin Transaction
Update tblInventory set ItemsInStock = 5 where Id = 1
waitfor delay '00:00:10'
Commit Transaction
-- Transaction 2
Set transaction isolation level snapshot
Begin Transaction
Select ItemsInStock from tblInventory where Id = 1
Commit Transaction
So what is the point in using read committed snapshot isolation level over snapshot
isolation level?
There are some differences between read committed snapshot isolation level and snapshot
isolation level. We will discuss these in our next video.
In this video we will discuss the differences between snapshot isolation and read committed
snapshot isolation in sql server. This is continuation to Parts 75 and 76. Please watch Part
75 and 76 from SQL Server tutorial before proceeding.
22 | P a g e
Works with existing applications without requiring Application change may be required to use
any change to the application with an existing application
Can be used with distributed transactions Cannot be used with distributed transactions
Provides statement-level read consistency Provides transaction-level read consistency
Enable Snapshot Isolation for the SampleDB database using the following command
Alter database SampleDB SET ALLOW_SNAPSHOT_ISOLATION ON
Open 2 instances of SQL Server Management studio. From the first window execute
Transaction 1 code and from the second window execute Transaction 2 code. Notice that
Transaction 2 is blocked until Transaction 1 is completed. When Transaction 1 completes,
Transaction 2 raises an update conflict and the transaction terminates and rolls back with an
error.
--Transaction 1
Set transaction isolation level snapshot
Begin Transaction
Update tblInventory set ItemsInStock = 8 where Id = 1
waitfor delay '00:00:10'
Commit Transaction
-- Transaction 2
Set transaction isolation level snapshot
Begin Transaction
Update tblInventory set ItemsInStock = 5 where Id = 1
Commit Transaction
Now let's try the same thing using Read Committed Sanpshot Isolation
Step 1 : Disable Snapshot Isolation for the SampleDB database using the following command
Alter database SampleDB SET ALLOW_SNAPSHOT_ISOLATION OFF
Step 2 : Enable Read Committed Sanpshot Isolation at the database level using the following
command
23 | P a g e
Alter database SampleDB SET READ_COMMITTED_SNAPSHOT ON
Step 3 : Open 2 instances of SQL Server Management studio. From the first window execute
Transaction 1 code and from the second window execute Transaction 2 code. Notice that
Transaction 2 is blocked until Transaction 1 is completed. When Transaction 1 completes,
Transaction 2 also completes successfully without any update conflict.
--Transaction 1
Set transaction isolation level read committed
Begin Transaction
Update tblInventory set ItemsInStock = 8 where Id = 1
waitfor delay '00:00:10'
Commit Transaction
-- Transaction 2
Set transaction isolation level read committed
Begin Transaction
Update tblInventory set ItemsInStock = 5 where Id = 1
Commit Transaction
Existing application : If your application is using the default Read Committed isolation level,
you can very easily make the application to use Read Committed Snapshot Isolation without
requiring any change to the application at all. All you need to do is turn on
READ_COMMITTED_SNAPSHOT option in the database, which will change read committed
isolation to use row versioning when reading the committed data.
Transaction 2 has 2 select statements. Notice that both of these select statements return
different data. This is because Read Committed Snapshot Isolation returns the last committed
data before the select statement began and not the last committed data before the transaction
began.
24 | P a g e
In the following example, both the select statements of Transaction 2 return same data. This is
because Snapshot Isolation returns the last committed data before the transaction began and
25 | P a g e
not the last committed data before the select statement began.
26 | P a g e
Part 78 - SQL Server deadlock example
In this video we will discuss a scenario when a deadlock can occur in SQL Server.
When deadlocks occur, SQL Server will choose one of processes as the deadlock victim and
rollback that process, so the other process can move forward. The transaction that is chosen as
the deadlock victim will produce the following error.
Msg 1205, Level 13, State 51, Line 1
Transaction (Process ID 57) was deadlocked on lock resources with another process and has
been chosen as the deadlock victim. Rerun the transaction.
Let us look at this in action. We will use the following 2 tables for this example.
SQL script to create the tables and populate them with test data
Create table TableA
(
Id int identity primary key,
27 | P a g e
Name nvarchar(50)
)
Go
Go
The following 2 transactions will result in a dead lock. Open 2 instances of SQL Server
Management studio. From the first window execute Transaction 1 code and from the second
window execute Transaction 2 code.
-- Transaction 1
Begin Tran
Update TableA Set Name = 'Mark Transaction 1' where Id = 1
-- Transaction 2
Begin Tran
Update TableB Set Name = 'Mark Transaction 2' where Id = 1
28 | P a g e
-- After a few seconds notice that one of the transactions complete
-- successfully while the other transaction is made the deadlock victim
Commit Transaction
Next Video : We will discuss the criteria SQL Server uses to choose a deadlock victim
What is DEADLOCK_PRIORITY
By default, SQL Server chooses a transaction as the deadlock victim that is least expensive to
roll back. However, a user can specify the priority of sessions in a deadlock situation using the
SET DEADLOCK_PRIORITY statement. The session with the lowest deadlock priority is chosen
as the deadlock victim.
DEADLOCK_PRIORITY
1. The default is Normal
2. Can be set to LOW, NORMAL, or HIGH
3. Can also be set to a integer value in the range of -10 to 10.
29 | P a g e
LOW : -5
NORMAL : 0
HIGH : 5
Open 2 instances of SQL Server Management studio. From the first window execute
Transaction 1 code and from the second window execute Transaction 2 code. We have not
explicitly set DEADLOCK_PRIORITY, so both the sessions have the default
DEADLOCK_PRIORITY which is NORMAL. So in this case SQL Server is going to choose
Transaction 2 as the deadlock victim as it is the least expensive one to rollback.
-- Transaction 1
30 | P a g e
Begin Tran
Update TableA Set Name = Name + ' Transaction 1' where Id IN (1, 2, 3, 4, 5)
-- Transaction 2
Begin Tran
Update TableB Set Name = Name + ' Transaction 2' where Id = 1
Update TableA Set Name = Name + ' Transaction 2' where Id IN (1, 2, 3, 4, 5)
-- After a few seconds notice that this transaction will be chosen as the deadlock
-- victim as it is less expensive to rollback this transaction than Transaction 1
Commit Transaction
-- Transaction 1
Begin Tran
Update TableA Set Name = Name + ' Transaction 1' where Id IN (1, 2, 3, 4, 5)
-- Transaction 2
SET DEADLOCK_PRIORITY HIGH
GO
31 | P a g e
Begin Tran
Update TableB Set Name = Name + ' Transaction 2' where Id = 1
Update TableA Set Name = Name + ' Transaction 2' where Id IN (1, 2, 3, 4, 5)
In this video we will discuss how to write the deadlock information to the SQL Server error
log
When deadlocks occur, SQL Server chooses one of the transactions as the deadlock victim
and rolls it back. There are several ways in SQL Server to track down the queries that are
causing deadlocks. One of the options is to use SQL Server trace flag 1222 to write the
deadlock information to the SQL Server error log.
Enable Trace flag : To enable trace flags use DBCC command. -1 parameter indicates that the
trace flag must be set at the global level. If you omit -1 parameter the trace flag will be set only
at the session level.
The following SQL code generates a dead lock. This is the same code we discussed inPart
78 of SQL Server Tutorial.
--SQL script to create the tables and populate them with test data
Create table TableA
(
Id int identity primary key,
Name nvarchar(50)
)
32 | P a g e
Go
Open 2 instances of SQL Server Management studio. From the first window
executespTransaction1 and from the second window execute spTransaction2.
After a few seconds notice that one of the transactions complete successfully while the other
transaction is made the deadlock victim and rollback.
33 | P a g e
The information about this deadlock should now have been logged in sql server error log.
Next video : How to read and understand the deadlock information that is logged in the sql
server error log
In this video we will discuss how to read and analyze sql server deadlock information
captured in the error log, so we can understand what's causing the deadlocks and take
appropriate actions to prevent or minimize the occurrence of deadlocks. This is continuation
to Part 80. Please watch Part 80 from SQL Server tutorial before proceeding.
Process List : The process list has lot of items. Here are some of them that are particularly
useful in understanding what caused the deadlock.
Node Description
loginname The loginname associated with the process
isolationlevel What isolation level is used
procname The stored procedure name
Inputbuf The code the process is executing when the deadlock occured
Resource List : Some of the items in the resource list that are particularly useful in
understanding what caused the deadlock.
Node Description
objectname Fully qualified name of the resource involved in the deadlock
Contains (owner id) the id of the owning process and the lock mode it has acquired
on the resource. lock mode determines how the resource can be accessed by
owner-list
concurrent transactions. S for Shared lock, U for Update lock, X for Exclusive lock
etc
34 | P a g e
Contains (waiter id) the id of the process that wants to acquire a lock on the
waiter-list
resource and the lock mode it is requesting
To prevent the deadlock that we have in our case, we need to ensure that database objects
(Table A & Table B) are accessed in the same order every time.
In this video we will discuss how to capture deadlock graph using SQL profiler.
To capture deadlock graph, all you need to do is add Deadlock graph event to the trace in SQL
profiler.
4. On the "Events Selection" tab, expand "Locks" section and select "Deadlock
graph" event
35 | P a g e
5. Finally click the Run button to start the trace
6. At this point execute the code that causes deadlock
7. The deadlock graph should be captured in the profiler as shown below.
The deadlock graph data is captured in XML format. If you want to extract this XML data to a
physical file for later analysis, you can do so by following the steps below.
1. In SQL profiler, click on "File - Export - Extract SQL Server Events - Extract Deadlock
Events"
2. Provide a name for the file
3. The extension for the deadlock xml file is .xdl
4. Finally choose if you want to export all events in a single file or each event in a separate file
36 | P a g e
The deadlock information in the XML file is similar to what we have captured using the trace flag
1222.
Server Process Id : If you are using SQL Server Management Studio you can see the
server process id on information bar at the bottom.
Deadlock Priority : If you have not set DEADLOCK PRIORITY explicitly using SET
DEADLOCK PRIORITY statement, then both the processes should have the same default
deadlock priority NORMAL (0).
Log Used : The transaction log space used. If a transaction has used a lot of log space
then the cost to roll it back is also more. So the transaction that has used the least log space is
killed and rolled back.
5. The rectangles represent the resource nodes.
HoBt ID : Heap Or Binary Tree ID. Using this ID query sys.partitions view to find the
database objects involved in the deadlock.
SELECT object_name([object_id])
FROM sys.partitions
WHERE hobt_id = 72057594041663488
6. The arrows represent types of locks each process has on each resource node.
In this video we will discuss how to catch deadlock error using try/catch in SQL Server.
Modify the stored procedure as shown below to catch the deadlock error. The code is
commented and is self-explanatory.
37 | P a g e
Begin Try
Update TableA Set Name = 'Mark Transaction 1' where Id = 1
Waitfor delay '00:00:05'
Update TableB Set Name = 'Mary Transaction 1' where Id = 1
-- If both the update statements succeeded.
-- No Deadlock occurred. So commit the transaction.
Commit Transaction
Select 'Transaction Successful'
End Try
Begin Catch
-- Check if the error is deadlock error
If(ERROR_NUMBER() = 1205)
Begin
Select 'Deadlock. Transaction failed. Please retry'
End
-- Rollback the transaction
Rollback
End Catch
End
After modifying the stored procedures, execute both the procedures from 2 different windows
38 | P a g e
simultaneously. Notice that the deadlock error is handled by the catch block.
In our next video, we will discuss how applications using ADO.NET can handle deadlock
errors.
In this video we will discuss how to handle deadlock errors in an ADO.NET application.
WebForm1.aspx HTML
<table>
<tr>
<td>
<asp:Button ID="Button1" runat="server"
Text="Update Table A and then Table B"
39 | P a g e
OnClick="Button1_Click" />
</td>
</tr>
<tr>
<td>
<asp:Label ID="Label1" runat="server"></asp:Label>
</td>
</tr>
</table>
WebForm1.aspx.cs code
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace Demo
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{}
40 | P a g e
{
Label1.Text = "Deadlock. Please retry";
}
else
{
Label1.Text = ex.Message;
}
Label1.ForeColor = System.Drawing.Color.Red;
}
}
}
}
WebForm2.aspx HTML
<table>
<tr>
<td>
<asp:Button ID="Button1" runat="server"
Text="Update Table B and then Table A"
OnClick="Button1_Click" />
</td>
</tr>
<tr>
<td>
<asp:Label ID="Label1" runat="server"></asp:Label>
</td>
</tr>
</table>
WebForm2.aspx.cs code
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace Demo
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{}
41 | P a g e
protected void Button1_Click(object sender, EventArgs e)
{
try
{
string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand("spTransaction1", con);
cmd.CommandType = CommandType.StoredProcedure;
con.Open();
cmd.ExecuteNonQuery();
Label1.Text = "Transaction successful";
Label1.ForeColor = System.Drawing.Color.Green;
}
}
catch (SqlException ex)
{
if (ex.Number == 1205)
{
Label1.Text = "Deadlock. Please retry";
}
else
{
Label1.Text = ex.Message;
}
Label1.ForeColor = System.Drawing.Color.Red;
}
}
}
}
In this video we will discuss implementing retry logic for deadlock exceptions.
This is continuation to Part 84. Please watch Part 84, before proceeding.
When a transaction fails due to deadlock, we can write some logic so the system can resubmit
the transaction. The deadlocks usually last for a very short duration. So upon resubmitting the
transaction it may complete successfully. This is much better from user experience standpoint.
42 | P a g e
To achieve this we will be using the following technologies
C#
ASP.NET
SQL Server
jQuery AJAX
Result.cs
public class Result
{
public int AttemptsLeft { get; set; }
public string Message { get; set; }
public bool Success { get; set; }
}
function updateData() {
$.ajax({
url: 'WebForm1.aspx/CallStoredProcedure',
method: 'post',
contentType: 'application/json',
data: '{attemptsLeft:' + attemptsLeft + '}',
dataType: 'json',
success: function (data) {
lblMessage.text(data.d.Message);
attemptsLeft = data.d.AttemptsLeft;
if (data.d.Success) {
$('#btn').prop('disabled', false);
lblMessage.css('color','green');
}
else if(attemptsLeft > 0){
lblMessage.css('color', 'red');
updateData();
43 | P a g e
}
else {
lblMessage.css('color', 'red');
lblMessage.text('Deadlock Occurred. ZERO attempts left. Please try later');
}
},
error: function (err) {
lblMessage.css('color', 'red');
lblMessage.text(err.responseText);
}
});
}
$('#btn').click(function () {
$(this).prop('disabled', true);
lblMessage.text('Updating....');
attemptsLeft = 5;
updateData();
});
});
</script>
</head>
<body style="font-family: Arial">
<form id="form1" runat="server">
<input id="btn" type="button"
value="Update Table A and then Table B" />
<br />
<asp:Label ID="Label1" runat="server"></asp:Label>
</form>
</body>
</html>
WebForm1.aspx.cs code
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace Demo
{
public partial class WebForm1 : System.Web.UI.Page
44 | P a g e
{
protected void Page_Load(object sender, EventArgs e)
{}
[System.Web.Services.WebMethod]
public static Result CallStoredProcedure(int attemptsLeft)
{
Result _result = new Result();
if (attemptsLeft > 0)
{
try
{
string cs =ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand("spTransaction15", con);
cmd.CommandType = CommandType.StoredProcedure;
con.Open();
cmd.ExecuteNonQuery();
_result.Message = "Transaction successful";
_result.AttemptsLeft = 0;
_result.Success = true;
}
}
catch (SqlException ex)
{
if (ex.Number == 1205)
{
_result.AttemptsLeft = attemptsLeft - 1;
_result.Message = "Deadlock occurred. Retrying. Attempts left : "
+ _result.AttemptsLeft.ToString();
}
else
{
throw;
}
_result.Success = false;
}
}
return _result;
}
45 | P a g e
}
}
Copy and paste the above code in WebForm2.aspx and make the required changes as
described in the video.
In this video we will discuss, how to find blocking queries in sql server.
Blocking occurs if there are open transactions. Let us understand this with an example.
Now from a different window, execute any of the following commands. Notice that all the queries
are blocked.
Select Count(*) from TableA
Delete from TableA where Id = 1
Truncate table TableA
Drop table TableA
This is because there is an open transaction. Once the open transaction completes, you will be
able to execute the above queries.
So the obvious next question is - How to identify all the active transactions.
One way to do this is by using DBCC OpenTran. DBCC OpenTran will display only the oldest
active transaction. It is not going to show you all the open transactions.
DBCC OpenTran
The following link has the SQL script that you can use to identify all the active transactions.
http://www.sqlskills.com/blogs/paul/script-open-transactions-with-text-and-plans
The beauty about this script is that it has a lot more useful information about the open
transactions
Session Id
Login Name
Database Name
Transaction Begin Time
The actual query that is executed
46 | P a g e
You can now use this information and ask the respective developer to either commit or rollback
the transactions that they have left open unintentionally.
For some reason if the person who initiated the transaction is not available, you also have the
option to KILL the associated process. However, this may have unintended consequences, so
use it with extreme caution.
In this video we will discuss SQL Server except operator with examples.
EXCEPT operator returns unique rows from the left query that aren’t in the right query’s results.
47 | P a g e
SQL Script to create the tables
Create Table TableA
(
Id int primary key,
Name nvarchar(50),
Gender nvarchar(10)
)
Go
48 | P a g e
Notice that the following query returns the unique rows from the left query that aren’t in the right
query’s results.
Select Id, Name, Gender
From TableA
Except
Select Id, Name, Gender
From TableB
Result :
To retrieve all of the rows from Table B that does not exist in Table A, reverse the two queries
as shown below.
Select Id, Name, Gender
From TableB
Except
Select Id, Name, Gender
From TableA
Result :
You can also use Except operator on a single table. Let's use the following tblEmployees table
for this example.
49 | P a g e
SQL script to create tblEmployees table
Create table tblEmployees
(
Id int identity primary key,
Name nvarchar(100),
Gender nvarchar(10),
Salary int
)
Go
Result :
50 | P a g e
Order By clause should be used only once after the right query
Select Id, Name, Gender, Salary
From tblEmployees
Where Salary >= 50000
Except
Select Id, Name, Gender, Salary
From tblEmployees
Where Salary >= 60000
order By Name
In this video we will discuss the difference between EXCEPT and NOT IN operators in SQL
Server.
The following query returns the rows from the left query that aren’t in the right query’s results.
Result :
51 | P a g e
The same result can also be achieved using NOT IN operator.
Select Id, Name, Gender From TableA
Where Id NOT IN (Select Id from TableB)
Now execute the following EXCEPT query. Notice that we get only the DISTINCT rows
Select Id, Name, Gender From TableA
Except
Select Id, Name, Gender From TableB
Result:
Now execute the following query. Notice that the duplicate rows are not filtered.
Select Id, Name, Gender From TableA
Where Id NOT IN (Select Id from TableB)
Result:
2. EXCEPT operator expects the same number of columns in both the queries, where as NOT
IN, compares a single column from the outer query with a single column from the subquery.
52 | P a g e
Select Id, Name From TableB
NOT IN, compares a single column from the outer query with a single column from subquery.
Intersect operator retrieves the common records from both the left and the right query of
the Intersect operator.
SQL Script to create the tables and populate with test data
Create Table TableA
53 | P a g e
(
Id int,
Name nvarchar(50),
Gender nvarchar(10)
)
Go
The following query retrieves the common records from both the left and the right query of the
Intersect operator.
Result :
We can also achieve the same thinkg using INNER join. The following INNER join query would
produce the exact same result.
54 | P a g e
From TableA Inner Join TableB
On TableA.Id = TableB.Id
Now execute the following INTERSECT query. Notice that we get only the DISTINCT rows
Result :
Now execute the following INNER JOIN query. Notice that the duplicate rows are not filtered.
Result :
You can make the INNER JOIN behave like INTERSECT operator by using the DISTINCT
operator
55 | P a g e
Result :
2. INNER JOIN treats two NULLS as two different values. So if you are joining two tables
based on a nullable column and if both tables have NULLs in that joining column then, INNER
JOIN will not include those rows in the result-set, where as INTERSECT treats two NULLs as a
same value and it returns all matching rows.
INTERSECT query
Select Id, Name, Gender from TableA
Intersect
Select Id, Name, Gender from TableB
Result :
Result :
56 | P a g e
Part 90 - Difference between union intersect and except in sql server
In this video we will discuss the difference between union intersect and except in sql server
with examples.
UNION operator returns all the unique rows from both the left and the right query. UNION ALL
included the duplicates as well.
INTERSECT operator retrieves the common unique rows from both the left and the right query.
EXCEPT operator returns unique rows from the left query that aren’t in the right query’s
results.
57 | P a g e
Let us understand these differences with examples. We will use the following 2 tables for the
examples.
UNION operator returns all the unique rows from both the queries. Notice the duplicates are
removed.
58 | P a g e
Select Id, Name, Gender from TableA
UNION
Select Id, Name, Gender from TableB
Result :
UNION ALL operator returns all the rows from both the queries, including the duplicates.
Result :
INTERSECT operator retrieves the common unique rows from both the left and the right query.
Notice the duplicates are removed.
Result :
59 | P a g e
EXCEPT operator returns unique rows from the left query that aren’t in the right query’s results.
Result :
If you wnat the rows that are present in Table B but not in Table A, reverse the queries.
Result :
For all these 3 operators to work the following 2 conditions must be met
The number and the order of the columns must be same in both the queries
The data types must be same or at least compatible
For example, if the number of columns are different, you will get the following error
Msg 205, Level 16, State 1, Line 1
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal
number of expressions in their target lists.
60 | P a g e
In this video we will discuss cross apply and outer apply in sql server with examples.
SQL Script to create the tables and populate with test data
Create table Department
(
Id int primary key,
DepartmentName nvarchar(50)
)
Go
61 | P a g e
Insert into Employee values (3, 'Steve', 'Male', 45000, 2)
Insert into Employee values (4, 'John', 'Male', 56000, 1)
Insert into Employee values (5, 'Sara', 'Female', 39000, 2)
Go
We want to retrieve all the matching rows between Department and Employee tables.
This can be very easily achieved using an Inner Join as shown below.
Select D.DepartmentName, E.Name, E.Gender, E.Salary
from Department D
Inner Join Employee E
On D.Id = E.DepartmentId
Now if we want to retrieve all the matching rows between Department and Employeetables +
the non-matching rows from the LEFT table (Department)
This can be very easily achieved using a Left Join as shown below.
Select D.DepartmentName, E.Name, E.Gender, E.Salary
from Department D
Left Join Employee E
On D.Id = E.DepartmentId
Now let's assume we do not have access to the Employee table. Instead we have access to the
following Table Valued function, that returns all employees belonging to a department by
62 | P a g e
Department Id.
The following query returns the employees of the department with Id =1.
Select * from fn_GetEmployeesByDepartmentId(1)
Now if you try to perform an Inner or Left join between Department table
andfn_GetEmployeesByDepartmentId() function you will get an error.
If you execute the above query you will get the following error
Msg 4104, Level 16, State 1, Line 3
The multi-part identifier "D.Id" could not be bound.
This is where we use Cross Apply and Outer Apply operators. Cross Apply is semantically
equivalent to Inner Join and Outer Apply is semantically equivalent to Left Outer Join.
Just like Inner Join, Cross Apply retrieves only the matching rows from the Department table
and fn_GetEmployeesByDepartmentId() table valued function.
Just like Left Outer Join, Outer Apply retrieves all matching rows from the Department table and
fn_GetEmployeesByDepartmentId() table valued function + non-matching rows from the left
table (Department)
63 | P a g e
How does Cross Apply and Outer Apply work
The APPLY operator introduced in SQL Server 2005, is used to join a table to a table-
valued function.
The Table Valued Function on the right hand side of the APPLY operator gets called for
each row from the left (also called outer table) table.
Cross Apply returns only matching rows (semantically equivalent to Inner Join)
Outer Apply returns matching + non-matching rows (semantically equivalent to Left
Outer Join). The unmatched columns of the table valued function will be set to NULL.
Certain system stored procedures that perform DDL-like operations can also fire DDL
triggers. Example - sp_rename system stored procedure
64 | P a g e
BEGIN
-- Trigger Body
END
DDL triggers scope : DDL triggers can be created in a specific database or at the server
level.
Please note : If you can't find the trigger that you just created, make sure to refresh the
Database Triggers folder.
When you execute the following code to create the table, the trigger will automatically fire and
will print the message - New table created
Create Table Test (Id int)
65 | P a g e
The above trigger will be fired only for one DDL event CREATE_TABLE. If you want this trigger
to be fired for multiple events, for example when you alter or drop a table, then separate the
events using a comma as shown below.
Now if you create, alter or drop a table, the trigger will fire automatically and you will get the
message - A table has just been created, modified or deleted.
The 2 DDL triggers above execute some code in response to DDL events
Now let us look at an example of how to prevent users from creating, altering or dropping tables.
To do this modify the trigger as shown below.
To be able to create, alter or drop a table, you either have to disable or delete the trigger.
To disable trigger
1. Right click on the trigger in object explorer and select "Disable" from the context menu
2. You can also disable the trigger using the following T-SQL command
DISABLE TRIGGER trMyFirstTrigger ON DATABASE
To enable trigger
1. Right click on the trigger in object explorer and select "Enable" from the context menu
2. You can also enable the trigger using the following T-SQL command
ENABLE TRIGGER trMyFirstTrigger ON DATABASE
To drop trigger
1. Right click on the trigger in object explorer and select "Delete" from the context menu
2. You can also drop the trigger using the following T-SQL command
DROP TRIGGER trMyFirstTrigger ON DATABASE
66 | P a g e
Certain system stored procedures that perform DDL-like operations can also fire DDL triggers.
The following trigger will be fired when ever you rename a database object
usingsp_rename system stored procedure.
The following code changes the name of the TestTable to NewTestTable. When this code is
executed, it will fire the trigger trRenameTable
sp_rename 'TestTable', 'NewTestTable'
The following code changes the name of the Id column in NewTestTable to NewId. When this
code is executed, it will fire the trigger trRenameTable
sp_rename 'NewTestTable.Id' , 'NewId', 'column'
The following trigger is a database scoped trigger. This will prevent users from creating, altering
or dropping tables only from the database in which it is created.
If you have another database on the server, they will be able to create, alter or drop tables in
that database. If you want to prevent users from doing this you may create the trigger again in
this database.
But, what if you have 100 different databases on your SQL Server, and you want to prevent
users from creating, altering or dropping tables from all these 100 databases. Creating the same
trigger for all the 100 different databases is not a good approach for 2 reasons.
67 | P a g e
1. It is tedious and error prone
2. Maintainability is a night mare. If for some reason you have to change the trigger, you will
have to do it in 100 different databases, which again is tedious and error prone.
This is where server-scoped DDL triggers come in handy. When you create a server scoped
DDL trigger, it will fire in response to the DDL events happening in all of the databases on that
server.
Creating a Server-scoped DDL trigger : Similar to creating a database scoped trigger, except
that you will have to change the scope to ALL Server as shown below.
Now if you try to create, alter or drop a table in any of the databases on the server, the trigger
will be fired.
68 | P a g e
To enable Server-scoped ddl trigger
1. Right click on the trigger in object explorer and select "Enable" from the context menu
2. You can also enable the trigger using the following T-SQL command
ENABLE TRIGGER tr_ServerScopeTrigger ON ALL SERVER
Server scoped triggers will always fire before any of the database scoped triggers. This
execution order cannot be changed.
In the example below, we have a database-scoped and a server-scoped trigger handling the
same event (CREATE_TABLE). When you create a table, notice that server-scoped trigger is
always fired before the database-scoped trigger.
Using the sp_settriggerorder stored procedure, you can set the execution order of server-
69 | P a g e
scoped or database-scoped triggers.
EXEC sp_settriggerorder
@triggername = 'tr_DatabaseScopeTrigger1',
@order = 'none',
@stmttype = 'CREATE_TABLE',
@namespace = 'DATABASE'
GO
If you have a database-scoped and a server-scoped trigger handling the same event, and
if you have set the execution order at both the levels. Here is the execution order of the triggers.
1. The server-scope trigger marked First
2. Other server-scope triggers
3. The server-scope trigger marked Last
4. The database-scope trigger marked First
5. Other database-scope triggers
6. The database-scope trigger marked Last
In this video we will discuss, how to audit table changes in SQL Server using a DDL
trigger.
70 | P a g e
AuditDateTime datetime
)
Go
The following trigger audits all table changes in all databases on a SQL Server
CREATE TRIGGER tr_AuditTableChanges
ON ALL SERVER
FOR CREATE_TABLE, ALTER_TABLE, DROP_TABLE
AS
BEGIN
DECLARE @EventData XML
SELECT @EventData = EVENTDATA()
In the above example we are using EventData() function which returns event data in XML
format. The following XML is returned by the EventData() function when I created a table with
name = MyTable in SampleDB database.
<EVENT_INSTANCE>
<EventType>CREATE_TABLE</EventType>
<PostTime>2015-09-11T16:12:49.417</PostTime>
<SPID>58</SPID>
<ServerName>VENKAT-PC</ServerName>
<LoginName>VENKAT-PC\Tan</LoginName>
<UserName>dbo</UserName>
<DatabaseName>SampleDB</DatabaseName>
<SchemaName>dbo</SchemaName>
<ObjectName>MyTable</ObjectName>
<ObjectType>TABLE</ObjectType>
71 | P a g e
<TSQLCommand>
<SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON"
ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON"
ENCRYPTED="FALSE" />
<CommandText>
Create Table MyTable
(
Id int,
Name nvarchar(50),
Gender nvarchar(50)
)
</CommandText>
</TSQLCommand>
</EVENT_INSTANCE>
As the name implies Logon triggers fire in response to a LOGON event. Logon triggers fire
after the authentication phase of logging in finishes, but before the user session is actually
established.
Logon trigger example : The following trigger limits the maximum number of open connections
for a user to 3.
72 | P a g e
WHERE is_user_process = 1
AND original_login_name = @LoginName) > 3
BEGIN
Print 'Fourth connection of ' + @LoginName + ' blocked'
ROLLBACK
END
END
The trigger error message will be written to the error log. Execute the following command to
read the error log.
Execute sp_readerrorlog
In this video we will discuss the power and use of SELECT INTO statement in SQL Server.
73 | P a g e
SQL Script to create Departments and Employees tables
Create table Departments
(
DepartmentId int primary key,
DepartmentName nvarchar(50)
)
Go
The SELECT INTO statement in SQL Server, selects data from one table and inserts it into a
new table.
74 | P a g e
SELECT INTO statement in SQL Server can do the following
1. Copy all rows and columns from an existing table into a new table. This is extremely useful
when you want to make a backup copy of the existing table.
SELECT * INTO EmployeesBackup FROM Employees
2. Copy all rows and columns from an existing table into a new table in an external database.
SELECT * INTO HRDB.dbo.EmployeesBackup FROM Employees
6. Create a new table whose columns and datatypes match with an existing table.
SELECT * INTO EmployeesBackup FROM Employees WHERE 1 <> 1
7. Copy all rows and columns from an existing table into a new table on a different SQL Server
instance. For this, create a linked server and use the 4 part naming convention
SELECT * INTO TargetTable
FROM [SourceServer].[SourceDB].[dbo].[SourceTable]
Please note : You cannot use SELECT INTO statement to select data into an existing table.
For this you will have to use INSERT INTO statement.
In this video we will discuss the difference between where and having clauses in SQL
Server.
Let us understand the difference with an example. For the examples in this video we will use the
following Sales table.
75 | P a g e
SQL Script to create and populate Sales table with test data
Create table Sales
(
Product nvarchar(50),
SaleAmount int
)
Go
To calculate total sales by product, we would write a GROUP BY query as shown below
SELECT Product, SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY Product
Now if we want to find only those products where the total sales amount is greater than
$1000, we will use HAVING clause to filter products
SELECT Product, SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY Product
76 | P a g e
HAVING SUM(SaleAmount) > 1000
Result :
If we use WHERE clause instead of HAVING clause, we will get a syntax error. This is because
the WHERE clause doesn’t work with aggregate functions like sum, min, max, avg, etc.
SELECT Product, SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY Product
WHERE SUM(SaleAmount) > 1000
So in short, the difference is WHERE clause cannot be used with aggregates where as
HAVING can.
However, there are other differences as well that we need to keep in mind when using WHERE
and HAVING clauses. WHERE clause filters rows before aggregate calculations are performed
where as HAVING clause filters rows after aggregate calculations are performed. Let us
understand this with an example.
Total sales of iPhone and Speakers can be calculated by using either WHERE or HAVING
clause
Calculate Total sales of iPhone and Speakers using WHERE clause : In this example the
WHERE clause retrieves only iPhone and Speaker products and then performs the sum.
SELECT Product, SUM(SaleAmount) AS TotalSales
FROM Sales
WHERE Product in ('iPhone', 'Speakers')
GROUP BY Product
Result :
Calculate Total sales of iPhone and Speakers using HAVING clause : This example
retrieves all rows from Sales table, performs the sum and then removes all products except
iPhone and Speakers.
SELECT Product, SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY Product
HAVING Product in ('iPhone', 'Speakers')
77 | P a g e
Result :
So from a performance standpoint, HAVING is slower than WHERE and should be avoided
when possible.
Another difference is WHERE comes before GROUP BY and HAVING comes after GROUP
BY.
2. WHERE comes before GROUP BY. This means WHERE clause filters rows before
aggregate calculations are performed. HAVING comes after GROUP BY. This means HAVING
clause filters rows after aggregate calculations are performed. So from a performance
standpoint, HAVING is slower than WHERE and should be avoided when possible.
3. WHERE and HAVING can be used together in a SELECT query. In this case WHERE clause
is applied first to filter individual rows. The rows are then grouped and aggregate calculations
are performed, and then the HAVING clause filters the groups.
Table Valued Parameter is a new feature introduced in SQL SERVER 2008. Table Valued
Parameter allows a table (i.e multiple rows of data) to be passed as a parameter to a stored
procedure from T-SQL code or from an application. Prior to SQL SERVER 2008, it is not
possible to pass a table variable as a parameter to a stored procedure.
Let us understand how to pass multiple rows to a stored procedure using Table Valued
Parameter with an example. We want to insert multiple rows into the following Employees table.
At the moment this table does not have any rows.
78 | P a g e
Create Table Employees
(
Id int primary key,
Name nvarchar(50),
Gender nvarchar(10)
)
Go
Step 2 : Use the User-defined Table Type as a parameter in the stored procedure. Table valued
parameters must be passed as read-only to stored procedures, functions etc. This means you
cannot perform DML operations like INSERT, UPDATE or DELETE on a table-valued parameter
in the body of a function, stored procedure etc.
Step 3 : Declare a table variable, insert the data and then pass the table variable as a
parameter to the stored procedure.
79 | P a g e
That's it. Now select the data from Employees table and notice that all the rows of the table
variable are inserted into the Employees table.
In our next video, we will discuss how to pass table as a parameter to the stored procedure
from an ADO.NET application
In this video we will discuss how to send datatable as parameter to stored procedure. This
is continuation to Part 99. Please watch Part 99 from SQL Server tutorial before proceeding.
In Part 99, we discussed creating a stored procedure that accepts a table as a parameter. In
this video we will discuss how to pass a datatable from a web application to the SQL Server
stored procedure.
2. When "Insert Employees" button is clicked, retrieve the from data into a datatabe and then
pass the datatable as a parameter to the stored procedure.
3. The stored procedure will then insert all the rows into the Employees table in the database.
80 | P a g e
Step 1 : Create new asp.net web application project. Name it Demo.
81 | P a g e
</td>
</tr>
<tr>
<td>
ID : <asp:TextBox ID="txtId4" runat="server"></asp:TextBox>
</td>
<td>
Name : <asp:TextBox ID="txtName4" runat="server"></asp:TextBox>
</td>
<td>
Gender : <asp:TextBox ID="txtGender4" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td>
ID : <asp:TextBox ID="txtId5" runat="server"></asp:TextBox>
</td>
<td>
Name : <asp:TextBox ID="txtName5" runat="server"></asp:TextBox>
</td>
<td>
Gender : <asp:TextBox ID="txtGender5" runat="server"></asp:TextBox>
</td>
</tr>
</table>
<br />
<asp:Button ID="btnInsert" runat="server" Text="Insert Employees"
OnClick="btnInsert_Click" />
Step 4 : Copy and paste the following code in the code-behind file
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace Demo
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{}
82 | P a g e
private DataTable GetEmployeeData()
{
DataTable dt = new DataTable();
dt.Columns.Add("Id");
dt.Columns.Add("Name");
dt.Columns.Add("Gender");
return dt;
}
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
83 | P a g e
txtId2.Text = "2";
txtId3.Text = "3";
txtId4.Text = "4";
txtId5.Text = "5";
txtName1.Text = "John";
txtName2.Text = "Mike";
txtName3.Text = "Sara";
txtName4.Text = "Pam";
txtName5.Text = "Todd";
txtGender1.Text = "Male";
txtGender2.Text = "Male";
txtGender3.Text = "Female";
txtGender4.Text = "Female";
txtGender5.Text = "Male";
}
}
}
We will be using the following Employees table for the examples in this video.
84 | P a g e
SQL Script to create and populate Employees table
Create Table Employees
(
Id int primary key,
Name nvarchar(50),
Gender nvarchar(10),
Salary int,
Country nvarchar(10)
)
Go
We want to calculate Sum of Salary by Country and Gender. The result should be as shown
below.
85 | P a g e
We can very easily achieve this using a Group By query as shown below
Select Country, Gender, Sum(Salary) as TotalSalary
From Employees
Group By Country, Gender
Within the same result set we also want Sum of Salary just by Country. The Result should be as
shown below. Notice that Gender column within the resultset is NULL as we are grouping only
by Country column
To achieve the above result we could combine 2 Group By queries using UNION ALL as shown
below.
UNION ALL
86 | P a g e
Group By Country
Within the same result set we also want Sum of Salary just by Gender. The Result should be as
shown below. Notice that the Country column within the resultset is NULL as we are grouping
only by Gender column.
We can achieve this by combining 3 Group By queries using UNION ALL as shown below
UNION ALL
UNION ALL
Finally we also want the grand total of Salary. In this case we are not grouping on any particular
column. So both Country and Gender columns will be NULL in the resultset.
87 | P a g e
To achieve this we will have to combine the fourth query using UNION ALL as shown below.
UNION ALL
UNION ALL
UNION ALL
88 | P a g e
operator. This can grow even more if we start to add more groups
2. The Employees table has to be accessed 4 times, once for every query.
If we use Grouping Sets feature introduced in SQL Server 2008, the amount of T-SQL code
that you have to write will be greatly reduced. The following Grouping Sets query produce the
same result as the above UNION ALL query.
The order of the rows in the result set is not the same as in the case of UNION ALL query. To
control the order use order by as shown below.
89 | P a g e
(
(Country, Gender), -- Sum of Salary by Country and Gender
(Country), -- Sum of Salary by Country
(Gender) , -- Sum of Salary by Gender
() -- Grand Total
)
Order By Grouping(Country), Grouping(Gender), Gender
Let us understand Rollup in SQL Server with examples. We will use the followingEmployees
table for the examples in this video.
90 | P a g e
Retrieve Salary by country along with grand total
There are several ways to achieve this. The easiest way is by using Rollup with Group By.
SELECT Country, SUM(Salary) AS TotalSalary
FROM Employees
GROUP BY ROLLUP(Country)
UNION ALL
91 | P a g e
SELECT NULL, SUM(Salary) AS TotalSalary
FROM Employees
Group Salary by Country and Gender. Also compute the Subtotal for Country level and Grand
Total as shown below.
--OR
92 | P a g e
SELECT Country, Gender, SUM(Salary) AS TotalSalary
FROM Employees
GROUP BY Country, Gender
UNION ALL
UNION ALL
Cube() in SQL Server produces the result set by generating all combinations of columns
specified in GROUP BY CUBE().
Let us understand Cube() in SQL Server with examples. We will use the followingEmployees
table for the examples in this video.
93 | P a g e
Write a query to retrieve Sum of Salary grouped by all combinations of the following 2 columns
as well as Grand Total.
Country,
Gender
94 | P a g e
GROUP BY Cube(Country, Gender)
--OR
The above query is equivalent to the following UNION ALL query. While the data in the
result set is the same, the ordering is not. Use ORDER BY to control the ordering of rows in the
result set.
UNION ALL
UNION ALL
UNION ALL
95 | P a g e
SELECT NULL, NULL, SUM(Salary) AS TotalSalary
FROM Employees
In this video we will discuss the difference between cube and rollup in SQL Server.
CUBE generates a result set that shows aggregates for all combinations of values in the
selected columns, where as ROLLUP generates a result set that shows aggregates for a
hierarchy of values in the selected columns.
Let us understand this difference with an example. Consider the following Sales table.
96 | P a g e
Insert into Sales values('Europe','United Kingdom','Manchester',2000)
Insert into Sales values('Europe','France','Paris',4000)
Insert into Sales values('Europe','France','Cannes',5000)
Go
ROLLUP(Continent, Country, City) produces Sum of Salary for the following hierarchy
Continent, Country, City
Continent, Country,
Continent
()
CUBE(Continent, Country, City) produces Sum of Salary for all the following column
combinations
Continent, Country, City
Continent, Country,
Continent, City
Continent
Country, City
Country,
City
()
97 | P a g e
SELECT Continent, Country, City, SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY CUBE(Continent, Country, City)
98 | P a g e
99 | P a g e
100 | P a g e
You won't see any difference when you use ROLLUP and CUBE on a single column. Both the
following queries produces the same output.
-- OR
In this video we will discuss the use of Grouping function in SQL Server.
This is continuation to Part 104. Please watch Part 104 from SQL Server tutorial before
proceeding. We will use the following Sales table for this example.
101 | P a g e
Grouping(Column) indicates whether the column in a GROUP BY list is aggregated or not.
Grouping returns 1 for aggregated or 0 for not aggregated in the result set.
The following query returns 1 for aggregated or 0 for not aggregated in the result set
Result :
SELECT
CASE WHEN
GROUPING(Continent) = 1 THEN 'All' ELSE ISNULL(Continent, 'Unknown')
END AS Continent,
CASE WHEN
GROUPING(Country) = 1 THEN 'All' ELSE ISNULL(Country, 'Unknown')
END AS Country,
CASE
WHEN GROUPING(City) = 1 THEN 'All' ELSE ISNULL(City, 'Unknown')
102 | P a g e
END AS City,
SUM(SaleAmount) AS TotalSales
FROM Sales
GROUP BY ROLLUP(Continent, Country, City)
Result :
Well, you can, but only if your data does not contain NULL values. Let me explain what I mean.
At the moment the raw data in our Sales has no NULL values. Let's introduce a NULL value in
the City column of the row where Id = 1
103 | P a g e
Now execute the following query with ISNULL function
Result : Notice that the actuall NULL value in the raw data is also replaced with the word 'All',
which is incorrect. Hence the need for Grouping function.
Please note : Grouping function can be used with Rollup, Cube and Grouping Sets
104 | P a g e
3. Use of GROUPING_ID function
Syntax : GROUPING function is used on single column, where as the column list for
GROUPING_ID function must match with GROUP BY column list.
GROUPING(Col1)
GROUPING_ID(Col1, Col2, Col3,...)
GROUPING indicates whether the column in a GROUP BY list is aggregated or not. Grouping
returns 1 for aggregated or 0 for not aggregated in the result set.
GROUPING_ID() function concatenates all the GOUPING() functions, perform the binary to
decimal conversion, and returns the equivalent integer. In short
GROUPING_ID(A, B, C) = GROUPING(A) + GROUPING(B) + GROUPING(C)
Query result :
105 | P a g e
Row Number 1 : Since the data is not aggregated by any column GROUPING(Continent),
GROUPING(Country) and GROUPING(City) return 0 and as result we get a binar string with all
ZEROS (000). When this converted to decimal we get 0 which is displayed in GPID column.
Row Number 7 : The data is aggregated for Country and City columns, so
GROUPING(Country) and GROUPING(City) return 1 where as GROUPING(Continent) return
0. As result we get a binar string (011). When this converted to decimal we get 10 which is
displayed in GPID column.
Row Number 15 : This is the Grand total row. Notice in this row the data is aggregated by all
the 3 columns. Hence all the 3 GROUPING functions return 1. So we get a binary string with all
ONES (111). When this converted to decimal we get 7 which is displayed in GPID column.
Use of GROUPING_ID function : GROUPING_ID function is very handy if you want to sort and
filter by level of grouping.
106 | P a g e
Result :
Filter by level of grouping : The following query retrieves only continent level aggregated data
SELECT Continent, Country, City, SUM(SaleAmount) AS TotalSales,
GROUPING_ID(Continent, Country, City) AS GPID
FROM Sales
GROUP BY ROLLUP(Continent, Country, City)
HAVING GROUPING_ID(Continent, Country, City) = 3
Result :
In this video we will discuss how to debug stored procedures in SQL Server.
107 | P a g e
Setting up the Debugger in SSMS : If you have connected to SQL Server using (local) or .
(period), and when you start the debugger you will get the following error
Unable to start T-SQL Debugging. Could not connect to computer.
To fix this error, use the computer name to connect to the SQL Server instead of using (local) or
.
For the examples in this video we will be using the following stored procedure.
Create procedure spPrintEvenNumbers
@Target int
as
Begin
Declare @StartNumber int
Set @StartNumber = 1
108 | P a g e
Begin
If(@StartNumber%2 = 0)
Begin
Print @StartNumber
End
Set @StartNumber = @StartNumber + 1
End
Print 'Finished printing even numbers till ' + RTRIM(@Target)
End
Connect to SQL Server using your computer name, and then execute the above code to create
the stored procedure. At this point, open a New Query window. Copy and paste the following T-
SQL code to execute the stored procedure.
Starting the Debugger in SSMS : There are 2 ways to start the debugger
1. In SSMS, click on the Debug Menu and select Start Debugging
At this point you should have the debugger running. The line that is about to be executed is
marked with an yellow arrow
109 | P a g e
Step Over, Step into and Step Out in SSMS : You can find the keyboard shortcuts in the Debug
menu in SSMS.
Let us understand what Step Over, Step into and Step Out does when debugging the following
piece of code
1. There is no difference when you STEP INTO (F11) or STEP OVER (F10) the code on LINE 2
2. On LINE 3, we are calling a Stored Procedure. On this statement if we press F10 (STEP
OVER), it won't give us the opportunity to debug the stored procedure code. To be able to
debug the stored procedure code you will have to STEP INTO it by pressing F11.
3. If the debugger is in the stored procedure, and you don't want to debug line by line with in
that stored procedure, you can STEP OUT of it by pressing SHIFT + F11. When you do this, the
debugger completes the execution of the stored procedure and waits on the next line in the
main query, i.e on LINE 4 in this example.
110 | P a g e
To stop debugging : There are 2 ways to stop debugging
1. In SSMS, click on the Debug Menu and select Stop Debugging
2. Use the keyboard shortcut SHIFT + F5
Show Next Statement shows the next statement that the debugger is about to execute.
Run to Cursor command executes all the statements in a batch up to the current cursor position
Locals Window in SSMS : Displays the current values of variables and parameters
If you cannot see the locals window or if you have closed it and if you want to open it, you can
do so using the following menu option. Locals window is only available if you are in DEBUG
mode.
111 | P a g e
Watch Window in SSMS : Just like Locals window, Watch window is used to watch the values
of variables. You can add and remove variables from the watch window. To add a variable to
the Watch Window, right click on the variable and select "Add Watch" option from the context
menu.
Call Stack Window in SSMS : Allows you to navigate up and down the call stack to see what
values your application is storing at different levels. It's an invaluable tool for determining why
your code is doing what it's doing.
Immediate Window in SSMS : Very helpful during debugging to evaluate expressions, and
print variable values. To clear immediate window type >cls and press enter.
Enable, Disable or Delete all breakpoints : There are 2 ways to Enable, Disable or Delete all
breakpoints
112 | P a g e
1. From the Debug menu
2. From the Breakpoints window. To view Breakpoints window select Debug => Windows =>
Breakpoints or use the keyboard shortcut ALT + CTRL + B
Conditional Breakpoint : Conditional Breakpoints are hit only when the specified condition is
met. These are extremely useful when you have some kind of a loop and you want to break,
only when the loop variable has a specific value (For example loop varible = 100).
113 | P a g e
2. In the Breakpoint window specify the condition
In this video we will discuss the power and use of Over clause in SQL Server.
The OVER clause combined with PARTITION BY is used to break up data into partitions.
Syntax : function (...) OVER (PARTITION BY col1, Col2, ...)
For example :
COUNT(Gender) OVER (PARTITION BY Gender) will partition the data by GENDER i.e there
will 2 partitions (Male and Female) and then the COUNT() function is applied over each
partition.
Any of the following functions can be used. Please note this is not the complete list.
COUNT(), AVG(), SUM(), MIN(), MAX(), ROW_NUMBER(), RANK(), DENSE_RANK() etc.
114 | P a g e
Example : We will use the following Employees table for the examples in this video.
Write a query to retrieve total count of employees by Gender. Also in the result we want
Average, Minimum and Maximum salary by Gender. The result of the query should be as shown
below.
115 | P a g e
This can be very easily achieved using a simple GROUP BY query as show below.
SELECT Gender, COUNT(*) AS GenderTotal, AVG(Salary) AS AvgSal,
MIN(Salary) AS MinSal, MAX(Salary) AS MaxSal
FROM Employees
GROUP BY Gender
What if we want non-aggregated values (like employee Name and Salary) in result set along
with aggregated values
One way to achieve this is by including the aggregations in a subquery and then JOININGit with
the main query as shown in the example below. Look at the amount of T-SQL code we have to
write.
SELECT Name, Salary, Employees.Gender, Genders.GenderTotals,
Genders.AvgSal, Genders.MinSal, Genders.MaxSal
FROM Employees
116 | P a g e
INNER JOIN
(SELECT Gender, COUNT(*) AS GenderTotals,
AVG(Salary) AS AvgSal,
MIN(Salary) AS MinSal, MAX(Salary) AS MaxSal
FROM Employees
GROUP BY Gender) AS Genders
ON Genders.Gender = Employees.Gender
Better way of doing this is by using the OVER clause combined with PARTITION BY
SELECT Name, Salary, Gender,
COUNT(Gender) OVER(PARTITION BY Gender) AS GenderTotals,
AVG(Salary) OVER(PARTITION BY Gender) AS AvgSal,
MIN(Salary) OVER(PARTITION BY Gender) AS MinSal,
MAX(Salary) OVER(PARTITION BY Gender) AS MaxSal
FROM Employees
In this video we will discuss Row_Number function in SQL Server. This is continuation toPart
108. Please watch Part 108 from SQL Server tutorial before proceeding.
Row_Number function
117 | P a g e
Please note : If ORDER BY clause is not specified you will get the following error
The function 'ROW_NUMBER' must have an OVER clause with ORDER BY
Use case for Row_Number function : Deleting all duplicate rows except one from a sql server
118 | P a g e
table.
Discussed in detail in Part 4 of SQL Server Interview Questions and Answers video series.
In this video we will discuss Rank and Dense_Rank functions in SQL Server
For example : If you have 2 rows at rank 1 and you have 5 rows in total.
RANK() returns - 1, 1, 3, 4, 5
DENSE_RANK returns - 1, 1, 2, 3, 4
Syntax :
RANK() OVER (ORDER BY Col1, Col2, ...)
DENSE_RANK() OVER (ORDER BY Col1, Col2, ...)
Example : We will use the following Employees table for the examples in this video
119 | P a g e
SQl Script to create Employees table
Create Table Employees
(
Id int primary key,
Name nvarchar(50),
Gender nvarchar(10),
Salary int
)
Go
DENSE_RANK() on the other hand will not skip ranks if there is a tie. The first 2 rows get rank
120 | P a g e
1. Third row gets rank 2.
RANK() and DENSE_RANK() functions with PARTITION BY clause : Notice when the
partition changes from Female to Male Rank is reset to 1
121 | P a g e
Use case for RANK and DENSE_RANK functions : Both these functions can be used to find
Nth highest salary. However, which function to use depends on what you want to do when there
is a tie. Let me explain with an example.
If there are 2 employees with the FIRST highest salary, there are 2 different business
cases
If your business case is, not to produce any result for the SECOND highest salary, then
use RANK function
If your business case is to return the next Salary after the tied rows as the SECOND
highest Salary, then use DENSE_RANK function
Since we have 2 Employees with the FIRST highest salary. Rank() function will not return any
rows for the SECOND highest Salary.
WITH Result AS
(
SELECT Salary, RANK() OVER (ORDER BY Salary DESC) AS Salary_Rank
FROM Employees
)
SELECT TOP 1 Salary FROM Result WHERE Salary_Rank = 2
Though we have 2 Employees with the FIRST highest salary. Dense_Rank() function returns,
the next Salary after the tied rows as the SECOND highest Salary
WITH Result AS
(
SELECT Salary, DENSE_RANK() OVER (ORDER BY Salary DESC) ASSalary_Rank
122 | P a g e
FROM Employees
)
SELECT TOP 1 Salary FROM Result WHERE Salary_Rank = 2
You can also use RANK and DENSE_RANK functions to find the Nth highest Salary among
Male or Female employee groups. The following query finds the 3rd highest salary amount paid
among the Female employees group
WITH Result AS
(
SELECT Salary, Gender,
DENSE_RANK() OVER (PARTITION BY Gender ORDER BY Salary DESC)
AS Salary_Rank
FROM Employees
)
SELECT TOP 1 Salary FROM Result WHERE Salary_Rank = 3
AND Gender = 'Female'
In this video we will discuss the similarities and difference between RANK, DENSE_RANK
and ROW_NUMBER functions in SQL Server.
Returns an increasing integer value starting at 1 based on the ordering of rows imposed
by the ORDER BY clause (if there are no ties)
ORDER BY clause is required
PARTITION BY clause is optional
When the data is partitioned, the integer value is reset to 1 when the partition changes
We will use the following Employees table for the examples in this video
123 | P a g e
SQL Script to create the Employees table
Create Table Employees
(
Id int primary key,
Name nvarchar(50),
Gender nvarchar(10),
Salary int
)
Go
Notice that no two employees in the table have the same salary. So all the 3 functions RANK,
DENSE_RANK and ROW_NUMBER produce the same increasing integer value when ordered
by Salary column.
You will only see the difference when there ties (duplicate values in the column used in the
ORDER BY clause).
To do this
First delete existing data from the Employees table
DELETE FROM Employees
124 | P a g e
Insert new rows with duplicate valuse for Salary column
Insert Into Employees Values (1, 'Mark', 'Male', 8000)
Insert Into Employees Values (2, 'John', 'Male', 8000)
Insert Into Employees Values (3, 'Pam', 'Female', 8000)
Insert Into Employees Values (4, 'Sara', 'Female', 4000)
Insert Into Employees Values (5, 'Todd', 'Male', 3500)
Notice 3 employees have the same salary 8000. When you execute the following query you can
clearly see the difference between RANK, DENSE_RANK and ROW_NUMBER functions.
ROW_NUMBER : Returns an increasing unique number for each row starting at 1, even
if there are duplicates.
RANK : Returns an increasing unique number for each row starting at 1. When there are
duplicates, same rank is assigned to all the duplicate rows, but the next row after the duplicate
125 | P a g e
rows will have the rank it would have been assigned if there had been no duplicates. So RANK
function skips rankings if there are duplicates.
DENSE_RANK : Returns an increasing unique number for each row starting at 1. When
there are duplicates, same rank is assigned to all the duplicate rows but the DENSE_RANK
function will not skip any ranks. This means the next row after the duplicate rows will have the
next rank in the sequence.
In this video we will discuss how to calculate running total in SQL Server 2012 and later
versions.
We will use the following Employees table for the examples in this video.
126 | P a g e
Insert Into Employees Values (1, 'Mark', 'Male', 5000)
Insert Into Employees Values (2, 'John', 'Male', 4500)
Insert Into Employees Values (3, 'Pam', 'Female', 5500)
Insert Into Employees Values (4, 'Sara', 'Female', 4000)
Insert Into Employees Values (5, 'Todd', 'Male', 3500)
Insert Into Employees Values (6, 'Mary', 'Female', 5000)
Insert Into Employees Values (7, 'Ben', 'Male', 6500)
Insert Into Employees Values (8, 'Jodi', 'Female', 7000)
Insert Into Employees Values (9, 'Tom', 'Male', 5500)
Insert Into Employees Values (10, 'Ron', 'Male', 5000)
Go
127 | P a g e
What happens if I use order by on Salary column
If you have duplicate values in the Salary column, all the duplicate values will be added to the
running total at once. In the example below notice that we have 5000 repeated 3 times. So
15000 (i.e 5000 + 5000 + 5000) is added to the running total at once.
So when computing running total, it is better to use a column that has unique data in the
ORDER BY clause.
128 | P a g e
Part 113 - NTILE function in SQL Server
NTILE function
We will use the following Employees table for the examples in this video.
129 | P a g e
Name nvarchar(50),
Gender nvarchar(10),
Salary int
)
Go
NTILE function without PARTITION BY clause : Divides the 10 rows into 3 groups. 4 rows in
first group, 3 rows in the 2nd & 3rd group.
What if the specified number of groups is GREATER THAN the number of rows
130 | P a g e
NTILE function will try to create as many groups as possible with one row in each group.
With 10 rows in the table, NTILE(11) will create 10 groups with 1 row in each group.
NTILE function with PARTITION BY clause : When the data is partitioned, NTILE function
creates the specified number of groups with in each partition.
The following query partitions the data into 2 partitions (Male & Female). NTILE(3) creates 3
groups in each of the partitions.
131 | P a g e
Part 114 - Lead and Lag functions in SQL Server 2012
132 | P a g e
We will use the following Employees table for the examples in this video
Lead and Lag functions example WITHOUT partitions : This example Leads 2 rows and
Lags 1 row from the current row.
When you are on the first row, LEAD(Salary, 2, -1) allows you to move forward 2 rows
and retrieve the salary from the 3rd row.
133 | P a g e
When you are on the first row, LAG(Salary, 1, -1) allows us to move backward 1 row.
Since there no rows beyond row 1, Lag function in this case returns the default value -1.
When you are on the last row, LEAD(Salary, 2, -1) allows you to move forward 2 rows.
Since there no rows beyond the last row 1, Lead function in this case returns the default value -
1.
When you are on the last row, LAG(Salary, 1, -1) allows us to move backward 1 row and
retrieve the salary from the previous row.
SELECT Name, Gender, Salary,
LEAD(Salary, 2, -1) OVER (ORDER BY Salary) AS Lead_2,
LAG(Salary, 1, -1) OVER (ORDER BY Salary) AS Lag_1
FROM Employees
Lead and Lag functions example WITH partitions : Notice that in this example, Lead and Lag
functions return default value if the number of rows to lead or lag goes beyond first row or last
row in the partition.
134 | P a g e
FROM Employees
FIRST_VALUE function
135 | P a g e
FIRST_VALUE function example WITH partitions : In the following example, FIRST_VALUE
function returns the name of the lowest paid employee from the respective partition.
136 | P a g e
In this video we will discuss window functions in SQL Server
Compute average salary and display it against every employee row as shown below.
137 | P a g e
As you can see from the result below, the above query does not produce the overall salary
average. It produces the average of the current row and the rows preceeding the current row.
This is because, the default value of ROWS or RANGE clause (RANGE BETWEEN
UNBOUNDED PRECEDING AND CURRENT ROW) is applied.
To fix this, provide an explicit value for ROWS or RANGE clause as shown below. ROWS
BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING tells the window
function to operate on the set of rows starting from the first row in the partition to the last row in
the partition.
138 | P a g e
The same result can also be achieved by using RANGE BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING
The following query can be used if you want to compute the average salary of
1. The current row
2. One row PRECEDING the current row and
3. One row FOLLOWING the current row
139 | P a g e
Part 117 - Difference between rows and range
In this video we will discuss the difference between rows and range in SQL Server. This is
continuation to Part 116. Please watch Part 116 from SQL Server tutorial before proceeding.
Let us understand the difference with an example. We will use the following Employeestable in
this demo.
140 | P a g e
Go
Calculate the running total of Salary and display it against every employee row
The following query calculates the running total. We have not specified an explicit value for
ROWS or RANGE clause.
SELECT Name, Salary,
SUM(Salary) OVER(ORDER BY Salary) AS RunningTotal
FROM Employees
This means the above query can be re-written using an explicit value for ROWS or RANGE
clause as shown below.
SELECT Name, Salary,
SUM(Salary) OVER(ORDER BY Salary
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ASRunningTotal
FROM Employees
We can also achieve the same result, by replacing RANGE with ROWS
SELECT Name, Salary,
SUM(Salary) OVER(ORDER BY Salary
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ASRunningTotal
FROM Employees
141 | P a g e
Execute the following UPDATE script to introduce duplicate values in the Salary column
Update Employees set Salary = 1000 where Id = 2
Update Employees set Salary = 3000 where Id = 4
Go
Now execute the following query. Notice that we get the running total as expected.
SELECT Name, Salary,
SUM(Salary) OVER(ORDER BY Salary
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ASRunningTotal
FROM Employees
You get the following result when you execute the above query. Notice we don't get the running
total as expected.
So, the main difference between ROWS and RANGE is in the way duplicate rows are treated.
ROWS treat duplicates as distinct values, where as RANGE treats them as a single entity.
All together side by side. The following query shows how running total changes
1. When no value is specified for ROWS or RANGE clause
2. When RANGE clause is used explicitly with it's default value
142 | P a g e
3. When ROWS clause is used instead of RANGE clause
LAST_VALUE function
143 | P a g e
FROM Employees
This tells the LAST_VALUE function that it's window starts at the first row and ends at the last
row in the result set.
144 | P a g e
LAST_VALUE function example with partitions : In the following example, LAST_VALUE
function returns the name of the highest paid employee from the respective partition.
145 | P a g e
In this video we will discuss UNPIVOT operator in SQL Server.
PIVOT operator turns ROWS into COLUMNS, where as UNPIVOT turns COLUMNS into
ROWS.
We discussed PIVOT operator in Part 54 of SQL Server tutorial. Please watch Part 54before
proceeding.
Let us understand UNPIVOT with an example. We will use the following tblProductSales table in
this demo.
Write a query to turn COLUMNS into ROWS. The result of the query should be as shown
below.
146 | P a g e
SELECT SalesAgent, Country, SalesAmount
FROM tblProductSales
UNPIVOT
(
SalesAmount
FOR Country IN (India, US ,UK)
) AS UnpivotExample
In this video we will discuss if it's always possible to reverse what PIVOT operator has done
using UNPIVOT operator.
Is it always possible to reverse what PIVOT operator has done using UNPIVOT operator.
No, not always. If the PIVOT operator has not aggregated the data, you can get your original
data back using the UNPIVOT operator but not if the data is aggregated.
Let us understand this with an example. We will use the following table tblProductSalesfor the
examples in this video.
147 | P a g e
Insert into tblProductSales values('John','US',540)
Go
Let's now use the PIVOT operator to turn ROWS into COLUMNS
SELECT SalesAgent, India, US
FROM tblProductSales
PIVOT
(
SUM(SalesAmount)
FOR Country IN (India, US)
) AS PivotTable
Now let's use the UNPIVOT operator to reverse what PIVOT operator has done
SELECT SalesAgent, Country, SalesAmount
FROM
(SELECT SalesAgent, India, US
FROM tblProductSales
PIVOT
(
SUM(SalesAmount)
FOR Country IN (India, US)
) AS PivotTable) P
UNPIVOT
(
SalesAmount
FOR Country IN (India, US)
) AS UnpivotTable
The above query reverses what PIVOT operator has done, and we get the original data back as
shown below. We are able to get the original data back, because the SUM aggregate function
that we used with the PIVOT operator did not perform any aggregation.
148 | P a g e
Now execute the following INSERT statement to insert a new row into tblProductSalestable.
Insert into tblProductSales values('David','India',100)
With this new row in the table, if you execute the following PIVOT query data will be aggregated
SELECT SalesAgent, India, US
FROM tblProductSales
PIVOT
(
SUM(SalesAmount)
FOR Country IN (India, US)
) AS PivotTable
Now if we use UNPIVOT opertaor with the above query, we wouldn't get our orginial data back
as the PIVOT operator has already aggrgated the data, and there is no way for SQL Server to
know how to undo the aggregations.
149 | P a g e
UNPIVOT
(
SalesAmount
FOR Country IN (India, US)
) AS UnpivotTable
Notice that for SalesAgent - David and Country - India we get only one row. In the original table
we had 2 rows for the same combination.
Choose function
Output :
Example : Using CHOOSE() function with table data. We will use the followingEmployees table
for this example.
150 | P a g e
SQL Script to create Employees table
Create table Employees
(
Id int primary key identity,
Name nvarchar(10),
DateOfBirth date
)
Go
We want to display Month name along with employee Name and Date of Birth.
151 | P a g e
WHEN 1 THEN 'JAN'
WHEN 2 THEN 'FEB'
WHEN 3 THEN 'MAR'
WHEN 4 THEN 'APR'
WHEN 5 THEN 'MAY'
WHEN 6 THEN 'JUN'
WHEN 7 THEN 'JUL'
WHEN 8 THEN 'AUG'
WHEN 9 THEN 'SEP'
WHEN 10 THEN 'OCT'
WHEN 11 THEN 'NOV'
WHEN 12 THEN 'DEC'
END
AS [MONTH]
FROM Employees
Using CHOOSE function in SQL Server : The amount of code we have to write is lot less than
using CASE statement.
IIF function
152 | P a g e
SET @Gender = 1
SELECT IIF( @Gender = 1, 'Male', 'Femlae') AS Gender
Output :
Example : Using IIF() function with table data. We will use the following Employees table for
this example.
Write a query to display Gender along with employee Name and GenderId. We can achieve
this either by using CASE or IIF.
153 | P a g e
Using CASE statement
SELECT Name, GenderId,
CASE WHEN GenderId = 1
THEN 'Male'
ELSE 'Female'
END AS Gender
FROM Employees
TRY_PARSE function
Difference between PARSE and TRY_PARSE functions
TRY_PARSE function
Example : Convert string to INT. As the string can be converted to INT, the result will be 99 as
expected.
154 | P a g e
Output :
Example : Convert string to INT. The string cannot be converted to INT, so TRY_PARSE
returns NULL
Output :
Use CASE statement or IIF function to provide a meaningful error message instead of NULL
when the conversion fails.
Example : Using CASE statement to provide a meaningful error message when the conversion
fails.
SELECT
CASE WHEN TRY_PARSE('ABC' AS INT) IS NULL
THEN 'Conversion Failed'
ELSE 'Conversion Successful'
END AS Result
Output : As the conversion fails, you will now get a message 'Conversion Failed' instead of
NULL
Example : Using IIF function to provide a meaningful error message when the conversion fails.
Since ABC cannot be converted to INT, TRY_PARSE will return NULL instead of an error
155 | P a g e
SELECT TRY_PARSE('ABC' AS INT) AS Result
Example : Using TRY_PARSE() function with table data. We will use the following Employees
table for this example.
The data type of Age column is nvarchar. So string values like (THIRTY, FIFTY ) are also
stored. Now, we want to write a query to convert the values in Age column to int and return
along with the Employee name. Notice TRY_PARSE function returns NULL for the rows where
age cannot be converted to INT.
156 | P a g e
If you use PARSE instead of TRY_PARSE, the query fails with an error.
TRY_CONVERT function
Difference between CONVERT and TRY_CONVERT functions
Difference between TRY_PARSE and TRY_CONVERT functions
TRY_CONVERT function
Style parameter is optional. The range of acceptable values is determined by the target
data_type. For the list of all possible values for style parameter, please visit the following MSDN
article
https://msdn.microsoft.com/en-us/library/ms187928.aspx
157 | P a g e
Example : Convert string to INT. As the string can be converted to INT, the result will be 99 as
expected.
Output :
Example : Convert string to INT. The string cannot be converted to INT, so TRY_CONVERT
returns NULL
Output :
If you want to provide a meaningful error message instead of NULL when the conversion fails,
you can do so using CASE statement or IIF function.
Example : Using CASE statement to provide a meaningful error message when the conversion
fails.
SELECT
CASE WHEN TRY_CONVERT(INT, 'ABC') IS NULL
THEN 'Conversion Failed'
ELSE 'Conversion Successful'
END AS Result
Output : As the conversion fails, you will now get a message 'Conversion Failed' instead of
NULL
Example : Using IIF function to provide a meaningful error message when the conversion fails.
158 | P a g e
'Conversion Successful') AS Result
Since ABC cannot be converted to INT, TRY_CONVERT will return NULL instead of an error
SELECT TRY_CONVERT(INT, 'ABC') AS Result
Example : Using TRY_CONVERT() function with table data. We will use the following
Employees table for this example.
The data type of Age column is nvarchar. So string values like (THIRTY, FIFTY ) are also
stored. Now, we want to write a query to convert the values in Age column to int and return
along with the Employee name. Notice TRY_CONVERT function returns NULL for the rows
159 | P a g e
where age cannot be converted to INT.
If you use CONVERT instead of TRY_CONVERT, the query fails with an error.
For example, you can use TRY_CONVERT to convert a string to XML data type, where as you
can do the same using TRY_PARSE
160 | P a g e
Another difference is TRY_PARSE relies on the presence of .the .NET Framework Common
Language Runtime (CLR) where as TRY_CONVERT does not.
EOMONTH function
start_date : The date for which to return the last day of the month
month_to_add : Optional. Number of months to add to the start_date. EOMONTH adds the
specified number of months to start_date, and then returns the last day of the month for the
resulting date.
Output :
Example : Returns last day of the month of February from a NON-LEAP year
Output :
Example : Returns last day of the month of February from a LEAP year
Output :
161 | P a g e
month_to_add optional parameter can be used to add or subtract a specified number of
months from the start_date, and then return the last day of the month from the resulting date.
The following example adds 2 months to the start_date and returns the last day of the month
from the resulting date
Output :
The following example subtracts 1 month from the start_date and returns the last day of the
month from the resulting date
Output :
Using EOMONTH function with table data. We will use the following Employees table for this
example.
162 | P a g e
Name nvarchar(10),
DateOfBirth date
Go
The following example returns the last day of the month from the DateOfBirth of every
employee.
If you want just the last day instead of the full date, you can use DATEPART function
SELECT Name, DateOfBirth, DATEPART(DD,EOMONTH(DateOfBirth)) AS LastDay
FROM Employees
163 | P a g e
Part 126 - DATEFROMPARTS function in SQL Server
DATEFROMPARTS function
Example : All the function arguments have valid values, so DATEFROMPARTS returns the
expected date
Output :
Example : Invalid value specified for month parameter, so the function returns an error
Output : Cannot construct data type date, some of the arguments have values which are not
valid.
164 | P a g e
Example : NULL specified for month parameter, so the function returns NULL.
Output :
Other new date and time functions introduced in SQL Server 2012
165 | P a g e
The range for SmallDateTime is January 1, 1900, through June 6, 2079. A value outside of this
range, is not allowed.
The following 2 queries have values outside of the range of SmallDateTime data type.
Insert into Employees ([SmallDateTime]) values ('01/01/1899')
Insert into Employees ([SmallDateTime]) values ('07/06/2079')
When executed, the above queries fail with the following error
The conversion of a varchar data type to a smalldatetime data type resulted in an out-of-range
value
The range for DateTime is January 1, 1753, through December 31, 9999. A value outside of
this range, is not allowed.
The following query has a value outside of the range of DateTime data type.
Insert into Employees ([DateTime]) values ('01/01/1752')
When executed, the above query fails with the following error
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
DateTime2FromParts function
Example : All the function arguments have valid values, so DATETIME2FROMPARTS returns
DATETIME2 value as expected.
Output :
166 | P a g e
Example : Invalid value specified for month parameter, so the function returns an error
Output : Cannot construct data type datetime2, some of the arguments have values which are
not valid.
Example : If any of the required arguments are NULL, the function returns null. NULL specified
for month parameter, so the function returns NULL.
Output :
SELECT DATETIME2FROMPARTS ( 2015, 15, 15, 20, 55, 55, 0, NULL ) AS[DateTime2]
Output : Scale argument is not valid. Valid expressions for data type datetime2 scale argument
are integer constants and integer constant expressions.
Next video : We will discuss the difference between DateTime and DateTime2 in SQL
Server
In this video we will discuss the difference between DateTime and DateTime2 in SQL Server
167 | P a g e
January 1, 1753, through December 31, January 1, 0001, through December 31,
Date Range
9999 9999
Time Range 00:00:00 through 23:59:59.997 00:00:00 through 23:59:59.9999999
Accuracy 3.33 Milli-seconds 100 nanoseconds
Size 8 Bytes 6 to 8 Bytes (Depends on the precision)
Default
1900-01-01 00:00:00 1900-01-01 00:00:00
Value
DATETIME2 has a bigger date range than DATETIME. Also, DATETIME2 is more accurate
than DATETIME. So I would recommend using DATETIME2 over DATETIME when possible. I
think the only reason for using DATETIME over DATETIME2 is for backward compatibility.
With DateTime2
The following query retrieves the prcision, the datetime value, and the storage size.
SELECT 'Precision - 1' AS [Precision],
DateTime2Precision1 AS DateValue,
DATALENGTH(DateTime2Precision1) AS StorageSize
FROM @TempTable
UNION ALL
UNION ALL
UNION ALL
UNION ALL
UNION ALL
169 | P a g e
SELECT 'Precision - 6',
DateTime2Precision6,
DATALENGTH(DateTime2Precision6)
FROM @TempTable
UNION ALL
SELECT 'Precision - 7',
DateTime2Precision7,
DATALENGTH(DateTime2Precision7) AS StorageSize
FROM @TempTable
In this video we will discuss OFFSET FETCH Clause in SQL Server 2012
One of the common tasks for a SQL developer is to come up with a stored procedure that can
return a page of results from the result set. With SQL Server 2012 OFFSET FETCH Clause it is
very easy to implement paging.
Let's understand this with an example. We will use the following tblProducts table for the
examples in this video. The table has got 100 rows. In the image I have shown just 10 rows.
170 | P a g e
SQL Script to create tblProducts table
Create table tblProducts
(
Id int primary key identity,
Name nvarchar(25),
[Description] nvarchar(50),
Price int
)
Go
171 | P a g e
Introduced in SQL Server 2012
Returns a page of results from the result set
ORDER BY clause is required
OFFSET FETCH Syntax :
SELECT * FROM Table_Name
ORDER BY Column_List
OFFSET Rows_To_Skip ROWS
FETCH NEXT Rows_To_Fetch ROWS ONLY
Result :
From the front-end application, we would typically send the PAGE NUMBER and thePAGE
SIZE to get a page of rows. The following stored procedure accepts PAGE NUMBER and the
PAGE SIZE as parameters and returns the correct set of rows.
172 | P a g e
BEGIN
SELECT * FROM tblProducts
ORDER BY Id
OFFSET (@PageNumber - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY
END
With PageNumber = 3 and PageSize = 10, the stored procedure returns the correct set of rows
EXECUTE spGetRowsByPageNumberAndSize 3, 10
In this video we will discuss how to identify object dependencies in SQL Server using SQL
Server Management Studio.
The following SQL Script creates 2 tables, 2 stored procedures and a view
Create table Departments
(
Id int primary key identity,
Name nvarchar(50)
)
Go
173 | P a g e
Create table Employees
(
Id int primary key identity,
Name nvarchar(50),
Gender nvarchar(10),
DeptId int foreign key references Departments(Id)
)
Go
For example : To find the dependencies on the Employees table, right click on it and select
View Dependencies from the context menu
174 | P a g e
In the Object Dependencies window, depending on the radio button you select, you can find
the objects that depend on Employees table and the objects on which Employeestable
depends on.
Identifying object dependencies is important especially when you intend to modify or delete
an object upon which other objects depend. Otherwise you may risk breaking the functionality.
There are other ways for finding object dependencies in SQL Server which we will discuss in
our upcoming videos.
175 | P a g e
Part 132 - sys.dm_sql_referencing_entities in SQL Server
How to find object dependencies using the following dynamic management functions
sys.dm_sql_referencing_entities
sys.dm_sql_referenced_entities
Difference between
Referencing entity and Referenced entity
Schema-bound dependency and Non-schema-bound dependency
This is continuation to Part 131, in which we discussed how to find object dependencies using
SQL Server Management Studio. Please watch Part 131 from SQL Server tutorialbefore
proceeding.
The following example returns all the objects that depend on Employees table.
Select * from sys.dm_sql_referencing_entities('dbo.Employees','Object')
Now, let us say we have a stored procedure and we want to find the all objects that this stored
procedure depends on. This can be very achieved using another dynamic management
function, sys.dm_sql_referenced_entities.
The following query returns all the referenced entities of the stored procedure
sp_GetEmployeesandDepartments
Select * from
sys.dm_sql_referenced_entities('dbo.sp_GetEmployeesandDepartments','Object')
Please note : For both these dynamic management functions to work we need to specify the
schema name as well. Without the schema name you may not get any results.
176 | P a g e
Schema-bound dependency : Schema-bound dependency prevents referenced objects from
being dropped or modified as long as the referencing object exists
Example : A view created with SCHEMABINDING, or a table created with foreign key
constraint.
sp_depends
A system stored procedure that returns object dependencies
For example,
If you specify a table name as the argument, then the views and procedures that depend
on the specified table are displayed
If you specify a view or a procedure name as the argument, then the tables and views on
which the specified view or procedure depends are displayed.
Syntax :Execute sp_depends 'ObjectName'
177 | P a g e
as
Begin
Select * from Employees
End
Go
Ouptut :
Returns the name of the table and the respective column names on which the stored procedure
sp_GetEmployees depends
sp_depends 'sp_GetEmployees'
Output :
Sometime sp_depends does not report dependencies correctly. For example, at the moment we
have Employees table and a stored procedure sp_GetEmployees.
Now execute the following, to find the objects that depend on Employees table
sp_depends 'Employees'
We know that stored procedure sp_GetEmployees still depends on Employees table. But
sp_depends does not report this dependency, as the Employees table is dropped and
178 | P a g e
recreated.
Object does not reference any object, and no objects reference it.
sp_depends is on the deprecation path. This might be removed from the future versions of SQL
server.
Sequence object
Property Description
Built-in integer type (tinyint , smallint, int, bigint, decimal etc...) or user-defined
DataType
integer type. Default bigint.
START WITH The first value returned by the sequence object
INCREMENT The value to increment or decrement by. The value will be decremented if a
BY negative value is specified.
MINVALUE Minimum value for the sequence object
MAXVALUE Maximum value for the sequence object
Specifies whether the sequence object should restart when the max value (for
incrementing sequence object) or min value (for decrementing sequence object)
CYCLE
is reached. Default is NO CYCLE, which throws an error when minimum or
maximum value is exceeded.
CACHE Cache sequence values for performance. Default value is CACHE.
Creating an Incrementing Sequence : The following code create a Sequence object that
179 | P a g e
starts with 1 and increments by 1
Generating the Next Sequence Value : Now we have a sequence object created. To generate
the sequence value use NEXT VALUE FOR clause
Output : 1
Every time you execute the above query the sequence value will be incremented by 1. I
executed the above query 5 times, so the current sequence value is 5.
Retrieving the current sequence value : If you want to see what the current Sequence value
before generating the next, use sys.sequences
Select the next sequence value to make sure the value starts from 1
SELECT NEXT VALUE FOR [dbo].[SequenceObject]
180 | P a g e
Creating the decrementing Sequence : The following code create a Sequence object that
starts with 100 and decrements by 1
Specifying MIN and MAX values for the sequence : Use the MINVALUE and MAXVALUE
arguments to specify the MIN and MAX values respectively.
Step 2 : Retrieve the next sequence value. The sequence value starts at 100. Every time we
call NEXT VALUE, the value will be incremented by 10.
If you call NEXT VALUE, when the value reaches 150 (MAXVALUE), you will get the following
error
The sequence object 'SequenceObject' has reached its minimum or maximum value. Restart
the sequence object to allow new values to be generated.
Recycling Sequence values : When the sequence object has reached it's maximum value,
and if you want to restart from the minimum value, set CYCLE option
At this point, whe the sequence object has reached it's maximum value, and if you ask for the
NEXT VALUE, sequence object starts from the minimum value again which in this case is 100.
181 | P a g e
To improve performance, the Sequence object values can be cached using the CACHE
option. When the values are cached they are read from the memory instead of from the disk,
which improves the performance. When the cache option is specified you can also specify the
size of th cache , that is the number of values to cache.
The following example, creates the sequence object with 10 values cached. When the 11th
value is requested, the next 10 values will be cached again.
Using SQL Server Graphical User Interface (GUI) to create the sequence object :
1. Expand the database folder
2. Expand Programmability folder
3. Right click on Sequences folder
4. Select New Sequence
This is continuation to Part 134. Please watch Part 134 from SQL Server tutorial before
proceeding.
Sequence object is similar to the Identity property, in the sense that it generates sequence of
numeric values in an ascending order just like the identity property. However there are several
differences between the 2 which we will discuss in this video.
Identity property is a table column property meaning it is tied to the table, where as the
sequence is a user-defined database object and is not tied to any specific table meaning it's
value can be shared by multiple tables.
This means the above sequence object can be used with any table.
183 | P a g e
CREATE TABLE Users
(
Id INT PRIMARY KEY,
Name NVARCHAR(50),
Gender NVARCHAR(10)
)
GO
Step 2 : Insert 2 rows into Customers table and 3 rows into Users table. Notice the same
sequence object is generating the ID values for both the tables.
Output : Notice the same sequence object has generated the values for ID columns in both the
tables
To generate the next identity value, a row has to be inserted into the table, where as with
sequence object there is no need to insert a row into the table to generate the next sequence
value. You can use NEXT VALUE FOR clause to generate the next sequence value.
184 | P a g e
Example : Generating Identity value by inserting a row into the table
Example : Generating the next sequence value using NEXT VALUE FOR clause.
Maximum value for the identity property cannot be specified. The maximum value will be the
maximum value of the correspoding column data type. With the sequence object you can use
the MAXVALUE option to specify the maximum value. If the MAXVALUE option is not specified
for the sequence object, then the maximum value will be the maximum value of it's data type.
Example : Specifying maximum value for the sequence object using the MAXVALUE option
CYCLE option of the Sequence object can be used to specify whether the sequence should
restart automatically when the max value (for incrementing sequence object) or min value (for
decrementing sequence object) is reached, where as with the Identity property we don't have
any such option to automatically restart the identity values.
Example : Specifying the CYCLE option of the Sequence object, so the sequence will restart
automatically when the max value is exceeded
185 | P a g e