Security.sql in SQL Server 2005- All others SQL Server 2005 Script have moved to Article under SQL Server

 

-------------------------

-- *** Windows Logins ***

-- **********************

-- This code assumes that JoeAppdev and JaneAppdev already exist as a Windows login

-- Add a Windows login to SQL Server

-- Note that the brackets are required for a Windows login

CREATE

LOGIN [APPDEV\JaneAppDev] FROM WINDOWS;

GO

USE

GO

CREATE

WITH DEFAULT_SCHEMA = Production

GO

-- Or, rename the user in the database

DROP

GO

CREATE

GO

-- Alter the login to add a default schema

ALTER

WITH DEFAULT_SCHEMA = Production

GO

-- Add one of the built-in Windows groups

CREATE

LOGIN [BUILTIN\Users] FROM WINDOWS;

GO

-- *** SQL Server Logins ***

-- *************************

CREATE

LOGIN Topaz WITH PASSWORD = 'Bo3EXNWJ#N6ndg5';

GO

USE

GO

CREATE

WITH DEFAULT_SCHEMA = HumanResources

GO

-- Or, rename the user in the database

DROP

GO

CREATE

WITH DEFAULT_SCHEMA = HumanResources

GO

-- *** Password Policies ***

-- *************************

-- Requires that SQL Server be running on Windows Server 2003 or later

-- and that password policies be enabled in Local Security Settings.

USE

GO

CREATE

LOGIN SIMPLEPWD WITH PASSWORD = 'SIMPLEPWD'

GO

ALTER

LOGIN Topaz WITH PASSWORD = 'Bo3EXNWJ#N6ndg5',

CHECK_EXPIRATION = OFF, CHECK_POLICY = OFF

ALTER

-- *** Authorization ***

==

*********************

-- *** Server Roles

-- Add login Topaz to the sysadmin role

sp_addsrvrolemember

'Topaz', 'sysadmin'

-- Get a list of all server roles

EXEC

sp_helpsrvrole

-- Get the description of a single server role

EXEC

-- Get list of members of the diskadmin role

EXEC

-- *** Database roles

 

 

 

 

 

/*** Execution Context

**********************/

-- Execution Context Sample

-- *** Create the database for this demo ***

USE

GO

CREATE

LOGIN UserProc WITH password = 'Y&2!@37z#F!l1zB'

CREATE

LOGIN UserTable WITH password = 'Y&2!@37z#F!l1zB'

CREATE

LOGIN RealUser WITH password = 'Y&2!@37z#F!l1zB'

GO

CREATE

GO

USE

GO

-- Create the users

CREATE

CREATE

CREATE

GO

-- Create the schemas

CREATE

GO

CREATE

GO

-- Create a table and a proc in different schemas to ensure that

-- there is no ownerhship chaining.

CREATE

TABLE SchemaUserTable.Vendor (ID int, name varchar(50), state char(2), phno char(12))

GO

INSERT

INTO SchemaUserTable.Vendor VALUES (1,'Vendor1','AK','123-345-1232')

INSERT

INTO SchemaUserTable.Vendor VALUES (2,'Vendor2','WA','454-765-3233')

INSERT

INTO SchemaUserTable.Vendor VALUES (3,'Vendor3','OR','345-776-3433')

INSERT

INTO SchemaUserTable.Vendor VALUES (4,'Vendor4','AK','232-454-5654')

INSERT

INTO SchemaUserTable.Vendor VALUES (5,'Vendor5','OR','454-545-5654')

INSERT

INTO SchemaUserTable.Vendor VALUES (6,'Vendor6','HI','232-655-1232')

INSERT

INTO SchemaUserTable.Vendor VALUES (7,'Vendor7','HI','453-454-1232')

INSERT

INTO SchemaUserTable.Vendor VALUES (8,'Vendor8','WA','555-654-1232')

INSERT

INTO SchemaUserTable.Vendor VALUES (9,'Vendor9','AK','555-345-1232')

GO

-- Create the stored procedure in SchemaUserProc

CREATE

PROC SchemaUserProc.VendorAccessProc @state char(2)

AS

SELECT * FROM SchemaUserTable.Vendor WHERE state = @state

GO

-- Grant permissions on the stored procedure

GRANT

GO

-- *** Ready to test execution context ***

-- Now try and access the proc as RealUser

EXECUTE

AS user = 'RealUser'

EXEC

SchemaUserProc.VendorAccessProc 'AK'

-- The permission is denied on the underlying table.

-- But do not want to have to grant permissions to all callers on the underlying table.

-- Instead have the proc run as UserTable, which has SELECT permissions on the table,

-- since that user owns the schema it is in.

REVERT

-- Alter the procedure with UserTable as the execution context

-- ALTER preserves the permissions on the object

ALTER

PROC SchemaUserProc.VendorAccessProc @state char(2)

WITH

EXECUTE AS 'UserTable'

AS

SELECT * FROM SchemaUserTable.Vendor WHERE state = @state

GO

-- Now try and execute the proc as RealUser

EXECUTE

AS user = 'RealUser'

EXEC

SchemaUserProc.VendorAccessProc 'AK'

REVERT

-- Clean up

USE

GO

DROP

DROP

DROP

DROP

 

 

 

/*** Metadata Security

**********************/

USE

CREATE

LOGIN User1 WITH password = 'mC%929N*!LkDvuJ'

-- Use the database of your choice

USE

CREATE

EXECUTE

AS LOGIN = 'User1'

SELECT

-- Because the user has no permissions in the database, no rows are returned

* FROM sys.objects

REVERT

-- Give User1 rights to a table and stored procedure

GRANT

GRANT

-- Execute again as User1

EXECUTE

AS LOGIN = 'User1'

SELECT

 -- Attempt to drop a table in the database

-- Throws an error that doesn't confirm the existence of the table

* FROM sys.objects

DROP

REVERT

-- Clean up

DROP

GO

USE

DROP

LOGIN User1
master
USER User1
TABLE Production.Product
EXECUTE ON dbo.uspGetBillOfMaterials TO User1
SELECT ON Person.Contact TO User1
USER User1
AdventureWorks
master
DATABASE ExecuteContextDB
LOGIN RealUser
LOGIN UserTable
LOGIN UserProc
master
EXECUTE ON SchemaUserProc.VendorAccessProc TO RealUser
SCHEMA SchemaUserTable AUTHORIZATION UserTable
SCHEMA SchemaUserProc AUTHORIZATION UserProc
USER RealUser
USER UserTable
USER UserProc
ExecuteContextDB
DATABASE ExecuteContextDB
master
sp_helpsrvrolemember securityadmin
sp_helpsrvrole securityadmin
LOGIN Topaz WITH PASSWORD = 'Bo3EXNWJ#N6ndg5' UNLOCK

 

-- Unlock after too many unsuccessful login attempts

master
USER TopazD FOR LOGIN Topaz
USER Topaz
USER Topaz FOR LOGIN Topaz
AdventureWorks
USER Jane
USER Jane FOR LOGIN [Home\Mhn002AppDev]
USER [Home\Mhn002AppDev]
USER [Home\Mhn002AppDev] FOR LOGIN [Home\Mhn002AppDev]
AdventureWorks
Encryption.sql in SQL Server 2005

 

Set up sample encryption database

USE

-- Set up three logins

CREATE

LOGIN User1 WITH password = '3f@$fWDY3QvP&K0'

GO

CREATE

GO

USE

CREATE

CREATE

TABLE Customer (

CustId int,

Name nvarchar(30),

City varchar(20),

CreditCardType varbinary(1000),

CreditCardNumber varbinary(1000),

Notes varbinary(4000))

GO

-- Grant access to user

GRANT

-- **************************************************************************

-- DATABASE MASTER KEY

-- **************************************************************************

USE

-- Databases do not have a master key by default, so you must create it

-- before you can use it:

CREATE

MASTER KEY ENCRYPTION BY PASSWORD = 'gK#3hbQKDFQY0oF'

-- Create an asymmetric key to protect the new symmetric key

CREATE

AUTHORIZATION User1

WITH ALGORITHM = RSA_2048

-- **************************************************************************

-- SYMMETRIC KEYS

-- **************************************************************************

CREATE

WITH ALGORITHM = RC4

ENCRYPTION BY ASYMMETRIC KEY User1AsymmetricKey

-- List the symmetric keys in the database

SELECT

-- Insert data, using various asymmetric keys. If the symmetric key isn't

-- open, no error and no data inserted.

* FROM sys.symmetric_keys

OPEN

DECRYPTION BY ASYMMETRIC KEY User1AsymmetricKey

INSERT

INTO Customer VALUES (1, 'Sally Roe', 'Chatinika',

EncryptByKey(Key_GUID('User1SymmetricKey'), 'Visa'),

EncryptByKey(Key_GUID('User1SymmetricKey'), '1234-5678-9009-8765'),

EncryptByKey(Key_GUID('User1SymmetricKey'),

'One of our best customers. Treat like royalty.'))

CLOSE

-- View the new data entered using symmetric keys.

SELECT

-- View the data. Note that you don't have to specify which symmectric key

-- to use to decrypt data, even though multiple symmetric keys can be open.

OPEN

DECRYPTION BY ASYMMETRIC KEY User1AsymmetricKey

SELECT

CustID, Name, City,

CONVERT(VARCHAR, DecryptByKey(CreditCardType)) AS CardType,

CONVERT(VARCHAR, DecryptByKey(CreditCardNumber)) AS CardNumber,

CONVERT(VARCHAR, DecryptByKey(Notes)) AS Notes

FROM

CLOSE

-- **************************************************************************

-- Encryption Catalog Views

-- **************************************************************************

-- Existing keys

SELECT

* FROM sys.certificates

SELECT

* FROM sys.asymmetric_keys

SELECT

* FROM sys.symmetric_keys

SELECT

* FROM sys.database_principals

SELECT

* FROM sys.key_encryptions

SELECT

-- Information about keys

-- "Returns a row for each symmetric key encryption specified using the

-- ENCRYPTION BY clause of the CREATE SYMMETRIC KEY statement."

* FROM sys.crypt_properties

SELECT

-- "Returns one row for each cryptographic property associated with a securable"

-- None in this database

* FROM sys.key_encryptions

SELECT

-- **************************************************************************

-- Clean Up Samples

-- **************************************************************************

* FROM sys.crypt_properties

USE

GO

DROP

DROP

LOGIN User1
DATABASE EncryptionDB
master
SYMMETRIC KEY User1SymmetricKey
Customer

SYMMETRIC KEY User1SymmetricKey
* FROM Customer
SYMMETRIC KEY User1SymmetricKey
SYMMETRIC KEY User1SymmetricKey
SYMMETRIC KEY User1SymmetricKey
ASYMMETRIC KEY User1AsymmetricKey
EncryptionDB
SELECT,INSERT on Customer to User1
USER User1 FOR LOGIN User1 EncryptionDB DATABASE EncryptionDB master
Transaction.sql in SQL Server 2005

 

 

 

 

USE

Northwind;

GO

-- Execute these statements in Connection1:

BEGIN

TRAN

UPDATE dbo.Categories

SET CategoryName = 'Drinks'

WHERE CategoryID = 1;

-- Open a new connection and execute this statement

SELECT

CategoryName from dbo.Categories WHERE CategoryID = 1;

-- Create a table to demonstrate compile errors

CREATE

(ID INT PRIMARY KEY,

ColValue CHAR(4));

GO

-- Create the batch

INSERT

INTO dbo.CompileErrors VALUES (1, 'aaaa');

INSERT

INTO dbo.CompileErrors VALUES (2, 'bbbb');

INSERT

INTO dbo.CompileErrors VALUSE (3, 'cccc');

GO

SELECT

* FROM CompileErrors;

GO

INSERT

INTO dbo.CompileErrors VALUES (1, 'aaaa');

GO

INSERT

INTO dbo.CompileErrors VALUES (2, 'bbbb');

GO

INSERT

INTO dbo.CompileErrors VALUSE (3, 'cccc');

GO

-- Insert new rows with PK violation

INSERT

INTO dbo.CompileErrors VALUES (11, 'aaaa');

INSERT

INTO dbo.CompileErrors VALUES (12, 'bbbb');

INSERT

INTO dbo.CompileErrors VALUES (11, 'cccc');

GO

-- Insert new rows with a non-existent table name

INSERT

INTO dbo.CompileErrors VALUES (111, 'aaaa');

INSERT

INTO dbo.CompileErrors VALUES (112, 'bbbb');

INSERT

INTO dbo.CompileErrrs VALUES (113, 'cccc');

GO

-- DROP TABLE CompileErrors;

-- Use @@TRANCOUNT

BEGIN

TRANSACTION;

UPDATE dbo.Employees

SET LastName = 'Da Volio'

WHERE LastName = 'Davolio';

IF @@TRANCOUNT > 0

BEGIN

PRINT N'The transaction is active.';

ROLLBACK TRANSACTION;

PRINT N'The transaction has been rolled back.';

END

GO

SELECT

LastName FROM dbo.Employees;

-- Use @@ERROR

SELECT

message_id, text from sys.messages;

-- Simple error handling

DECLARE

BEGIN

@err int TRANSACTION;

INSERT INTO dbo.Customers (CustomerID, CompanyName)

VALUES ('ALFKI', 'New ALFKI');

SET @Err = @@ERROR

IF @Err = 0

BEGIN

PRINT 'Commit transaction.';

COMMIT

END

ELSE

BEGIN

PRINT 'Error = ' + CAST(@Err AS varchar(10));

ROLLBACK

END

GO

-- Transactions in Stored Procedures

-- Traditional error handling with @@ERROR

CREATE

@CategoryName nvarchar(15) = NULL,

@CategoryID int = NULL OUTPUT,

@ReturnCode int = NULL OUTPUT,

@ReturnMessage nvarchar(255) = NULL OUTPUT

AS

SET

NOCOUNT ON

-- Declare some working variables

DECLARE @Err int;

DECLARE @Rows int;

DECLARE @identity int;

 

IF @CategoryName IS NULL

BEGIN

SELECT @ReturnCode = 515,

@ReturnMessage = 'Null CategoryName not allowed.'

RETURN

END

 

SELECT

@ReturnCode AS ReturnCode,

@ReturnMessage AS ReturnMessage;

GO

-- Using RAISERROR

IF

WHERE CategoryName='Seafood')

BEGIN

RAISERROR ('Duplicate CategoryName detected.', 16, 1);

END

GO

-- Creating a user-defined error.

EXECUTE

N'Session ID %d caused an error in %s.';

GO

-- Raise the custom error:

DECLARE

@spid INT;

SET

@spid = @@SPID;

DECLARE

@name NVARCHAR(128);

SET

@name = DB_NAME();

RAISERROR

(50003, 10, 1, @spid, @name)

GO

--EXECUTE sp_dropmessage 50003;

-- TRY/CATCH

BEGIN

TRY

BEGIN TRANSACTION;

INSERT INTO dbo.Customers (CustomerID, CompanyName)

VALUES ('ALFKI', 'New ALFKI');

COMMIT

PRINT 'Transaction committed.'; TRY CATCH

 

ROLLBACK

PRINT 'Transaction rolled back.'; CATCH

 

GO

-- Display detailed error information

BEGIN

TRY

BEGIN TRANSACTION;

INSERT INTO dbo.Customers (CustomerID, CompanyName)

VALUES ('ALFKI', 'New ALFKI');

COMMIT

PRINT 'Transaction committed.'; TRY CATCH

 

ROLLBACK

SELECT

ERROR_NUMBER() AS Number,

ERROR_SEVERITY() AS Severity,

ERROR_STATE() AS State,

ERROR_PROCEDURE() AS procedureName,

ERROR_LINE() AS Line,

ERROR_MESSAGE() AS messageText;

PRINT 'Transaction rolled back.'; CATCH

 

GO

-- Use RAISERROR in a TRY/CATCH

BEGIN

TRY

RAISERROR ('Error severity 9', 9, 1);

RAISERROR ('Error severity 16', 16, 1); TRY CATCH

 

DECLARE @ErrorMessage NVARCHAR(4000);

DECLARE @ErrorSeverity INT;

SELECT

@ErrorMessage = ('In CATCH block: ' + ERROR_MESSAGE()),

@ErrorSeverity = ERROR_SEVERITY();

RAISERROR (@ErrorMessage,

@ErrorSeverity, 1); CATCH;

 

GO

-- Create a stored procedure using TRY/CATCH

-- and RAISERROR

CREATE

@CategoryName nvarchar(15) = NULL,

@CategoryID int = NULL OUTPUT,

@ReturnCode int = NULL OUTPUT,

@ReturnMessage nvarchar(255) = NULL OUTPUT

AS

SET

BEGIN

NOCOUNT ON TRY

-- Test if CategoryName null.

IF @CategoryName IS NULL

RAISERROR ('Validation failed: Null CategoryName.', 16, 1);

-- Test if CategoryName already exists.

IF EXISTS (SELECT CategoryName FROM dbo.Categories

WHERE CategoryName=@CategoryName)

RAISERROR ('Validation failed: Duplicate CategoryName.', 16, 1);

-- Begin the transaction.

BEGIN TRANSACTION

INSERT INTO dbo.Categories (CategoryName)

VALUES (@CategoryName);

COMMIT

SET @CategoryID=SCOPE_IDENTITY();

SELECT @ReturnCode=0,

@ReturnMessage='Success! ' + @CategoryName + ' added.'; TRY CATCH

 

-- Test to see if we're in a transaction.

IF @@TRANCOUNT > 0

ROLLBACK

-- Return error information to client.

SELECT @ReturnCode = ERROR_NUMBER();

SELECT @ReturnMessage = ERROR_MESSAGE() +

' Severity=' + CAST(ERROR_SEVERITY() AS nvarchar(2)) +

'; State=' + CAST(ERROR_STATE() AS nvarchar(2)) +

'; Proc=' + CAST(ERROR_PROCEDURE() AS nvarchar(50)) +

'; Line=' + CAST(ERROR_LINE() AS nvarchar(10)); CATCH

 

GO

-- Execute the Stored Procedure

DECLARE

@CategoryName nvarchar(15)

DECLARE

DECLARE

DECLARE

@CategoryID int @ReturnCode int @ReturnMessage nvarchar(255)

SET

@CategoryName = 'Seafood'

EXECUTE

@CategoryName,

@CategoryID OUTPUT,

@ReturnCode OUTPUT,

@ReturnMessage OUTPUT;

 

END

IF

WHERE CategoryName=@CategoryName)

BEGIN

SELECT @ReturnCode = 2601,

@ReturnMessage = 'Name already exists.'

RETURN

END TRANSACTION

 

 

INSERT INTO dbo.Categories (CategoryName)

VALUES (@CategoryName);

-- Pick up @@ERROR and @@ROWCOUNT

SELECT @Err = @@ERROR, @Rows = @@ROWCOUNT

-- If there's an error, rollback.

IF @Err <> 0

BEGIN

SELECT @ReturnCode=@Err,

@ReturnMessage= 'Transaction rolled back.'

ROLLBACK

RETURN

END

-- If no rows inserted, rollback.

IF @Rows = 0

BEGIN

SELECT @ReturnCode=2601,

@ReturnMessage='Insert failed.'

ROLLBACK

RETURN

END

-- Success! Commit the transaction.

ELSE

BEGIN

COMMIT

SET @identity=SCOPE_IDENTITY();

SELECT @ReturnCode=0, @CategoryID=@identity,

@ReturnMessage='Transaction succeeded, row added.'

RETURN

END

GO

-- Execute the Stored Procedure

DECLARE

@CategoryName nvarchar(15)

DECLARE

DECLARE

DECLARE

@CategoryID int @ReturnCode int @ReturnMessage nvarchar(255)

SET

@CategoryName = 'Seafood1'

EXECUTE

@CategoryName,

@CategoryID OUTPUT,

@ReturnCode OUTPUT,

@ReturnMessage OUTPUT;

 

BEGIN

 

SELECT

@ReturnCode AS ReturnCode,

@ReturnMessage AS ReturnMessage;

GO

-- Use XACT_STATE

SET

XACT_ABORT ON;

BEGIN

TRY

BEGIN TRANSACTION;

-- Generate a constraint violation error.

DELETE FROM dbo.Categories WHERE CategoryID=1;

COMMIT TRANSACTION;

PRINT 'Transaction Committed.' TRY CATCH

 

IF (XACT_STATE()) = -1

BEGIN

DECLARE @category nvarchar(50)

SELECT @Category =

(SELECT CategoryName FROM dbo.Categories WHERE CategoryID=1)

ROLLBACK

PRINT 'The ' + @category + ' category cannot be deleted.';

END CATCH

GO

--CLEANUP

DROP

DROP

PROC dbo.InsertCategoryTransaction;

DROP

PROC dbo.InsertCategoryTryCatch;

EXECUTE

sp_dropmessage 50003;
TABLE dbo.CompileErrors;

END

BEGIN

END

END

BEGIN

END

END

BEGIN

END

END

BEGIN

END

END

BEGIN

-- Perform the transaction

 

-- Exit if CategoryName already exists.

-- Exit if CategoryName is null.

 

@CategoryID AS CategoryId, dbo.InsertCategoryTryCatch PROCEDURE dbo.InsertCategoryTryCatch sp_addmessage 50003, 16, EXISTS (SELECT CategoryName FROM dbo.Categories @CategoryID AS CategoryId, dbo.InsertCategoryTransaction EXISTS (SELECT CategoryName FROM dbo.Categories PROCEDURE dbo.InsertCategoryTransaction TABLE dbo.CompileErrors

-- Don't execute this yet!!

ROLLBACK

Functions.sql in SQL Server 2005

 

 

USE

Northwind;

--------------------------------------------

-- Scalar Functions

--------------------------------------------

CREATE

RETURNS int

BEGIN

DECLARE @Total AS int;

SELECT @Total = SUM(Quantity)

FROM dbo.[Order Details];

RETURN @Total;

END

GO

SELECT

dbo.fnProductsSold();

GO

SELECT

dbo.fnProductsSold() AS TotalSold

FROM

 

Products;

-- Scalar function with parameter

CREATE

(@ProductID int = null)

RETURNS int

WITH RETURNS NULL ON NULL INPUT

AS

BEGIN

DECLARE @total int;

SELECT @Total = SUM(Quantity)

FROM dbo.[Order Details]

WHERE ProductID = @ProductID;

RETURN @Total;

END

GO

SELECT

dbo.fnProductsSoldByProduct(NULL);

SELECT

dbo.fnProductsSoldByProduct(DEFAULT);

SELECT

dbo.fnProductsSoldByProduct(3);

GO

--------------------------------------------

-- Inline Table Valued Functions

--------------------------------------------

CREATE

RETURNS

AS

RETURN

SELECT

dbo.fnProductsSold() AS UnitsSold,

SUM(UnitPrice * Quantity) AS TotalSales,

AVG(UnitPrice) AS AveragePrice,

COUNT(*) AS LineItems

FROM dbo.[Order Details];

-- returns an error

SELECT

dbo.fnProductSelectStatistics();

-- correct calling syntax

SELECT

* FROM dbo.fnProductStatistics();

SELECT

FROM

dbo.fnProductStatistics();

-- Inline function with parameter

CREATE

(@ProductID int = NULL)

RETURNS

AS

RETURN

SELECT

dbo.fnProductsSoldByProduct(@ProductID)

AS UnitsSold,

SUM(UnitPrice * Quantity) AS TotalSales,

COUNT(*) AS LineItems

FROM dbo.[Order Details]

WHERE ProductID = @ProductID;

-- execute the function

SELECT

FROM fnStatisticsByProduct(4);

SELECT

* FROM dbo.fnStatisticsByProduct(DEFAULT);

SELECT

* FROM dbo.fnStatisticsByProduct(NULL);

-- Update from inline function

CREATE

(@ProductID int)

RETURNS

AS

RETURN

SELECT ProductID, ProductName, UnitPrice, UnitsInStock

FROM dbo.Products

WHERE ProductID = @ProductID

AND Discontinued = 0;

-- Execute as SELECT

SELECT

* FROM dbo.fnProductByID(3);

-- Update

UPDATE

dbo.fnProductByID(3)

SET

UnitsInStock = 63;

-- Display modified data

SELECT

FROM

dbo.fnProductByID(3);

--------------------------------------------

-- Multi-Statement Table Valued Functions

--------------------------------------------

-- get orders by employee or country

CREATE

(

@EmployeeID int = NULL,

@ShipCountry nvarchar(15) = NULL

RETURNS

(

ShipCountry nvarchar(15) NOT NULL,

CustomerID nchar(5) NOT NULL,

OrderID int NOT NULL,

EmployeeID int NOT NULL

AS

BEGIN

-- If all inputs null, return all rows.

-- Sort by ShipCountry, CustomerID, OrderID, EmployeeID

IF @EmployeeID IS NULL AND @ShipCountry IS NULL

INSERT @Order

SELECT ShipCountry, CustomerID, OrderID, EmployeeID

FROM dbo.Orders

ORDER BY ShipCountry, CustomerID, OrderID, EmployeeID;

ELSE IF @EmployeeID IS NULL AND @ShipCountry IS NOT NULL

-- Filter by ShipCountry.

-- Sort by EmployeeID, CustomerID, OrderID

INSERT @Order

SELECT ShipCountry, CustomerID, OrderID, EmployeeID

FROM dbo.Orders

WHERE ShipCountry=@ShipCountry

ORDER BY EmployeeID, CustomerID, OrderID;

ELSE IF @EmployeeID IS NOT NULL AND @ShipCountry IS NULL

-- Filter by EmployeeID.

-- Sort by ShipCountry, CustomerID, OrderID

INSERT @Order

SELECT ShipCountry, CustomerID, OrderID, EmployeeID

FROM dbo.Orders

WHERE EmployeeID=@EmployeeID

ORDER BY ShipCountry, CustomerID, OrderID;

ELSE IF @EmployeeID IS NOT NULL AND @ShipCountry IS NOT NULL

-- Filter by ShipCountry and EmployeeID.

-- Sort by ShipCountry, CustomerID, OrderID, EmployeeID

INSERT @Order

SELECT ShipCountry, CustomerID, OrderID, EmployeeID

FROM dbo.Orders

WHERE ShipCountry=@ShipCountry AND EmployeeID=@EmployeeID

ORDER BY ShipCountry, CustomerID, OrderID, EmployeeID;

RETURN

END

;

GO

-- Execute the function

DECLARE

@EmployeeID nchar(5);

DECLARE

@ShipCountry nvarchar(15)

SET

@EmployeeID = NULL

SET

@ShipCountry = NULL

SELECT

FROM

dbo.fnOrdersByEmplyee_Country(@EmployeeID, @ShipCountry)

GO

-- Filter on employee

SELECT

FROM

dbo.fnOrdersByEmplyee_Country(6, NULL);

GO

-- Rearrange column and sort orders

SELECT

FROM

dbo.fnOrdersByEmplyee_Country(NULL, 'Spain')

ORDER

BY CustomerID, EmployeeID, OrderID;

GO

-- List distinct countries

SELECT

FROM

dbo.fnOrdersByEmplyee_Country(6, NULL);

GO

-- Joining functions to tables

SELECT

FROM

INNER

ON

O.EmployeeID = E.EmployeeID

ORDER

BY E.LastName;

---------------------------------------------------

-- Using Functions

---------------------------------------------------

-- Create a scalar function to calculate a discount

CREATE

(

@price money,

@discount int

)

RETURNS money

WITH RETURNS NULL ON NULL INPUT

AS

BEGIN

DECLARE @work money

SELECT @work = @price - (@price * (@discount * .01))

RETURN @work

END

 

;

-- Execute the function against the Products table

SELECT

dbo.fnCalcDiscountPrice(UnitPrice,5) AS [5% Off],

dbo.fnCalcDiscountPrice(UnitPrice,3) AS [3% Off]

FROM

ORDER

 

BY UnitPrice DESC;

-- Using Table-Valued Functions in a subquery

-- Compute order total

IF

Object_id('dbo.fnOrderTotal') IS NOT NULL

DROP FUNCTION dbo.fnOrderTotal;

GO

CREATE

FUNCTION dbo.fnOrderTotal()

RETURNS

AS

RETURN SELECT

OrderID, SUM(UnitPrice*Quantity) AS Total

FROM dbo.[Order Details]

GROUP BY OrderID

GO

-- Using functions in subqueries

SELECT

FROM

INNER

ON

WHERE

T.Total >

(SELECT AVG(Total) FROM dbo.fnOrderTotal())

ORDER

BY CustomerID, Total DESC;

-- Cleanup

IF

Object_id('dbo.fnProductsSold') IS NOT NULL

DROP FUNCTION dbo.fnProductsSold;

IF

Object_id('dbo.fnProductsSoldByProduct') IS NOT NULL

DROP FUNCTION dbo.fnProductsSoldByProduct;

IF

Object_id('dbo.fnProductStatistics') IS NOT NULL

DROP FUNCTION dbo.fnProductStatistics;

IF

Object_id('dbo.fnStatisticsByProduct') IS NOT NULL

DROP FUNCTION dbo.fnStatisticsByProduct;

IF

Object_id('dbo.fnProductByID') IS NOT NULL

DROP FUNCTION dbo.fnProductByID;

IF

OBJECT_ID (N'dbo.fnOrdersByEmplyee_Country') IS NOT NULL

DROP FUNCTION dbo.fnOrdersByEmplyee_Country;

IF

Object_id('dbo.fnCalcDiscountPrice') IS NOT NULL

DROP FUNCTION dbo.fnCalcDiscountPrice;

IF

Object_id('dbo.fnOrderTotal') IS NOT NULL

DROP FUNCTION dbo.fnOrderTotal;

O.OrderID = T.OrderID
JOIN dbo.fnOrderTotal() AS T
dbo.fnOrdersByEmplyee_Country(NULL, 'USA') AS O
O.CustomerID, O.OrderID, T.Total
TABLE
dbo.Products
ProductID, ProductName, UnitPrice,
FUNCTION dbo.fnCalcDiscountPrice
JOIN dbo.Employees AS E dbo.fnOrdersByEmplyee_Country(NULL, 'Italy') AS O E.LastName, E.FirstName, O.CustomerID, O.OrderID DISTINCT ShipCountry CustomerID, EmployeeID, OrderID ShipCountry, CustomerID, OrderID ShipCountry, CustomerID, OrderID, EmployeeID

)

@Order