----------------------------------------------
-- Try/Catch
USE AdventureWorks
GO
CREATE PROCEDURE MyProc
AS
BEGIN
BEGIN TRY
SELECT * FROM Person.Address WHERE 1 > 2/0
END TRY
BEGIN CATCH
PRINT 'Error Occurred'
PRINT ERROR_NUMBER()
PRINT ERROR_SEVERITY()
PRINT ERROR_STATE()
PRINT ERROR_MESSAGE()
END CATCH
END
GO
EXEC MyProc
----------------------------------------------
-- Common Table Expressions
WITH Median AS
(
SELECT ((MAX(LineTotal) - MIN(LineTotal)) / 2)
AS MedianValue FROM Sales.SalesOrderDetail
)
SELECT TOP 1000 SalesOrderID, SalesOrderDetailID, LineTotal,
CASE
WHEN LineTotal > Median.MedianValue THEN 1
ELSE 0
END AS OverHalf
FROM Sales.SalesOrderDetail, Median
----------------------------------------------
-- Common Table Expressions (Recursive)
SET NOCOUNT ON
CREATE TABLE MLM (
ID int,
Name varchar(10),
Parent int)
GO
INSERT MLM VALUES ( 1,'Bob',null)
INSERT MLM VALUES ( 2,'Amy',1)
INSERT MLM VALUES ( 3,'Jake',1)
INSERT MLM VALUES ( 4,'Kirra',2)
INSERT MLM VALUES ( 5,'Mark',3)
INSERT MLM VALUES ( 6,'Steve',3)
INSERT MLM VALUES ( 7,'Randy',3)
INSERT MLM VALUES ( 8,'Kristen',4)
INSERT MLM VALUES ( 9,'Isaac',6)
INSERT MLM VALUES (10,'Cole',9)
GO
SELECT * FROM MLM
GO
WITH Descendant (Parent,ID,Name) AS
(SELECT Parent, ID, Name
FROM MLM WHERE ID = 3
UNION ALL
SELECT M.Parent, M.ID, M.Name
FROM MLM AS M INNER JOIN
Descendant AS D ON D.ID = M.Parent)
SELECT ID FROM Descendant
GO
DROP TABLE MLM
----------------------------------------------
-- PIVOT
-- Raw data - expensive (> $10k items) sold in 2002 by quarter
SELECT DatePart(q,OrderDate) as Quarter, P.Name, LineTotal
FROM Sales.SalesOrderHeader AS H
INNER JOIN Sales.SalesOrderDetail AS D ON H.SalesOrderID = D.SalesOrderID
INNER JOIN Production.Product AS P ON D.ProductID = P.ProductID
WHERE DatePart(yy,OrderDate) = 2002 AND D.LineTotal > 10000
-- Put into a temporary table (optional)
SET NOCOUNT ON
SELECT DatePart(q,OrderDate) as Quarter, P.Name, LineTotal
INTO #TempSales
FROM Sales.SalesOrderHeader AS H
INNER JOIN Sales.SalesOrderDetail AS D ON H.SalesOrderID = D.SalesOrderID
INNER JOIN Production.Product AS P ON D.ProductID = P.ProductID
WHERE DatePart(yy,OrderDate) = 2002 AND D.LineTotal > 10000
-- Pivot
SELECT Name, [1] AS 'Q1', [2] AS 'Q2', [3] AS 'Q3', [4] AS 'Q4'
FROM #TempSales
PIVOT(SUM(LineTotal)
FOR Quarter IN ([1], [2], [3], [4])) AS P
-- Done
DROP TABLE #TempSales
----------------------------------------------
-- ROW_NUMBER
-- Return Orders for Customers < 100 with row numbers
SELECT SalesOrderID, CustomerID,
ROW_NUMBER() OVER(ORDER BY SalesOrderID) AS Number
FROM Sales.SalesOrderHeader
WHERE CustomerID < 100
-- Return Orders for Customers < 100 with row numbers and more!
SELECT SalesOrderID, CustomerID,
ROW_NUMBER() OVER(ORDER BY CustomerID) AS Number,
RANK() OVER(ORDER BY CustomerID) AS [rank],
DENSE_RANK() OVER(ORDER BY CustomerID) AS [denserank],
NTILE(5) OVER(ORDER BY CustomerID) AS ntile5
FROM Sales.SalesOrderHeader
WHERE CustomerID < 100
----------------------------------------------
-- WINDOWING (OVER)
SELECT *,
RANK() OVER(PARTITION BY Title ORDER BY VacationHours) AS [rank]
from
(
SELECT E.Title, C.LastName, E.VacationHours
FROM HumanResources.Employee AS E
INNER JOIN Person.Contact AS C ON E.ContactID = C.ContactID
) AS A
----------------------------------------------
-- WINDOWING (OVER with MAX aggregate)
SELECT *,
RANK() OVER(PARTITION BY Title ORDER BY VacationHours) AS [rank],
MAX(VacationHours) OVER(PARTITION BY Title) as [Most Hours by Title]
from
(
SELECT E.Title, C.LastName, E.VacationHours
FROM HumanResources.Employee AS E
INNER JOIN Person.Contact AS C ON E.ContactID = C.ContactID
) AS A
----------------------------------------------
-- CROSS APPLY and OUTER APPLY
-- Create UDF
CREATE FUNCTION Greater(@v float, @t float)
RETURNS TABLE AS
RETURN SELECT @v AS UDF
WHERE @v > @t
GO
-- Test
/*
SELECT * FROM dbo.Greater(100,200)
SELECT * FROM dbo.Greater(200,100)
SELECT * FROM dbo.Greater(200,200)
-- Test with CROSS APPLY
SELECT * FROM Sales.SalesOrderDetail AS D
CROSS APPLY Greater(D.LineTotal, 15000)
WHERE OrderQty > 10
-- Test with OUTER APPLY
SELECT * FROM Sales.SalesOrderDetail AS D
OUTER APPLY Greater(D.LineTotal, 15000)
WHERE OrderQty > 10
*/
-- Done
DROP FUNCTION Greater
GO
----------------------------------------------
-- UPDATE with OUTPUT
SET NOCOUNT OFF
SELECT * FROM Production.Product WHERE Color = 'Black'
--
UPDATE Production.Product SET Color = 'Schwarz' WHERE Color = 'Black'
--
DECLARE @Changes
TABLE (ProductID int,
Name nvarchar(50),
Color nvarchar(15),
OldColor nvarchar(15))
UPDATE Production.Product SET Color = 'Black'
OUTPUT Inserted.ProductID, Inserted.Name, Inserted.Color, Deleted.Color
INTO @Changes WHERE Color = 'Schwarz'
SELECT * FROM @Changes
----------------------------------------------
-- INSERT with OUTPUT
USE AdventureWorks
GO
SET NOCOUNT ON
GO
-- Create table
CREATE TABLE Test (ID int identity(1,1), Data varchar(20))
GO
-- Quick Test
INSERT Test (Data) Values ('Red')
SELECT * FROM Test
-- @@IDENTITY returns last identity value assigned
INSERT Test (Data) Values ('Blue')
SELECT @@IDENTITY
-- @@IDENTITY doesn't handle inserting multiple rows
INSERT Test (Data) SELECT Data FROM Test
SELECT @@Identity
-- Using INSERT ... with OUTPUT is the solution!
DECLARE @NewRows TABLE (ID int, Data varchar(20))
INSERT Test (Data)
OUTPUT Inserted.ID, Inserted.Data INTO @NewRows
SELECT Data FROM Test
SELECT * FROM @NewRows
-- Done
DROP TABLE Test
----------------------------------------------
-- Large Objects (LOBs)
CREATE TABLE BigText (ID int, Data text)
INSERT BigText VALUES (1,'Hello World')
--
SELECT * FROM BigText
SELECT UPPER(Data) FROM BigText
--
INSERT BigText VALUES (1,REPLICATE('x',10000))
SELECT * FROM BigText
--
DROP Table BigText
CREATE TABLE BigText (ID int, Data varchar(max))
--
INSERT BigText VALUES (1,'Hello World')
INSERT BigText VALUES (1,REPLICATE('x',10000))
SELECT * FROM BigText
SELECT UPPER(Data) FROM BigText
--
DROP Table BigText
----------------------------------------------
-- Synonyms
CREATE SYNONYM Emp
FOR AdventureWorks.HumanResources.Employee
SELECT * FROM Emp
DROP SYNONYM Emp
----------------------------------------------
-- DDL Triggers
CREATE TRIGGER trgThankYou ON DATABASE FOR CREATE_TABLE
AS PRINT 'Thank you for contributing to AdventureWorks!'
--
CREATE TABLE NewTable (ID int)
--
CREATE TRIGGER trgSafety ON DATABASE FOR DROP_TABLE
AS PRINT 'Sorry, you may not drop tables!' ROLLBACK
--
DROP TABLE NewTable
-- How do you drop DDL triggers? (Have SMS show you ...)
DROP TRIGGER [trgSafety] ON DATABASE
DROP TRIGGER [trgThankYou] ON DATABASE
DROP TABLE NewTable
----------------------------------------------
-- XML
----------------------------------------------
----------------------------------------------
-- XML Data Type
SET NOCOUNT ON
CREATE TABLE Candidate (ID int, Name varchar(50), Resume xml)
--
INSERT Candidate VALUES (1,'Smith','none')
SELECT * FROM Candidate
--
INSERT Candidate VALUES (1,'Smith','none')
INSERT Candidate VALUES (1,'Smith','nonenone')
SELECT * FROM Candidate
--
INSERT Candidate VALUES (1,'Smith','none')
INSERT Candidate VALUES (1,'Smith','no resume & no CV')
----------------------------------------------
-- XML Schema
CREATE XML SCHEMA COLLECTION ResumeSchema AS N''
-- Schema
--
SELECT * FROM sys.xml_schema_collections
-- Create Table
DROP TABLE Candidate
CREATE TABLE Candidate (ID int, Name varchar(50), Resume xml (ResumeSchema))
--
INSERT Candidate VALUES (1,'Smith','')
-- Smith.xml
Pat
Smith
Speak about Yukon and Whidbey
1993
1999
Software Developer
Built lots of really cool software!
2000
2005
Trainer and Author
Wrote books and spoke at lots of conferences
1989
1993
Podunk University
I like pudding!
----------------------------------------------
-- FOR XML Improvements
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE ContactID < 10
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE ContactID < 10
FOR XML AUTO
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE ContactID < 10
FOR XML AUTO, ELEMENTS
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE ContactID < 10
FOR XML PATH
--
SELECT Title AS '@Title',
FirstName as 'Name/First',
LastName as 'Name/Last',
EmailAddress as 'Email'
FROM Person.Contact
WHERE ContactID < 10
FOR XML PATH ('Person')
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE FirstName = 'Cathan'
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE FirstName = 'Cathan'
FOR XML AUTO, ELEMENTS
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE FirstName = 'Cathan'
FOR XML AUTO, ELEMENTS XSINIL
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE FirstName = 'Cathan'
FOR XML AUTO, XMLDATA
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE FirstName = 'Cathan'
FOR XML AUTO, XMLSCHEMA
--
SELECT Title, FirstName, LastName, EmailAddress
FROM Person.Contact
WHERE FirstName = 'Cathan'
FOR XML AUTO, ELEMENTS, XMLSCHEMA
--
DECLARE @XML XML
SET @XML =
(SELECT Title, FirstName, LastName, EmailAddress FROM Person.Contact
WHERE ContactID < 10 FOR XML PATH)
SELECT @XML
----------------------------------------------
-- XQUERY
DECLARE @xmldoc xml
SET @xmldoc = '
Martin
Gudgin
33
short
Simon
Horrell
40
short
Mark
Szolkowski
30
medium
'
SELECT @xmldoc
-- Return names
SELECT @xmldoc.query('
(: SQL Server 2005 :)
(: doc function not used :)
for $p in /people/person
return $p/name')
-- Return people older than 30 (XPATH way)
SELECT @xmldoc.query('
(: this uses an XPath predicate :)
/people/person[age > 30]')
-- Return people older than 30 (FLWOR way)
SELECT @xmldoc.query('
(: this uses a where :)
for $p in /people/person
where $p/age > 30
order by $p/age[1]
return $p/name')
-- Getting Creative
SELECT @xmldoc.query('
(: this uses a where :)
for $p in /people/person
where $p/age > 30
order by $p/age[1]
return {$p/name}')
----------------------------------------------
-- XML DML
UPDATE HumanResources.JobCandidate SET Resume = ' entire new xml document '
--
DECLARE @myDoc xml
SET @myDoc =
''
SELECT @myDoc as Example
--
SET @myDoc.modify('insert Built Microsoft BOB
into (/Student/Experience)[1]')
SELECT @myDoc
--
SET @myDoc.modify('
replace value of (/Student/Experience/Development[1]/text())[1]
with "Built Donkey .NET"')
SELECT @myDoc
--
SET @myDoc.modify('delete /Student/Experience/Development[1]')
SELECT @myDoc
---------------------------------------------------------------
-- Managed Code
---------------------------------------------------------------
---------------------------------------------------------------
-- UDF
using System;
using System.Collections;
using System.Data;
using System.Data.Sql;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class CoolFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString CoolEncrypt(SqlString Data)
{
char[] strArray = Data.ToString().ToCharArray();
Array.Reverse(strArray);
return new string(strArray);
}
};
--
SELECT dbo.CoolEncrypt('SQL Server 2005 Rocks!')
SELECT dbo.CoolEncrypt('A man a plan a canal Panama')
---------------------------------------------------------------
-- Update the TEST.SQL and run with F5
---------------------------------------------------------------
-- Add a breakpoint and run with F5
---------------------------------------------------------------
-- Stored Procedure
using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlTypes;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void spTransformXML(SqlXml rawXML, SqlXml rawXSLT)
{
SqlPipe pipe = SqlContext.Pipe;
// Cast XML
XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.LoadXml(rawXML.Value);
// Cast XSLT
XmlDocument xslDoc = new System.Xml.XmlDocument();
xslDoc.LoadXml(rawXSLT.Value);
// Transform
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xslDoc);
Stream stream = new MemoryStream();
XmlWriter wrt = new XmlTextWriter(stream, System.Text.Encoding.UTF8);
xslt.Transform(xmlDoc, null, wrt);
// Return HTML
stream.Position = 0;
StreamReader SR = new StreamReader(stream);
pipe.Send(SR.ReadToEnd());
SR.Close();
}
};
---------------------------------------------------------------
-- Test
DECLARE @xml xml
SET @xml = '
Richard
Hundhausen
Trainer
Steven
Borg
Trainer
'
DECLARE @xsl xml
SET @xsl = '
|
|
|
'
exec spTransformXML @xml, @xsl
---------------------------------------------------------------
-- UDT
using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)]
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public class DMS : INullable
{
private Int16 dd, mm, ss;
private bool bIsNull = true;
public Int16 DD
{
get { return dd; }
set { dd = value; }
}
public Int16 MM
{
get { return mm; }
set { mm = value; }
}
public Int16 SS
{
get { return ss; }
set { ss = value; }
}
public override string ToString()
{
if (bIsNull)
return "null";
else
return String.Format("{0}°{1}'{2}", dd, mm, ss);
}
public bool IsNull
{
get
{
return bIsNull;
}
}
public static DMS Null
{
get
{
DMS dms = new DMS();
return dms;
}
}
public static DMS Parse(SqlString s)
{
if (s.IsNull || s.Value.ToLower().Equals("null"))
return null;
DMS dms = new DMS();
string[] st = s.Value.Split('.');
dms.DD = Int16.Parse(st[0]);
dms.MM = Int16.Parse(st[1]);
dms.SS = Int16.Parse(st[2]);
dms.bIsNull = false;
return dms;
}
}
---------------------------------------------------------------
-- Test the UDT
CREATE TABLE EmployeeLocation (
Employee int,
Latitude DMS,
Longitude DMS)
GO
INSERT EmployeeLocation VALUES (1,'15.55.00','37.15.12')
INSERT EmployeeLocation VALUES (2,'25.27.15','114.38.05')
SELECT Latitude.DD, Latitude.MM, Latitude.SS FROM EmployeeLocation
SELECT Latitude.ToString() FROM EmployeeLocation
-- Fails because the assembly isn't registered on the local machine
SELECT * FROM EmployeeLocation
INSERT EmployeeLocation VALUES (3,null,null)
SELECT Latitude.ToString() FROM EmployeeLocation