Introduction
A Cursor is a database object that retrieves data from a result set row by row. A Cursor is required whenever we need to process records row by row. A cursor impacts database performance. The Cursor forces the database engine to repeatedly fetch the rows, managing the locks and transmit the results. Forward-only and read-only cursors are faster and use the least resources. Cursor use the memory of the SQL Server instance and network bandwidth and also locks server resources.
Example
Suppose I have EmployeeMaster and EmployeeSalaryDetails Tables. The EmployeeMaster table contains details, like Name, code, email address and so on. And the EmployeeSalaryDetail s Table contains information like monthly total salary of each employee. Now I want to send an email to each employee for there salary for the given month.
Prerequisite tables, Stored Procedures and sample data
The following script helps to generate the table with test data and a Stored Procedure.
Create EmployeeMaster and EmployeeSalaryDetails tables:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[EmployeeMaster]') AND type in (N'U'))
DROP TABLE [dbo].[EmployeeMaster]
GO
CREATE TABLE [dbo].[EmployeeMaster](
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[EmployeeCode] [varchar](25) NULL,
[EmployeeName] [varchar](50) NULL,
[EmailAddress] [varchar](50) NULL,
CONSTRAINT [PK_EmployeeMaster] PRIMARY KEY CLUSTERED
(
[EmployeeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_EmployeeSalaryDetails_EmployeeMaster]') AND parent_object_id = OBJECT_ID(N'[dbo].[EmployeeSalaryDetails]'))
ALTER TABLE [dbo].[EmployeeSalaryDetails] DROP CONSTRAINT [FK_EmployeeSalaryDetails_EmployeeMaster]
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[EmployeeSalaryDetails]') AND type in (N'U'))
DROP TABLE [dbo].[EmployeeSalaryDetails]
GO
CREATE TABLE [dbo].[EmployeeSalaryDetails](
[SalaryDetailId] [int] IDENTITY(1,1) NOT NULL,
[EmployeeId] [int] NOT NULL,
[Month] [int] NOT NULL,
[TotalSalary] [float] NOT NULL,
CONSTRAINT [PK_EmployeeSalaryDetails2] PRIMARY KEY CLUSTERED
(
[SalaryDetailId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[EmployeeSalaryDetails] WITH CHECK ADD CONSTRAINT [FK_EmployeeSalaryDetails_EmployeeMaster] FOREIGN KEY([EmployeeId])
REFERENCES [dbo].[EmployeeMaster] ([EmployeeId])
GO
ALTER TABLE [dbo].[EmployeeSalaryDetails] CHECK CONSTRAINT [FK_EmployeeSalaryDetails_EmployeeMaster]
GO
Insert to test data
INSERT [dbo].[EmployeeMaster] ([EmployeeCode], [EmployeeName], [EmailAddress]) VALUES (N'A001', N'Jignesh Trivedi', N'[email protected]')
INSERT [dbo].[EmployeeMaster] ([EmployeeCode], [EmployeeName], [EmailAddress]) VALUES (N'A002', N'Tejas Trivedi', N'[email protected]')
INSERT [dbo].[EmployeeMaster] ([EmployeeCode], [EmployeeName], [EmailAddress]) VALUES (N'A003', N'Rakesh Trivedi', N'[email protected]')
INSERT [dbo].[EmployeeSalaryDetails] ([EmployeeId], [Month], [TotalSalary]) VALUES (1, 9, 5666.32)
INSERT [dbo].[EmployeeSalaryDetails] ([EmployeeId], [Month], [TotalSalary]) VALUES (2, 9, 10035.56)
INSERT [dbo].[EmployeeSalaryDetails] ([EmployeeId], [Month], [TotalSalary]) VALUES (3, 9, 3560)
Stored procedure for sending email
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[MailNotification]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[MailNotification]
GO
GO
CREATE PROCEDURE [dbo].[MailNotification]
@EmployeeId INT,
@EmployeeCode VARCHAR(25),
@EmailAddress VARCHAR(50),
@EmployeeName VARCHAR(25),
@TotalSalary FLOAT
AS
BEGIN
SET NOCOUNT ON;
--Write logic/code to send Email using sp_send_dbmail
END
Methods for performing row by row operations are described below.
Using Cursor
GO

Join the conversation! Your thoughts help the community grow.