Friday, August 23, 2013

QUOTED_IDENTIFIER AND ANSI_NULLS IN SQL SERVER

These are the two widely used SET options in SQL Server. Most developers explicitly set these options while creating Stored Procedures, Triggers and User Defined Functions but many are unclear on why we need to explicitly SET them? And why they are special compared to other options?
Below is the typical usage of these options.

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
CREATE PROCEDURE SampleProcedure
AS
BEGIN
 -- select employees
 SELECT * FROM HumanResources.Employee

END
Lets first understand what they exactly mean to SQL Server and then we will move on to why they are special.
SET QUOTED_IDENTIFIER ON/OFF:
It specifies how SQL Server treats the data that is defined in Single Quotes and Double Quotes. When it is set to ON any character set that is defined in the double quotes “” is treated as a T-SQL Identifier (Table Name, Proc Name, Column Name….etc) and the T-SQL rules for naming identifiers will not be applicable to it. And any character set that is defined in the Single Quotes ‘’ is treated as a literal.
SET QUOTED_IDENTIFIER ON
CREATE TABLE "SELECT" ("TABLE" int)  -- SUCCESS
GO
SET QUOTED_IDENTIFIER ON

SELECT "sometext" AS Value   -- FAIL because “sometext” is not a literal

Though the SELECT” and “TABLE” are reserved keywords  we are able to create the table because they are now treated as identifiers and the T SQL rules for identifier names are ignored.
When it is set to OFF any character set that is defined either in Single Quotes or in Double Quotes is treated as a literal.

SET QUOTED_IDENTIFIER OFF
CREATE TABLE "SELECT"(TABLEint) -- FAIL
GO
SET QUOTED_IDENTIFIER OFF
SELECT "sometext" AS Value    -- SUCCESS as “sometext” is treated as a literal


You can clearly see the difference in CREATE TABLE and SELECT query. Here the CREATE TABLE fails because “SELECT” is a reserved keyword and it is considered as a literal. The default behavior is ON in any database.
 SET ANSI_NULLS ON/OFF:
The ANSI_NULLS option specifies that how SQL Server handles the comparison operations with NULL values. When it is set to ON any comparison with NULL using = and <> will yield to false value. And it is the ISO defined standard behavior. So to do the comparison with NULL values we need to use IS NULL and IS NOT NULL. And when it is set to OFF any comparison with NULL using = and <> will work as usual i.e. NULL = NULL returns true and 1= NULL returns false.
SET ANSI_NULLS ON
IF NULL = NULL
 PRINT 'same'
ELSE
 PRINT 'different'
--result:  different

SET ANSI_NULLS ON
IF NULL IS NULL
 PRINT 'same'
ELSE
 PRINT 'different'
-- result: same
SET ANSI_NULLS OFF
IF NULL = NULL
 PRINT 'same'
ELSE
 PRINT 'different'
--result:  same (now NULL = NULL works as 1=1)
The default behavior is ON in any database. As per BOL 2008 this option will always be set to ON in the future releases of SQL Server and any explicit SET to OFF will result an error. So avoid explicitly setting this option in future development work.
 Why are these two options Special?:
These two SET options are special because whenever a stored procedure or a Trigger or a User Defined Function is created or modified with these options explicitly SET; SQL Server remembers those settings in the associated object metadata. And every time the object (stored procedure,Trigger..etc.) is executed SQL server uses the stored settings irrespective of what the current user session settings are. So the behavior of the stored procedure is not altered by the calling session settings and the usage of the SET option behavior inside the SP is always guaranteed.
You can get any procedure or trigger or function settings for these options from the sys..sql_modules metadata table.
SELECT uses_ansi_nulls, uses_quoted_identifier
 FROM sys.sql_modules WHERE object_id = object_id('SampleProcedure')
And if you need to guarantee the behavior for other SET options like SET ARITHABORT inside the SP then you need to SET them inside the procedure. The scope of the options specified inside the procedure are only applicable until the procedure completes its execution.
 Hope it helps.
- Arka Gupta

Tuesday, August 20, 2013

AGING in SQL Server 2008

I calculate this Aging Report on 20-August-2013. So, you can change data as your requirement...

CREATE TABLE TAB1 (ITEM VARCHAR(20),DATE DATETIME,QTY INT)

INSERT INTO TAB1
SELECT 'BOOK1','2013-04-01',1 UNION ALL SELECT 'BOOK2','2013-04-02',1 UNION ALL
SELECT 'BOOK3','2013-04-03',1 UNION ALL SELECT 'BOOK4','2013-04-04',1 UNION ALL
SELECT 'BOOK1','2013-04-11',1 UNION ALL SELECT 'BOOK2','2013-04-12',1 UNION ALL
SELECT 'BOOK3','2013-04-13',1 UNION ALL SELECT 'BOOK4','2013-04-14',1 UNION ALL
SELECT 'BOOK1','2013-04-21',1 UNION ALL SELECT 'BOOK2','2013-04-22',1 UNION ALL
SELECT 'BOOK3','2013-04-23',1 UNION ALL SELECT 'BOOK4','2013-04-24',1 UNION ALL
SELECT 'BOOK1','2013-05-01',1 UNION ALL SELECT 'BOOK2','2013-05-02',1 UNION ALL
SELECT 'BOOK3','2013-05-03',1 UNION ALL SELECT 'BOOK4','2013-05-04',1 UNION ALL
SELECT 'BOOK1','2013-05-11',1 UNION ALL SELECT 'BOOK2','2013-05-12',1 UNION ALL
SELECT 'BOOK3','2013-05-13',1 UNION ALL SELECT 'BOOK4','2013-05-14',1 UNION ALL
SELECT 'BOOK1','2013-05-21',1 UNION ALL SELECT 'BOOK2','2013-05-22',1 UNION ALL
SELECT 'BOOK3','2013-05-23',1 UNION ALL SELECT 'BOOK4','2013-05-24',1 UNION ALL
SELECT 'BOOK1','2013-06-01',1 UNION ALL SELECT 'BOOK2','2013-06-02',1 UNION ALL
SELECT 'BOOK3','2013-06-03',1 UNION ALL SELECT 'BOOK4','2013-06-04',1 UNION ALL
SELECT 'BOOK1','2013-06-11',1 UNION ALL SELECT 'BOOK2','2013-06-12',1 UNION ALL
SELECT 'BOOK3','2013-06-13',1 UNION ALL SELECT 'BOOK4','2013-06-14',1 UNION ALL
SELECT 'BOOK1','2013-06-21',1 UNION ALL SELECT 'BOOK2','2013-06-22',1 UNION ALL
SELECT 'BOOK3','2013-06-23',1 UNION ALL SELECT 'BOOK4','2013-06-24',1 UNION ALL
SELECT 'BOOK1','2013-07-01',1 UNION ALL SELECT 'BOOK2','2013-07-02',1 UNION ALL
SELECT 'BOOK3','2013-07-03',1 UNION ALL SELECT 'BOOK4','2013-07-04',1 UNION ALL
SELECT 'BOOK1','2013-07-11',1 UNION ALL SELECT 'BOOK2','2013-07-12',1 UNION ALL
SELECT 'BOOK3','2013-07-13',1 UNION ALL SELECT 'BOOK4','2013-07-14',1 UNION ALL
SELECT 'BOOK1','2013-07-21',1 UNION ALL SELECT 'BOOK2','2013-07-22',1 UNION ALL
SELECT 'BOOK3','2013-07-23',1 UNION ALL SELECT 'BOOK4','2013-07-24',1

SELECT * FROM TAB1 ORDER BY ITEM, DATE ASC

SELECT ITEM,
SUM(CASE WHEN DATEDIFF(DD,DATE,GETDATE())<= 30 THEN QTY ELSE 0 END) 
AS [0-30],
SUM(CASE WHEN DATEDIFF(DD,DATE,GETDATE())<= 60 AND DATEDIFF(DD,DATE,GETDATE())>= 31 THEN QTY ELSE 0 END) 
AS [31-60],
SUM(CASE WHEN DATEDIFF(DD,DATE,GETDATE())<= 90 AND DATEDIFF(DD,DATE,GETDATE())>= 61 THEN QTY ELSE 0 END) 
AS [61-90],
SUM(CASE WHEN DATEDIFF(DD,DATE,GETDATE())>= 91 THEN QTY ELSE 0 END)
AS [90+],
SUM(QTY) AS TOTAL_QTY FROM TAB1 GROUP BY ITEM
ORDER BY TOTAL_QTY DESC

Know your age in SQL Server 2008

Just put your Date of Birth (DOB) at parameter @FRMDT and  execute following code...

DECLARE @FRMDT AS DATETIME
DECLARE @TODT AS DATETIME
SET @FRMDT = '1987-08-20'
SET @TODT = GETDATE()
SELECT DATEPART (YEAR, @TODT-@FRMDT)-1900 AS YEARS,  
DATEPART (MONTH, @TODT-@FRMDT)-1 AS MONTHS,    
DATEPART (DAY, @TODT-@FRMDT)-1 AS DAYS,  
DATEPART (HOUR, @TODT-@FRMDT) AS HOURS,
DATEPART (MINUTE, @TODT-@FRMDT) AS MINUTES,
DATEPART (SECOND, @TODT-@FRMDT) AS SECONDS,
DATEPART (MILLISECOND, @TODT-@FRMDT) AS MILLISECONDS

Date Time Format in SQL Server 2008

SELECT GETDATE()
2013-08-20 12:27:37.663
SELECT CAST ( GETDATE() AS VARCHAR(20))
Aug 20 2013 12:27PM
SELECT CONVERT(VARCHAR,GETDATE())
Aug 20 2013 12:27PM
SELECT CONVERT(VARCHAR,GETDATE(),0)'0'
Aug 20 2013 12:27PM
SELECT CONVERT(VARCHAR,GETDATE(),1)'1'
08/20/13
SELECT CONVERT(VARCHAR,GETDATE(),2)'2'
13.08.20
SELECT CONVERT(VARCHAR,GETDATE(),3)'3'
20/08/13
SELECT CONVERT(VARCHAR,GETDATE(),4)'4'
20.08.13
SELECT CONVERT(VARCHAR,GETDATE(),5)'5'
20-08-13
SELECT CONVERT(VARCHAR,GETDATE(),6)'6'
20 Aug 13
SELECT CONVERT(VARCHAR,GETDATE(),7)'7'
Aug 20, 13
SELECT CONVERT(VARCHAR,GETDATE(),8)'8'
12:27:37
SELECT CONVERT(VARCHAR,GETDATE(),9)'9'
Aug 20 2013 12:27:37:663PM
SELECT CONVERT(VARCHAR,GETDATE(),10)'10'
08-20-13
SELECT CONVERT(VARCHAR,GETDATE(),11)'11'
13/08/20
SELECT CONVERT(VARCHAR,GETDATE(),12)'12'
130820
SELECT CONVERT(VARCHAR,GETDATE(),13)'13'
20 Aug 2013 12:27:37:663
SELECT CONVERT(VARCHAR,GETDATE(),14)'14'
12:27:37:663
SELECT CONVERT(VARCHAR,GETDATE(),100)'100'
Aug 20 2013 12:27PM
SELECT CONVERT(VARCHAR,GETDATE(),101)'101'
08/20/2013
SELECT CONVERT(VARCHAR,GETDATE(),102)'102'
2013.08.20
SELECT CONVERT(VARCHAR,GETDATE(),103)'103'
20/08/2013
SELECT CONVERT(VARCHAR,GETDATE(),104)'104'
20.08.2013
SELECT CONVERT(VARCHAR,GETDATE(),105)'105'
20-08-2013
SELECT CONVERT(VARCHAR,GETDATE(),106)'106'
20 Aug 2013
SELECT CONVERT(VARCHAR,GETDATE(),107)'107'
Aug 20, 2013
SELECT CONVERT(VARCHAR,GETDATE(),108)'108'
12:27:37
SELECT CONVERT(VARCHAR,GETDATE(),109)'109'
Aug 20 2013 12:27:37:663PM
SELECT CONVERT(VARCHAR,GETDATE(),110)'110'
08-20-2013
SELECT CONVERT(VARCHAR,GETDATE(),111)'111'
2013/08/20
SELECT CONVERT(VARCHAR,GETDATE(),112)'112'
20130820
SELECT CONVERT(VARCHAR,GETDATE(),113)'113'
20 Aug 2013 12:27:37:663
SELECT CONVERT(VARCHAR,GETDATE(),114)'114'
12:27:37:663
SELECT CONVERT(VARCHAR,GETDATE(),120)'120'
2013-08-20 12:27:37
SELECT CONVERT(VARCHAR,GETDATE(),121)'121'
2013-08-20 12:27:37.663
SELECT CONVERT(VARCHAR,GETDATE(),126)'126'
2013-08-20T12:27:37.663
SELECT CONVERT(VARCHAR,GETDATE(),130)'130'
14 ???? 1434 12:27:37:663PM
SELECT CONVERT(VARCHAR,GETDATE(),131)'131'
14/10/1434 12:27:37:663PM

How to add ‘st’,’nd’,’rd’,’th’ to dates in SQL Server 2008 using CASE statement

Hi, Friends! Welcome to all of you in my Blog.
Today is a special day in my life… My Birthday. Yeah! This is 20th August.
So, today I write in a topic of How we can add ‘st’,’nd’,’rd’,’th’ to dates in SQL Server 2008.

USE [tempdb]
GO
--Create a sample table
CREATE TABLE [dbo].[tbl_sample](
[ID] [int] NULL,
[Date] [date] NULL
)
GO
--Insert records in the table
INSERT INTO dbo.[tbl_sample]
SELECT 1 AS [ID] ,N'2013-08-01' AS [Date] UNION ALL
SELECT 2 AS [ID] ,N'2013-08-02' AS [Date] UNION ALL
SELECT 3 AS [ID] ,N'2013-08-03' AS [Date] UNION ALL
SELECT 4 AS [ID] ,N'2013-08-04' AS [Date] UNION ALL
SELECT 5 AS [ID] ,N'2013-08-05' AS [Date] UNION ALL
SELECT 6 AS [ID] ,N'2013-08-06' AS [Date] UNION ALL
SELECT 7 AS [ID] ,N'2013-08-07' AS [Date] UNION ALL
SELECT 8 AS [ID] ,N'2013-08-08' AS [Date] UNION ALL
SELECT 9 AS [ID] ,N'2013-08-09' AS [Date] UNION ALL
SELECT 10 AS [ID] ,N'2013-08-10' AS [Date] UNION ALL
SELECT 11 AS [ID] ,N'2013-08-11' AS [Date] UNION ALL
SELECT 12 AS [ID] ,N'2013-08-12' AS [Date] UNION ALL
SELECT 13 AS [ID] ,N'2013-08-13' AS [Date] UNION ALL
SELECT 14 AS [ID] ,N'2013-08-14' AS [Date] UNION ALL
SELECT 15 AS [ID] ,N'2013-08-15' AS [Date] UNION ALL
SELECT 16 AS [ID] ,N'2013-08-16' AS [Date] UNION ALL
SELECT 17 AS [ID] ,N'2013-08-17' AS [Date] UNION ALL
SELECT 18 AS [ID] ,N'2013-08-18' AS [Date] UNION ALL
SELECT 19 AS [ID] ,N'2013-08-19' AS [Date] UNION ALL
SELECT 20 AS [ID] ,N'2013-08-20' AS [Date] UNION ALL
SELECT 21 AS [ID] ,N'2013-08-21' AS [Date] UNION ALL
SELECT 22 AS [ID] ,N'2013-08-22' AS [Date] UNION ALL
SELECT 23 AS [ID] ,N'2013-08-23' AS [Date] UNION ALL
SELECT 24 AS [ID] ,N'2013-08-24' AS [Date] UNION ALL
SELECT 25 AS [ID] ,N'2013-08-25' AS [Date] UNION ALL
SELECT 26 AS [ID] ,N'2013-08-26' AS [Date] UNION ALL
SELECT 27 AS [ID] ,N'2013-08-27' AS [Date] UNION ALL
SELECT 28 AS [ID] ,N'2013-08-28' AS [Date] UNION ALL
SELECT 29 AS [ID] ,N'2013-08-29' AS [Date] UNION ALL
SELECT 30 AS [ID] ,N'2013-08-30' AS [Date] UNION ALL
SELECT 31 AS [ID] ,N'2013-08-31' AS [Date]

--DROP TABLE [dbo].[tbl_sample]

SELECT ID, [DATE], FORMATDATE = CASE                           
WHEN DAY([DATE]) IN (1,21,31) THEN DATENAME(D,[DATE])+'st ' + DATENAME(MONTH, [DATE]) + ' ' + DATENAME(YEAR, [DATE]) 
WHEN DAY([DATE]) IN (2,22) THEN  DATENAME(D,[DATE])+'nd ' + DATENAME(MONTH, [DATE]) + ' ' + DATENAME(YEAR, [DATE])                       
WHEN DAY([DATE]) IN (3,23) THEN  DATENAME(D,[DATE])+'rd ' + DATENAME(MONTH, [DATE]) + ' ' + DATENAME(YEAR, [DATE])                       
ELSE DATENAME(D,[DATE])+'th ' + DATENAME(MONTH, [DATE])+ ' ' + DATENAME(YEAR, [DATE])
END            

FROM TBL_SAMPLE