2. Project 01: Transact SQL
Objective
Write several simple to complex data retrieval queries that involve self joins, correlated sub queries, and parameter insertions.
Sample Scenarios and Queries
Query #1
The Available Books page is a report listing the publishers and the books they offer. Output a list of publishers, the books they
publish and each book’s ISBN. Ensure the output lists the Publishers in alphabetical order and the titles in alphabetical order.
--Very basic query
USE junglebooks
SELECT publisher, title, isbn
FROM books
ORDER BY publisher, title
GO
Query # 2
The Range of Customers form allows the user to view orders placed within a given range of customer IDs. The user enters 6 in the
txtIDStart form field and 15 in txtIDEnd form field. Display all columns of data in order by Customer ID. Alias the columns in the
result set as: ‘Order #’, ‘Cust ID’, ‘Ordered’.
--Query with parameters
USE junglebooks
DECLARE @txtIDStart int, @txtIDEnd int
SET @txtIDStart = 6
SET @txtIDEnd = 15
SELECT orderID AS Order#, customerID AS [Cust ID], OrderDate AS Ordered
FROM orders
WHERE customerID BETWEEN @txtIDStart AND @txtIDEnd
ORDER BY customerID
GO
Query #3
The Large Orders page is a report displaying the largest number of items sold per order. Display the Order ID, Customer ID and
Name along with the total number of items they ordered. Display the record with the largest quantity first. Alias as: “Order ID’, ‘Cust
ID’, ‘Customer’ and ‘# of items’.
--Query with JOINS
USE junglebooks
SELECT o.OrderID AS [Order ID], c.CustomerID AS [Cust ID], c.Name AS [Name},
SUM(quantityordered) AS [# of items]
FROM orders AS o JOIN customers AS c
ON o.customerID = c.customerID
JOIN orderitems AS oi
ON o.orderID = oi.orderID
GROUP BY o.orderID, c.customerID, c.Name
ORDER BY SUM(quantityordered) DESC
GO
Query #4
The Search For Authors page also allows the user to search for Authors with a last name starting with a particular letter. The user
inputs ‘B’ in the txtLastName form field. Display AuthorID and Name in order by name. Make the assumption that any compound
names are hyphenated (i.e.: Billy-Bob Hicks or Susan Smith-Anderson). Alias as: ‘ID’, ‘Name’.
--Query with parameters and wild card
USE junglebooks
DECLARE @txtLastName varchar(80)
SET @txtLastName = '% B%'
SELECT AuthorID AS ID, Name
FROM Authors
WHERE Name LIKE @txtLastName
ORDER BY Name
GO
3. Query #5
Write and execute a query that returns the member_no, full name, out_date, due_date, and title columns from the Loan, Member,
and Title tables. Convert the datetime values from the out_date and due_date columns to char(12), format 101. Restrict the results
to books which were due prior to the current date. Load the records into a temporary table called #overdue. Leave the query
window open after you create the temporary table.
--Query data to temporary table
USE library
SELECT m.member_no, (firstname + ' ' + middleinitial + '.' + ' ' + lastname) AS name,
CONVERT (char(12), l.out_date, 101) AS out_date,
CONVERT (char(12), l.due_date, 101) AS due_date , t.title
INTO #overdue
FROM member AS m JOIN loan AS l
ON m.member_no = l.member_no
JOIN title AS t
ON t.title_no = l.title_no
WHERE due_date < CURRENT_TIMESTAMP
GO
Query #6
Using joins and a UNION clause, write a query to retrieve a single list of members both adult and juvenile, who have reserved ISBN
number 288. The list must include the ISBN, title, member_no and name (i.e.: Smith, John) of each member who has the
reservation. Additionally, the list should indicate whether the member is an adult or a juvenile. Output the records by name.
--Query with UNION clause
USE library
SELECT (firstname + ' ' + middleinitial + '.' + ' ' + lastname) AS name , m.member_no, r.isbn, title,
'adult' AS [adult or juvenile]
FROM member AS m JOIN adult AS a
ON m.member_no = a.member_no
JOIN reservation AS r
ON a.member_no = r.member_no
JOIN item AS it
ON r.isbn = it.isbn
JOIN title AS t
ON t.title_no = it.title_no
WHERE r.isbn = 288
UNION
SELECT (firstname + ' ' + middleinitial + '.' + ' ' + lastname) AS name, m.member_no, r.isbn, title,
'juvenile' AS [adult or juvenile]
FROM member AS m JOIN juvenile AS j
ON m.member_no = j.member_no
JOIN reservation AS r
ON r.member_no = j.member_no
JOIN item AS it
ON r.isbn = it.isbn
JOIN title AS t
ON t.title_no = it.title_no
WHERE r.isbn = 288
ORDER BY name
GO
Query #7
Using CASE statement, write a query to retrieve a single list of members both adult and juvenile, who have reserved ISBN number
288. You cannot JOIN to the Adult or Juvenile tables. The list must include the ISBN, title, member_no and name (i.e.: Smith, John)
of each member who has the reservation. Additionally, the list should indicate whether the member is an adult or a juvenile. Output
the records by name.
--Query invloving a subquery
SELECT r.isbn AS Isbn, t.title AS Title
, m.member_no AS Member_no
, m.lastname + ', ' + m.firstname AS name
, Category = (CASE WHEN (SELECT a.member_no FROM dbo.adult AS a
WHERE a.member_no = m.member_no) = m.member_no
THEN 'adult'
ELSE
WHEN (SELECT j.member_no FROM dbo.juvenile AS j
WHERE j.member_no = m.member_no) = m.member_no
THEN 'juvenile' END)
FROM dbo.reservation AS r JOIN dbo.member AS m
ON r.member_no = m.member_no
JOIN dbo.item AS i
ON i.isbn = r.isbn
JOIN dbo.title AS t
ON t.title_no = i.title_no
WHERE r.isbn = 288
ORDER BY name
GO
4. Project 02: XML
Objective
Create XML queries involving FOR XML, and XQuery to retrieve order delivery details.
XML Query Samples
Sample 1:
Create two FOR XML queries to return the order manifest documents.
--Attribute-centric XML
USE Northwind
SELECT OrderID, OrderDate, CustomerID,
(SELECT ProductID, Quantity AS OrderQty
FROM [Order Details]
WHERE orders.orderID = [Order Details].orderID
FOR XML RAW ('Details'),TYPE)
FROM Orders
FOR XML RAW ('Order'), ROOT ('Orders')
--Mixture of element-centric and attribute-centric XML
USE Northwind
SELECT OrderID, OrderDate, CustomerID,
(SELECT ProductID, Quantity AS OrderQty
FROM [Order Details]
WHERE orders.orderID = [Order Details].orderID
FOR XML RAW ('Item'), ELEMENTS, TYPE)
FROM Orders
FOR XML RAW ('SalesOrder')
Sample 2:
We have a reporting application that the marketing analysts use to analyze product sales. This Application needs data in XML
Format where the parent node is the city and its children are the list of products with Product ID, UnitPrice sold, Discount provided,
and Quantity Sold. Create a FORXML Query to return this document. Include all product sales data available.
USE Northwind
SELECT ShipCity,
(SELECT ProductID, UnitPrice, Discount, Quantity
FROM [Order Details]
WHERE orders.orderID = [Order Details].orderID
FOR XML RAW ('Details'), TYPE)
FROM Orders
FOR XML RAW ('Sale')
Sample 3:
For each order that Northwind Traders receives, the goods are delivered by a delivery driver. These drivers are going to utilize
delivery lists that you are going to implement now. Using SSMS, create a dbo.DeliverySchedule table containing a Delivery ID,
Schedule date, Delivery Route, Delivery Driver, and Delivery List column.
Populate (“insert” via the starter script provided) the dbo.DeliverySchedule table with test data as follows:
• ScheduleDate is GetDate()
• DeliveryRoute is 3
• DeliveryDriver is James
• DeliveryList is the delivery list XML document (copy and paste from deliverylist.xml)
• DeliveryID can auto-increment via an identity property and does not need to be inserted.
Verify that this data has been stored in the dbo.DeliverySchedule table.
USE Northwind
GO
-- Drop Statement for when the table is already in the database
IF EXISTS(SELECT * FROM sys.tables
WHERE name='DeliverySchedule'
AND schema_id = (SELECT schema_id FROM sys.schemas WHERE name = 'dbo'))
BEGIN
DROP TABLE dbo.DeliverySchedule
END
--Create a table for delivery schedule
CREATE TABLE dbo.DeliverySchedule
(ScheduleID int IDENTITY PRIMARY KEY,
ScheduleDate Datetime,
DeliveryRoute int,
DeliveryDriver nvarchar(20),
DeliveryList xml)
--Insert XML
INSERT INTO DeliverySchedule
VALUES
(GetDate(), 3, 'James', '<?xml version="1.0" ?>
5. <DeliveryList>
<Delivery OrderID="10296">
<CustomerName>Carlos González</CustomerName>
<Address>Carrera 52 con Ave. Bolívar #65-98 Llano Largo
Barquisimeto Lara 3508 Venezuela</Address>
</Delivery>
<Delivery OrderID="10310">
<CustomerName>Liz Nixon</CustomerName>
<Address>89 Jefferson Way Suite 2 Portland </Address>
</Delivery>
</DeliveryList>')
--Insert Completed
SELECT * FROM dbo.DeliverySchedule
Sample 4:
Use XQuery expressions to retrieve and modify delivery schedule data
Tasks:
Retrieve the delivery elements
Retrieve the address for the first delivery
Find the driver for an order
Update a delivery address
Verify new delivery address
--Retrieve the delivery elements
USE Northwind
SELECT ScheduleID, ScheduleDate, DeliveryRoute, DeliveryDriver,
DeliveryList.query('/DeliveryList/Delivery')DeliveryList
FROM DeliverySchedule
--Retrieve the address for the first delivery
USE Northwind
SELECT DeliveryList.value('(/DeliveryList/Delivery/@Address)[1]', 'nvarchar(100)') [Delivery Address]
FROM DeliverySchedule
WHERE ScheduleID = 1
--Find the driver for an order
SELECT DeliveryDriver
FROM DeliverySchedule
WHERE DeliveryList.exist
('/DeliveryList/Delivery[@OrderID=10296]') = 1
--Find the driver for an order
UPDATE DeliverySchedule
SET DeliveryList.modify
('replace value of (/DeliveryList/Delivery/@Address)[1]
with "2000 Park Place, Portland"')
WHERE ScheduleID = 1
--Verify change delivery address
SELECT DeliveryList.value
('(/DeliveryList/Delivery/Address)[1]', 'nvarchar(100)')[Delivery Address]
FROM DeliverySchedule
WHERE ScheduleID = 1
6. Project 03: Stored Procedures
Objective
Create stored procedures to the support the following principal functions of a library’s day-to-day operations: adding new members
(adult and juvenile) and checking books in and out, adding new books, renewing memberships, changing a juvenile record into an
adult record after a customer has reached 18.
Requirements
• Design and develop back end stored procedures that satisfy these functionalities: Add Adult, Add Juvenile, Check In a book,
Check Out a book, Add Book, Renew Membership, Change Juvenile to Adult, Update Adult.
• Provide input validations (against null and whitespace values as outlined).
• Provide adequate error handling.
• Produce a build script and two test scripts that are intuitively designed to indicate to the grader that the intended functionality
works. These should require a minimum of effort to execute. The test scripts must test all required functionality: one should
hold all test cases intended to succeed and the second script should hold all the failures-> i.e.
Sample Stored Procedures
Add Adult Member
--Default values are set to NULL to allow execution despite missing inputs.
ALTER PROCEDURE [dbo].[sp_AddAdultMember]
@street varchar(15) = NULL
,@city varchar(15) = NULL
,@state char(2) = NULL
,@zip char(10) = NULL
,@phone_no char(13) = NULL
,@lastname varchar(15) = NULL
,@firstname varchar(15) = NULL
,@MemberID int = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;--Prevents extra result sets from interfering with SELECT statements.
--Verify that required params being passed are not NULL and do not contain spaces.
IF ((@firstname IS NULL OR @firstname = '')
OR (@lastname IS NULL OR @lastname = '')
OR (@street IS NULL OR @street = '')
OR (@city IS NULL OR @city = '')
OR (@state IS NULL OR @state = '')
OR (@zip IS NULL OR @zip = ''))
BEGIN
RAISERROR('Null values and whitespaces are prohibited. Please enter a valid integer.',16,1)
RETURN
END
--If validations met, insert values into member and adult table.
BEGIN TRY
BEGIN TRAN --Allows for execute all or rollback
INSERT [dbo].[member] ([lastname],[firstname])
VALUES (@lastname, @firstname)
Set @MemberID = SCOPE_IDENTITY()
INSERT [dbo].[adult]
([member_no],[street],[city],[state],[zip],[phone_no],[expr_date])
VALUES (@MemberID,@street,@city,@state,@zip,@phone_no,dateadd(year,1,getdate()))
COMMIT TRAN
END TRY
--If any error(s) take place during the transaction, errors will be raised and displayed like so:
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_NUMBER() ErrorNumber, ERROR_MESSAGE() Message
END CATCH
END
GO
7. Add Book
--Default values are set to NULL to allow execution despite missing inputs.
ALTER PROCEDURE [dbo].[sp_AddBook]
@title varchar(63) = NULL,
@author varchar(31) = NULL,
@synopsis text = NULL,
@isbn int = NULL,
@translation char(8) = NULL,
@cover char(8) = NULL,
@copy_no smallint = 1,
@title_no int = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON; --Prevents extra result sets from interfering with SELECT statements.
--Verify that required params being passed are not NULL and do not contain spaces.
IF ((@title IS NULL OR @title = '')
OR (@author IS NULL OR @author = '')
OR (@isbn IS NULL OR @isbn = '')
OR (@copy_no IS NULL OR @copy_no = ''))
BEGIN
RAISERROR('Null values and whitespaces prohibited. Please enter a valid integer.',16,1)
RETURN
END
ELSE
--If no NULL or blank spaces, check if @isbn book already exists and create new copy record.
IF EXISTS (SELECT isbn, title_no FROM item WHERE isbn = @isbn)
BEGIN TRY
BEGIN TRAN --Allows for execute all or rollback
--Declare @copyno so that the proc adds one to the highest existing copy number.
--Set @title_no to insert existing title_no into record.
DECLARE @copyno int
SET @copyno = (SELECT max(copy_no) FROM dbo.copy WHERE isbn = @isbn)
SET @title_no = (SELECT title_no FROM item WHERE isbn = @isbn)
INSERT INTO [library].[dbo].[copy] ([isbn], [copy_no], [title_no], [on_loan])
VALUES (@isbn, @copyno + 1, @title_no, 'N')
COMMIT TRAN
END TRY
--If any error(s) take place during the transaction, errors will be raised and displayed like so:
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_NUMBER() ErrorNumber, ERROR_MESSAGE() Message
END CATCH
ELSE
--If @isbn does not exist, create new a title record
BEGIN TRY
BEGIN TRAN
INSERT INTO [library].[dbo].[title] ([title],[author],[synopsis])
VALUES (@title, @author, @synopsis)
Set @title_no = SCOPE_IDENTITY()
--then a new item record
INSERT INTO [library].[dbo].[item] ([isbn], [title_no],[translation],
[cover],[loanable])
VALUES (@isbn, @title_no, @translation, @cover, 'Y')
--and lastly a new copy record
INSERT INTO [library].[dbo].[copy] ([isbn], [copy_no], [title_no], [on_loan])
VALUES (@isbn, @copy_no, @title_no, 'N')
COMMIT TRAN
END TRY
--If any error(s) take place during the transaction, errors will be raised and displayed like so:
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_NUMBER() ErrorNumber, ERROR_MESSAGE() Message
END CATCH
END
GO
8. Check Book Out
--Default values are set to NULL to allow execution despite missing inputs.
ALTER PROCEDURE [dbo].[sp_CheckOutBook]
@isbn int = NULL
,@copy_no smallint = NULL
,@member_no smallint = NULL
AS
BEGIN
SET NOCOUNT ON; --Prevents extra result sets from interfering with SELECT statements.
--Verify that required params being passed are not NULL and do not contain spaces.
IF ((@isbn IS NULL OR @isbn = '')
OR (@copy_no IS NULL OR @copy_no = '')
OR (@member_no IS NULL OR @member_no = ''))
BEGIN
RAISERROR('Null values and whitespaces prohibited. Please enter a valid integer.',16,1)
RETURN
END
--Verify that book exists.
IF NOT EXISTS (SELECT isbn, copy_no FROM copy where isbn = @isbn AND copy_no = @copy_no)
BEGIN
RAISERROR('Book does not exist. Please enter a valid isbn and copy_no.',16,1)
RETURN
END
--Verify that card is not expired.
IF (SELECT expr_date FROM adult WHERE member_no = @member_no) <= getdate()
BEGIN
RAISERROR('Member card expired or does not exist. Please renew.' ,16,1)
RETURN
END
--Verify that member has not reached their book limit.
IF (SELECT COUNT(member_no) FROM loan WHERE member_no = @member_no) > 4
BEGIN
RAISERROR('Cannot process request. Book check out limit met.',16,1)
RETURN
END
--Verify that book is loanable
IF (SELECT loanable FROM item WHERE isbn = @isbn) = 'N'
BEGIN
RAISERROR('Item is not loanable. Please make another selection',16,1)
RETURN
END
--Verify that book is not on loan
IF (SELECT on_loan FROM copy WHERE isbn = @isbn AND copy_no = @copy_no) = 'Y'
BEGIN
RAISERROR('Item is on loan. Please make another selection',16,1)
RETURN
END
--If validations met, insert param values into the loan table
BEGIN TRY
BEGIN TRAN --Allows for rollback in case of error
DECLARE @title_no int
SET @title_no = (SELECT title_no FROM item WHERE isbn = @isbn)
INSERT INTO [library].[dbo].[loan] ([isbn],[copy_no],[title_no],[member_no]
,[out_date],[due_date])
VALUES (@isbn, @copy_no, @title_no, @member_no, getdate(), dateadd(day,14,getdate()))
--then update the on_loan column in the copy table.
UPDATE [library].[dbo].[copy]
SET [on_loan] = 'Y'
WHERE isbn = @isbn AND copy_no = @copy_no
COMMIT TRAN
END TRY
--If any error(s) take place during the transaction, errors will be raised and displayed like so:
BEGIN CATCH
SELECT ERROR_NUMBER() ErrorNumber, ERROR_MESSAGE() Message
ROLLBACK TRAN
END CATCH
END
GO
9. Project 04: Building Bank database
Objective
Create stored procedures, views and triggers to support the day-to-day duties of Bank tellers. The tellers will need to search for
customers by phone, name, or account number. They will need to search for accounts by customer and account number. The
application should also be able to list all Checking accounts for a customer and list all Savings accounts for a customer. The
application should support all the actions like Deposit, Withdraw, Transfer funds, obtaining account history (of current month),
account history (of any month), etc.
Requirements
• Design and build a banking database based on given specifications
• Design and develop back end stored procedures that satisfy these functionalities: create account, deposit, withdraw, transfer
funds, close account, update account, and obtain account history.
• Provide input validations (against null and whitespace values as outlined).
• Provide adequate error handling.
• Prevent Drop and Alter to Schema (DDL Triggers) and prevent delete of Account and delete/updates of Transactions (DML
triggers)
• Produce a build script and two test scripts that are intuitively designed to indicate to the grader that the intended functionality
works. These should require a minimum of effort to execute. The test scripts must test all required functionality: one should
hold all test cases intended to succeed and the second script should hold all the failures.
Bank ERD diagram
10. Sample Stored Procedures
Create Account
CREATE PROCEDURE [dbo].[sp_CreateAccount]
@CustomerID int = NULL
,@AccountTypeID int = NULL
,@AccountStatusID int = NULL
,@OpeningBalance money = NULL
,@SavingsInterestRate decimal (18,2) = NULL
,@GeneralOverDraft bit = 0
,@GeneralOverDraftBalance money = NULL
,@OverDraftAccountID int = NULL
,@AccountID int = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;--Prevents extra result sets from interfering with SELECT statements.
--Verify that required params being passed are not NULL and do not contain spaces.
IF ((@CustomerID IS NULL OR @CustomerID = '')
OR (@AccountTypeID IS NULL OR @AccountTypeID = '')
OR (@OpeningBalance IS NULL OR @OpeningBalance = '')
OR (@AccountStatusID IS NULL OR @AccountStatusID = ''))
BEGIN
RAISERROR('Null values and whitespaces prohibited. Please enter a valid integer.',16,1)
RETURN
END
--Verify that the Customer exists.
IF NOT EXISTS (SELECT CustomerID FROM Customer where @CustomerID = CustomerID)
BEGIN
RAISERROR('CustomerID is invalid. Please enter a valid CustomerID.',16,1)
RETURN
END
--If validations met, insert values into table Account and CustomerAccount tables to create account.
BEGIN TRY
BEGIN TRAN --Allows for execute all or rollback
DECLARE @CurrentBalance money
SET @CurrentBalance = @OpeningBalance
INSERT INTO [PiggBank].[dbo].[Account] ([AccountTypeID],[AccountStatusID],
[DateOpened],[OpeningBalance], [CurrentBalance], [SavingsInterestRate],[GeneralOverDraft],
[GeneralOverDraftBalance],[OverDraftAccountID]
,[OverDraftDate])
VALUES (@AccountTypeID, @AccountStatusID, GETDATE(), @OpeningBalance,
@CurrentBalance,@SavingsInterestRate, @GeneralOverDraft,
@GeneralOverDraftBalance, @OverDraftAccountID, GETDATE())
Set @AccountID = SCOPE_IDENTITY()
INSERT INTO [PiggBank].[dbo].[CustomerAccount] ([AccountID], [CustomerID])
VALUES (@AccountID, @CustomerID)
COMMIT TRAN
END TRY
--If any error(s) take place during the transaction, errors will be raised and displayed like so:
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_NUMBER() ErrorNumber, ERROR_MESSAGE() Message
END CATCH
END
GO
11. Transfer funds
--Default values are set to NULL to allow execution despite missing inputs.
CREATE PROCEDURE [dbo].[sp_Transfer]
@CustomerID int = NULL
,@wAccountID int = NULL
,@dAccountID int = NULL
,@wTransactionTypeID int = NULL
,@dTransactionTypeID int = NULL
,@TransactionAmount money = NULL
,@Description ntext = NULL
,@TransactionID int = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;--Prevents extra result sets from interfering with SELECT statements.
--Verify that required params being passed are not NULL and do not contain spaces.
IF ((@CustomerID IS NULL OR @CustomerID = '')
OR (@wAccountID IS NULL OR @wAccountID = '')
OR (@dAccountID IS NULL OR @dAccountID = '')
OR (@wTransactionTypeID IS NULL OR @wTransactionTypeID = '')
OR (@dTransactionTypeID IS NULL OR @dTransactionTypeID = '')
OR (@TransactionAmount IS NULL OR @TransactionAmount = ''))
BEGIN
RAISERROR('Null values and whitespaces prohibited. Please enter a valid integer.',16,1)
RETURN
END
--Verify that the Customer is linked to the Account specified.
IF NOT EXISTS (SELECT CustomerID, AccountID FROM CustomerAccount WHERE @CustomerID = CustomerID AND
@wAccountID = AccountID OR @dAccountID = AccountID )
BEGIN
RAISERROR('CustomerID is not linked to the account. Please enter a valid AccountID.',16,1)
RETURN
END
--Verify that the Account is active.
IF (SELECT AccountStatusID FROM Account WHERE @wAccountID = AccountID OR @dAccountID = AccountID) = '2'
BEGIN
RAISERROR('AccountID is inactive. Please enter a valid AccountID or reactivate account.',16,1)
RETURN
END
--Verfiy that there is enough funding in overdraft account as well as the general overdraft account to
commit transaction.
IF @OverDraftAccount IS NOT NULL
AND @OverDraftBalance - @TransactionAmount < 0
AND @GeneralOverDraft = '1'
AND @GeneralOverDraftBalance - @TransactionAmount < -400
BEGIN
RAISERROR('Not enough funding in acccount to commit transaction.',16,1)
RETURN
END
--If validations met, insert values into table.
BEGIN TRY
BEGIN TRAN --Allows for execute all or rollback
DECLARE @wNewBalance money, @wOldBalance money
SET @wOldBalance = (SELECT CurrentBalance FROM Account WHERE @wAccountID =
AccountID)
SET @wNewBalance = (@wOldBalance - @TransactionAmount)
--First insert the withdraw/deposit into the Transaction table.
INSERT INTO [PiggBank].[dbo].[Transaction] ([AccountID],[TransactionTypeID],
[TransactionDate],[TransactionAmount],[OldBalance],[NewBalance],[Description])
VALUES (@wAccountID, @wTransactionTypeID, GETDATE(), @TransactionAmount,
@wOldBalance, @wNewBalance, @Description)
Set @TransactionID = SCOPE_IDENTITY()
--Then update the Account table with the new current balance.
UPDATE [PiggBank].[dbo].[Account]
SET [CurrentBalance] = @wNewBalance
WHERE @wAccountID = AccountID
--Now record the desposit into the transferring account.
DECLARE @dNewBalance money, @dOldBalance money
SET @dOldBalance = (SELECT CurrentBalance FROM Account WHERE @dAccountID =
AccountID)
SET @dNewBalance = (@dOldBalance + @TransactionAmount)
INSERT INTO [PiggBank].[dbo].[Transaction] ([AccountID],[TransactionTypeID],
[TransactionDate]
,[TransactionAmount],[OldBalance],[NewBalance],[Description])
VALUES (@dAccountID, @dTransactionTypeID, GETDATE(), @TransactionAmount,
@dOldBalance, @dNewBalance, @Description)
12. Set @TransactionID = SCOPE_IDENTITY()
--Finally, update the transferring account’s current balance with the set @dNewBalance value.
UPDATE [PiggBank].[dbo].[Account]
SET [CurrentBalance] = @dNewBalance
WHERE @dAccountID = AccountID
COMMIT TRAN
END TRY
--If any error(s) take place during the transaction, errors will be raised and displayed like so:
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_NUMBER() ErrorNumber, ERROR_MESSAGE() Message
END CATCH
END
GO
DML Trigger
CREATE TRIGGER [dbo].[PreventAccountDelete]
ON [dbo].[Account]
AFTER DELETE AS
--If the total rowcount of the item just deleted is = to zeroreturn to the transaction.
DECLARE @rowcount int
SET @rowcount = @@rowcount
IF @rowcount = 0
RETURN
--If the total rowcount of the item just deleted and the rows deleted from the transaction table is
--is not equal to the rowcount of the deleted account, prevent the delete then raise error.
IF (SELECT COUNT(*)
FROM [dbo].[Transaction] t, deleted d
WHERE t.AccountID = d.AccountID) <> @rowcount
BEGIN
RAISERROR 50001
'User cannot delete records from Account table'
ROLLBACK TRAN
RETURN
END
DDL Trigger
--DDL trigger safety will fire whenever a DROP TABLE or ALTER TABLE event occurs in the database, raising
an error and preventing altering/deletion of tables.
CREATE TRIGGER [Safety]
ON DATABASE
AFTER DROP_TABLE, ALTER_TABLE
AS
PRINT 'You must disable Trigger "safety" to drop or alter tables!'
ROLLBACK;
GO
.