SQL Server CURSOR and it’s Life Cycle
A CURSOR in SQL is a database object that contains a set of records that you can traverse one-by-one, rather than the SET as a whole.
SQL is a set-based language and produces a complete result set, and the SQL queries works on this complete set only, and not on individual rows. But there are times when the results are best processed one row at a time. Opening a cursor on a result set allows processing the result set one row at a time. You can assign a cursor to a variable or parameter with a cursor data type.
CURSOR in SQL language gives you the flexibility to traverse records like the way you do in other programming languages with iterators and for-loop.
–> A simple Cursor life cycle with minimum definition:
USE [AdventureWorks]
GO
-- Returns -3
SELECT CURSOR_STATUS('global','myCursor') AS 'Before Declare'
DECLARE myCursor CURSOR
FOR SELECT ContactID, FirstName, LastName FROM Person.Contact WHERE ContactID BETWEEN 100 and 102
-- Returns -1
SELECT CURSOR_STATUS('global','myCursor') AS 'After Declare'
DECLARE @ContactID INT, @FirstName VARCHAR(50), @LastName VARCHAR(50)
OPEN myCursor
-- Returns 1
SELECT CURSOR_STATUS('global','myCursor') AS 'Open Cusrsor'
FETCH NEXT FROM myCursor INTO @ContactID, @FirstName, @LastName
WHILE @@fetch_status=0
BEGIN
-- SQL Statements with logic inside
SELECT @ContactID, @FirstName, @LastName
FETCH NEXT FROM myCursor INTO @ContactID, @FirstName, @LastName
END
-- Returns 1
SELECT CURSOR_STATUS('global','myCursor') AS 'While loop exited, all rows iterated'
CLOSE myCursor
-- Returns -1
SELECT CURSOR_STATUS('global','myCursor') AS 'Cursor is Closed'
DEALLOCATE myCursor
-- Returns -3
SELECT CURSOR_STATUS('global','myCursor') AS 'Cursor Deallocated'
SQL Basics – IDENTITY property of a Column (in a table)
With IDENTITY property you can:
1. Creates an identity column in a table.
2. Used for generating key values, based on the current seed & increment.
3. Each new value for a particular transaction is different from other concurrent transactions on the table.
–> You can check the demo about IDENTITY property here:
–> IDENTITY property on a column does not guarantee:
1. Uniqueness of the value,
2. Consecutive values within a transaction,
3. Consecutive values after server restart or other failures,
4. Reuse of values,
–> SQL Script used in Demo:
-- IDENTITY property of a Column
CREATE TABLE [dbo].[Employee](
[EmployeeID] int NOT NULL IDENTITY (100, 1),
[EmployeeName] nvarchar(100) NOT NULL,
[Gender] nchar(1) NULL,
[DOB] datetime NULL,
[DOJ] datetime NULL,
[DeptID] int NULL
)
INSERT INTO [dbo].[Employee] (EmployeeName, Gender, DOB, DOJ, DeptID)
VALUES ('MANOJ PANDEY', 'M', '1990-01-01', '2010-01-01', 101)
INSERT INTO [dbo].[Employee] (EmployeeName, Gender, DOB, DOJ, DeptID)
VALUES ('JHON K', 'M', NULL, '2010-01-01', NULL)
INSERT INTO [dbo].[Employee] ([EmployeeName])
VALUES ('Brock H')
GO
SELECT * FROM [dbo].[Employee]
GO
-- Inserting Explicit value in IDENTITY column:
SET IDENTITY_INSERT [dbo].[Employee] ON
INSERT INTO [dbo].[Employee] ([EmployeeID],[EmployeeName])
VALUES (1000, 'Brock H')
SET IDENTITY_INSERT [dbo].[Employee] OFF
GO
SELECT * FROM [dbo].[Employee]
GO
INSERT INTO [dbo].[Employee] ([EmployeeName])
VALUES ('Jhon B')
GO
SELECT * FROM [dbo].[Employee]
GO
–> Check more articles on IDENTITY property:
– RE-SEED an IDENTITY value of a Column
– Using IDENTITY() function with SELECT into statement
– All about IDENTITY columns, some more secrets
– IDENTITY property behavior with SQL Server 2012 and above
Multiple ways to INSERT records in a table
The following exercise shows multiple ways to INSERT records in a table, as the post title says.
USE [tempdb]
GO
CREATE TABLE sometable(a INT, b VARCHAR(20), c INT)
GO
-- Method #1 - Simple INSERT statement
INSERT sometable (a, b, c)
VALUES(1, 'New York', 123)
GO
DROP TABLE sometable
-- Method #2 - CREATE the table and INSERT records. This is minimally logged operation and faster than explicitly creating table and inserting records.
SELECT 1 a, 'New York' b, 334 c
INTO sometable
UNION
SELECT 2, 'London', 823
UNION
SELECT 3, 'Paris', 1124
UNION
SELECT 4, 'Munich', 2080
GO
-- Method #3
INSERT sometable (a, b, c)
EXEC('SELECT 5, ''New York'', 234
SELECT 6, ''London'', 923
SELECT 7, ''Paris'', 1024
SELECT 8, ''Munich'', 1980')
GO
-- Method #4
INSERT sometable (a, b, c)
SELECT 9, 'New York', 334 UNION
SELECT 10, 'London', 823 UNION
SELECT 11, 'Paris', 1124 UNION
SELECT 12, 'Munich', 2080
GO
-- Method #5 - More options in SQL Server 2008, by using the VALUES() constructor
INSERT sometable (a, b, c)
VALUES (13, 'New York', 334),
(14, 'London', 823),
(15, 'Paris', 1124),
(16, 'Munich', 2080))
GO
-- Method #6 - Yes you can also use SQL statements at column level inside the VALUES constructor
INSERT sometable (a, b, c)
VALUES (18, 'New York', 334),
(19, 'London', 823),
((SELECT MAX(a)+1 FROM sometable), (SELECT b FROM sometable WHERE a=15), SELECT SUM(c) FROM sometable),
(20, 'Munich', 2080))
GO
-- Now check the resultset
SELECT * FROM sometable
-- Final Cleanup
DROP TABLE sometable
More on VALUES constructor on MS BOL: http://technet.microsoft.com/en-us/library/dd776382.aspx
Physical Join vs Logical Join in SQL Server
Most of us know about JOINS in SQL Server and their types. But do we really know how they are interpreted in SQL Server internally. Today I found lot of informative, interesting and important sources regarding Logical and Physical joins in SQL Server (links below).
–> Classifying JOINS mainly into 2 types:
1. Logical Joins: These joins are simple joins that we apply in our SQL queries, like INNER JOIN, RIGHT/LEFT OUTER JOIN, CROSS JOIN, OUTER APPLY, etc.
2. Physical Joins: These are the joins that users don’t use/write in their SQL queries. Instead these are implemented inside SQL Server engine as operators or algorithms to implement the Logical Joins. Their types are Nested Loop, Merge and Hash.
For a particular SQL query when you try to view an Estimated Execution Plan or execute a query by selecting Actual Execution Plan, you can clearly see these Physical Joins under the Execution Plan tab in SSMS.
Reference for Logical Joins from one of my old posts: https://sqlwithmanoj.wordpress.com/2009/03/12/sql-server-joins-and-types
–> Logical Joins:
– Inner/Outer/Cross: https://blogs.msdn.microsoft.com/craigfr/2006/07/19/introduction-to-joins/
–> Physical Joins:
– Nested Loop Joins: https://blogs.msdn.microsoft.com/craigfr/2006/07/26/nested-loops-join/
– Merge Joins: https://blogs.msdn.microsoft.com/craigfr/2006/08/03/merge-join/
– Hash Joins: https://blogs.msdn.microsoft.com/craigfr/2006/08/10/hash-join/
SQL DBA – Database Mail Setup – SQL Server 2005
Database Mail, a new addition to the SQL Server 2005 database engine, is an enterprise solution for sending e-mail messages from the Microsoft SQL Server 2005 Database Engine. Using Database Mail, your database applications can send e-mail messages to users. The messages can contain query results, and can also include files from any resource on your network. Database Mail is designed for reliability, scalability, security, and supportability.
Database Mail provides a robust, high-performance replacement for the most commonly requested features of SQL Mail. Database Mail is designed to operate with SMTP servers, and is tested with Microsoft SMTP servers.
Note: Database Mail is not active by default. To use Database Mail, you must explicitly enable Database Mail by using either the “SQL Server Surface Area Configuration” tool or the “Database Mail Configuration Wizard“.
Database Mail Setup:
Enabling the Database Mail feature: By default the Database mail Stored-Procs are disabled.
For Express Edition, check the required files exists in MSSQL\Binn folder. If not then copy the following 3 files:
1. DatabaseMail90.exe
2. DatabaseMailEngine.dll
3. DatabaseMailProtocols.dll
Then execute the following Stored-Porcs:
exec dbo.sysmail_start_sp exec dbo.sysmail_stop_sp
A User must be a member of the DatabaseMailUserRole database role in the msdb database.
To Enable Database Mail execute the following block of code:
use master go exec sp_configure 'show advanced options', 1 reconfigure exec sp_configure 'Database Mail XPs', 1 reconfigure
Initial Cleanup:
IF EXISTS(
SELECT * FROM msdb.dbo.sysmail_profileaccount pa
JOIN msdb.dbo.sysmail_profile p ON pa.profile_id = p.profile_id
JOIN msdb.dbo.sysmail_account a ON pa.account_id = a.account_id
WHERE
p.name = @ProfileName AND
a.name = @AccountName)
BEGIN
PRINT 'Deleting Profile Account'
EXECUTE sysmail_delete_profileaccount_sp
@profile_name = @ProfileName,
@account_name = @AccountName
END
IF EXISTS(
SELECT * FROM msdb.dbo.sysmail_profile p
WHERE p.name = @ProfileName)
BEGIN
PRINT 'Deleting Profile.'
EXECUTE sysmail_delete_profile_sp
@profile_name = @ProfileName
END
IF EXISTS(
SELECT * FROM msdb.dbo.sysmail_account a
WHERE a.name = @AccountName)
BEGIN
PRINT 'Deleting Account.'
EXECUTE sysmail_delete_account_sp
@account_name = @AccountName
END
Setting up Accounts & Profiles for DB Mail:
Create a Database Mail account for holding information about an SMTP account.
An Account holds information for only one e-mail server, such as the account name, e-mail address, reply-to e-mail address, server name or IP address, and some optional security settings.
--// Create a Database Mail account
EXECUTE msdb.dbo.sysmail_add_account_sp
@account_name = 'Test Mail Account',
@description = 'Mail account for administrative e-mail.',
@email_address = 'abc@xyz.com',
@replyto_address = 'abc@xyz.com',
@display_name = 'Manoj Pandey',
@mailserver_name = 'smtp.xxxx.net',
@port = 587,
@username = 'xyz',
@password = 'xxyyzz',
@enable_ssl = 1
-- Create a Database Mail profile
EXECUTE msdb.dbo.sysmail_add_profile_sp
@profile_name = 'Test Mail Profile',
@description = 'Profile used for administrative mail.'
-- Add the account to the profile
EXECUTE msdb.dbo.sysmail_add_profileaccount_sp
@profile_name = 'Test Mail Profile',
@account_name = 'Test Mail Account',
@sequence_number =1
-- Grant access to the profile to the DBMailUsers role
EXECUTE msdb.dbo.sysmail_add_principalprofile_sp
@profile_name = 'Test Mail Profile',
@principal_name = 'public',
@is_default = 1
Sending Mail and Check its status:
--Send mail
EXEC msdb.dbo.sp_send_dbmail
@recipients=N'manub22@gmail.com',
@body= 'Test Email Body',
@subject = 'Test Email Subject',
@profile_name = 'Test Mail Profile'
--Send mail with attachment
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'DBMail'
,@recipients = 'GroupSQLDBA@MyCo.com'
,@from_address = 'DBMail@MyCo.com'
,@query = 'SELECT resource_type, resource_database_id,
request_mode, request_session_id
FROM sys.dm_tran_locks
WHERE request_mode IN (''IX'', ''X'')'
,@subject = 'Exclusive Locks'
,@attach_query_result_as_file = 1 ;
Important Tables used in configuring Database mail and check their status:
--Profiles
SELECT * FROM msdb.dbo.sysmail_profile
--Accounts
SELECT * FROM msdb.dbo.sysmail_account
--Profile Accounts
select * from msdb.dbo.sysmail_profileaccount
--Principal Profile
select * from msdb.dbo.sysmail_principalprofile
--Mail Server
SELECT * FROM msdb.dbo.sysmail_server
SELECT * FROM msdb.dbo.sysmail_servertype
SELECT * FROM msdb.dbo.sysmail_configuration
--Email Sent Status
SELECT * FROM msdb.dbo.sysmail_allitems
SELECT * FROM msdb.dbo.sysmail_sentitems
SELECT * FROM msdb.dbo.sysmail_unsentitems
SELECT * FROM msdb.dbo.sysmail_faileditems
--Email Status
SELECT SUBSTRING(fail.subject,1,25) AS 'Subject',
fail.mailitem_id,
LOG.description
FROM msdb.dbo.sysmail_event_log LOG
join msdb.dbo.sysmail_faileditems fail
ON fail.mailitem_id = LOG.mailitem_id
WHERE event_type = 'error'
--Mail Queues
EXEC msdb.dbo.sysmail_help_queue_sp
--DB Mail Status
EXEC msdb.dbo.sysmail_help_status_sp
Note: After performing above steps the mails were not getting sent. I was configuring DB mail from my client machine, even with the admin account. I was getting various errors like:
The mail could not be sent to the recipients because of the mail server failure. (Sending Mail using Account 19 (2010-10-22T07:24:21). Exception Message: Could not connect to mail server. (A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond IP_ADD:25).
Then I tried to setup the DB mail from the server itself and it worked in one go.




