You are on page 1of 34

ST, MARRY UNIVERSITY

DEPARTMENT OF COMPUTER SCIENCE


LAB MANUAL & EXERCISE, ADVANCED DATABASE
SAMPLE DDL & DML TO OPERATE BASIC & ADVANCED QUERY
MANIPULATIONs

************************************
Basic database manipulation
************************************

INSTRUCTION 1: BEFORE starting to manipulate please DOWNLOAD, UNCOMPRESS


and LOAD Sample Database from (https://www.sqlservertutorial.net/wp-content/uploads/SQL-
Server-SampleDatabase.zip)) FILEs TO YOUR DBMS. Or, download the file from your
telegram channel.

INSTRUCTION 2: CREATE DATABASE Naming BikeStores

 BikeStores Sample Database - create objects.sql – this file is for creating database objects
including schemas and tables.
 BikeStores Sample Database - load data.sql – this file is for inserting data into the tables

1|Page Prepared By: Kassahun T. ADBS


 BikeStores Sample Database - drop all objects.sql – this file is for removing the tables
and their schemas from the sample database. It is useful when you want to refresh the
sample database.

INSTRUCTION 3: Having the above information do the following operations


1. CREATE TABLE sales.promotions (
promotion_id INT PRIMARY KEY IDENTITY (1, 1), -- (seed, increment)
promotion_name VARCHAR (255) NOT NULL,
discount NUMERIC (3, 2) DEFAULT 0,
start_date DATE NOT NULL,
expired_date DATE NOT NULL
);
2. INSERT INTO sales.promotions (
promotion_name, discount, start_date, expired_date )
VALUES
( '2019 Summer Promotion', 0.15, '20190601', '20190901'),
( '2019 Fall Promotion', 0.20, '20191001', '20191101'),
( '2019 Winter Promotion', 0.25, '20191201', '20200101' );
3. SELECT * FROM sales.promotions; -- displays the result of above query
4. SELECT product_id, product_name, category_id, model_year, list_price
FROM production.products
WHERE category_id = 1
ORDER BY list_price DESC;
5. SELECT product_id, product_name, category_id, model_year, list_price
FROM production.products
WHERE category_id = 1 AND model_year = 2018
ORDER BY list_price DESC;
6. SELECT product_id, product_name, category_id, model_year, list_price FROM
production.products
WHERE list_price BETWEEN 1899.00 AND 1999.99
ORDER BY list_price DESC;
7. SELECT product_id, product_name, category_id, model_year, list_price
FROM production.products
WHERE product_name LIKE '%Cruiser%'
ORDER BY list_price DESC;
8. SELECT * FROM sales. orders;
UPDATE sales.orders
SET order_status= order_status +2
WHERE store_id=1;

2|Page Prepared By: Kassahun T. ADBS


9. SELECT customer_id, YEAR (order_date) order_year
FROM sales.orders
WHERE customer_id IN (1, 2)
GROUP BY customer_id, YEAR (order_date)
ORDER BY customer_id;

*********************
Next class
*********************
10. SELECT first_name + ' ' + last_name AS full_name
FROM sales.customers
ORDER BY first_name;
11. SELECT category_name 'Product Category'
FROM production.categories;
12. CREATE TABLE sales.quotations (
quotation_no INT IDENTITY PRIMARY KEY,
valid_from DATE NOT NULL,
valid_to DATE NOT NULL );
13. ALTER TABLE sales.quotations
ADD description VARCHAR (255) NOT NULL;
amount DECIMAL (10, 2) NOT NULL,
customer_name VARCHAR (50) NOT NULL;
 The above query adds description, amount and customer_name columns to the table
created in no 12.
 WE CAN ALSO DROP A COLUMN FROM THE ABOVE TABLE
14. ALTER TABLE sales.quotations
DROP COLUMN amount;
 WE CAN ALSO DROP MORE THAN 2 columns BY SEPARATING VIA
COMMAS
ALTER TABLE sales.quotations
DROP COLUMN amount, customer_name;
 We can delete some top of the row as below
15. DELETE TOP (21)
FROM sales.customers;
 We can also delete some percent (%) of the row as below
16. DELETE TOP (3) PERCENT
FROM sales.customers;
WHERE city=’buffalo’
 We can also delete all the rows as below

3|Page Prepared By: Kassahun T. ADBS


17. DELETE FROM sales.ccustomers;
 truncate is also possible instead of delete which is more efficient and fast if many
rows are in the table
18. SELECT customer_id, YEAR (order_date), COUNT (order_id)
order_count
FROM sales.orders
GROUP BY customer_id, YEAR (order_date)
HAVING COUNT (order_id) >= 2
ORDER BY customer_id;
19. DROP DATABASE IF EXISTS BikeStores;
 The IF EXISTS option is available from SQL Server 2016 (13.x) It allows you to
conditionally delete a database only if the database already exists. If you attempt to delete
a non-existing database without specifying the IF EXISTS option, SQL Server will issue
an error.
 Before deleting a database, you must ensure the following important points: First, the
DROP DATABASE statement deletes the database and also the physical disk files used
by the database. Therefore, you should have a backup of the database in case you want
to restore it in the future. Second, you cannot drop the database that is currently being
used. Cannot drop database "database_name" because it is currently in use. Trying to
drop a database currently being used causes the following error: Cannot drop database
"database_name" because it is currently in use.
20. DROP SCHEMA sales;
 The DROP SCHEMA statement allows you to delete a schema from a database. First,
specify the name of the schema that you want to drop. If the schema contains any objects,
the statement will fail. Therefore, you must delete all objects in the schema before
removing the schema. Second, use the IF EXISTS option to conditionally remove the
schema only if the schema exists. Attempting to drop a non-existing schema without the
IF EXISTS option will result in an error.
*********************
Next class
*********************

*****************************
Database constraints
*****************************
1. SQL Server PRIMARY KEY constraint
A primary key is a column or a group of columns that uniquely identifies each row in a table.
You create a primary key for a table by using the PRIMARY KEY constraint.

4|Page Prepared By: Kassahun T. ADBS


If the primary key consists of only one column, you can define use PRIMARY KEY constraint
as a column constraint:
CREATE TABLE sales.activities (
activity_id INT PRIMARY KEY IDENTITY,
activity_name VARCHAR (255) NOT NULL,
activity_date DATE NOT NULL
);
NB: The IDENTITY property is used for the activity_id column to automatically generate unique
integer values.
The following statement creates a new table named sales.participants whose primary key consists
of two columns:In this example, the values in either activity_id or customer_id column can be
duplicate, but each combination of values from both columns must be unique.
CREATE TABLE sales.participants(
activity_id int,
customer_id int,
PRIMARY KEY(activity_id, customer_id) );
If the primary key is not stated during table creation, we can update as follows:
CREATE TABLE sales.activities (
activity_id INT,
activity_name VARCHAR (255) NOT NULL,
activity_date DATE NOT NULL
);
ALTER TABLE sales.activities
ADD PRIMARY KEY(activity_id);
Note that if the sales.events table already has data, before promoting the event_id column as the
primary key, you must ensure that the values in the event_id are unique.

2. SQL Server foreign key constraint


CREATE TABLE procurement.vendor_groups (
group_id INT IDENTITY PRIMARY KEY,
group_name VARCHAR (100) NOT NULL
);
CREATE TABLE procurement.vendors (
vendor_id INT IDENTITY PRIMARY KEY,
vendor_name VARCHAR(100) NOT NULL,
group_id INT NOT NULL,
);

5|Page Prepared By: Kassahun T. ADBS


Each vendor belongs to a vendor group and each vendor group may have zero or more vendors.
The relationship between the vendor_groups and vendors tables is one-to-many.
For each row in the vendors table, you can always find a corresponding row in the vendor_groups
table.
However, with the current tables setup, you can insert a row into the vendors table without a
corresponding row in the vendor_groups table. Similarly, you can also delete a row in the
vendor_groups table without updating or deleting the corresponding rows in the vendors table that
results in orphaned rows in the vendors table.
To enforce the link between data in the vendor_groups and vendors tables, you need to establish a
foreign key in the vendors table.
A foreign key is a column or a group of columns in one table that uniquely identifies a row of
another table (or the same table in case of self-reference).
To create a foreign key, you use the FOREIGN KEY constraint.
The following statements drop the vendors table and recreate it with a FOREIGN KEY constraint:
DROP TABLE vendors; -- to create the table with its constraints
DROP TABLE vendors;
CREATE TABLE procurement.vendors (
vendor_id INT IDENTITY PRIMARY KEY,
vendor_name VARCHAR(100) NOT NULL,
group_id INT NOT NULL,
CONSTRAINT fk_group FOREIGN KEY (group_id)
REFERENCES procurement.vendor_groups(group_id)
);
The vendor_groups table now is called the parent table that is the table to which the foreign key
constraint references. The vendors table is called the child table that is the table to which the
foreign key constraint is applied. in the statement above, the following clause creates a FOREIGN
KEY constraint named fk_group that links the group_id in the vendors table to the group_id in the
vendor_groups table:
CONSTRAINT fk_group FOREIGN KEY (group_id)
REFERENCES procurement.vendor_groups(group_id)
The foreign key constraint ensures referential integrity. It means that you can only insert a row
into the child table if there is a corresponding row in the parent table.
Besides, the foreign key constraint allows you to define the referential actions when the row in the
parent table is updated or deleted as follows:

Delete actions of rows in the parent table

6|Page Prepared By: Kassahun T. ADBS


If you delete one or more rows in the parent table, you can set one of the following actions:
ON DELETE NO ACTION: SQL Server raises an error and rolls back the delete action on the
row in the parent table.
ON DELETE CASCADE: SQL Server deletes the rows in the child table that is corresponding
to the row deleted from the parent table.
ON DELETE SET NULL: SQL Server sets the rows in the child table to NULL if the
corresponding rows in the parent table are deleted. To execute this action, the foreign key columns
must be nullable.
ON DELETE SET DEFAULT: SQL Server sets the rows in the child table to their default values
if the corresponding rows in the parent table are deleted. To execute this action, the foreign key
columns must have default definitions. Note that a nullable column has a default value of NULL
if no default value specified
By default, SQL Server applies ON DELETE NO ACTION if you don’t explicitly specify any
action.

Update action of rows in the parent table


If you update one or more rows in the parent table, you can set one of the following actions:
ON UPDATE NO ACTION: SQL Server raises an error and rolls back the update action on the
row in the parent table.
ON UPDATE CASCADE: SQL Server updates the corresponding rows in the child table when
the rows in the parent table are updated.
ON UPDATE SET NULL: SQL Server sets the rows in the child table to NULL when the
corresponding row in the parent table is updated. Note that the foreign key columns must be
nullable for this action to execute.
ON UPDATE SET DEFAULT : SQL Server sets the default values for the rows in the child table
that have the corresponding rows in the parent table updated.

3. SQL Server UNIQUE Constraint


SQL Server UNIQUE constraints allow you to ensure that the data stored in a column, or a group
of columns, is unique among the rows in a table.
The following statement creates a table whose data in the email column is unique among the rows
in the hr.persons table:
In this syntax, you define the UNIQUE constraint as a column constraint. You can also define the
UNIQUE constraint as a table constraint, like this:

7|Page Prepared By: Kassahun T. ADBS


CREATE SCHEMA hr;
GO
CREATE TABLE hr.persons(
person_id INT IDENTITY PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE
);
In this syntax, you define the UNIQUE constraint as a column constraint. You can also define the
UNIQUE constraint as a table constraint, like this:
CREATE SCHEMA hr;
GO
CREATE TABLE hr.persons(
person_id INT IDENTITY PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE
);
CREATE TABLE hr.persons(
person_id INT IDENTITY PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email VARCHAR(255), UNIQUE(email)
);
Behind the scenes, SQL Server automatically creates a UNIQUE index to enforce the uniqueness
of data stored in the columns that participate in the UNIQUE constraint. Therefore, if you attempt
to insert a duplicate row, SQL Server rejects the change and returns an error message stating that
the UNIQUE constraint has been violated.
The following statement inserts a new row into the hr.persons table:
INSERT INTO hr.persons(first_name, last_name, email)
VALUES('John','Doe','j.doe@bike.stores');
The statement works as expected. However, the following statement fails due to the duplicate
email:
INSERT INTO hr.persons(first_name, last_name, email)
VALUES('Jane','Doe','j.doe@bike.stores');
SQL Server issued the following error message: Violation of UNIQUE KEY constraint
'UQ__persons__AB6E616417240E4E'. Cannot insert

8|Page Prepared By: Kassahun T. ADBS


If you don’t specify a separate name for the UNIQUE constraint, SQL Server will automatically
generate a name for it. In this example, the constraint name is
UQ__persons__AB6E616417240E4E, which is not quite readable.
To assign a particular name to a UNIQUE constraint, you use the CONSTRAINT keyword as
follows:
CREATE TABLE hr.persons (
person_id INT IDENTITY PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email VARCHAR(255),
CONSTRAINT unique_email UNIQUE(email)
);
The following are the benefits of assigning a UNIQUE constraint a specific name:
first, it easier to classify the error message. second, you can reference the constraint name when
you want to modify it.

Reading assignment: UNIQUE constraint vs. PRIMARY KEY constraint


*********************
Next class
*********************
4. SQL Server CHECK Constraint
The CHECK constraint allows you to specify the values in a column that must satisfy a Boolean
expression.
For example, to require positive unit prices, you can use:
CREATE SCHEMA test;
GO
CREATE TABLE test.products(
product_id INT IDENTITY PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,
unit_price DEC(10,2) CHECK(unit_price > 0)
);
You can also assign the constraint a separate name by using the CONSTRAINT keyword as
follows:
CREATE TABLE test.products(
product_id INT IDENTITY PRIMARY KEY,

9|Page Prepared By: Kassahun T. ADBS


product_name VARCHAR(255) NOT NULL,
unit_price DEC(10,2) CONSTRAINT positive_price CHECK(unit_price > 0) );
The explicit names help classify the error messages and allow you to refer to the constraints when
you want to modify them.
if you don’t specify a constraint name this way, SQL Server automatically generates a name for
you. See the following insert statement:
INSERT INTO test.products(product_name, unit_price)
VALUES ('Awesome Free Bike', 0);
SQL Server issued the following error: The INSERT statement conflicted with the CHECK constraint
"positive_price". The error occurred because the unit price is not greater than zero as specified in the
CHECK constraint.
the CHECK constraints reject values that cause the Boolean expression evaluates to FALSE.
Because NULL evaluates to UNKNOWN, it can be used in the expression to bypass a constraint.
For example, you can insert a product whose unit price is NULL as shown in the following query:
INSERT INTO test.products(product_name, unit_price)
VALUES ('Another Awesome Bike', NULL);
Then the sql results without error b/c it bypasses the CHECK constraint. SQL Server inserted
NULL into the unit_price column and did not return an error. To fix this, you need to use a NOT
NULL constraint for the unit_price column.

CHECK constraint referring to multiple columns


A CHECK constraint can refer to multiple columns. For instance, you store a regular and
discounted prices in the test.products table and you want to ensure that the discounted price is
always lower than the regular price:
CREATE TABLE test.products(
product_id INT IDENTITY PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,
unit_price DEC(10,2) CHECK(unit_price > 0),
discounted_price DEC(10,2) CHECK(discounted_price > 0),
CHECK(discounted_price < unit_price)
);
The first two constraints for unit_price and discounted_price should look familiar.
The third constraint uses a new syntax which is not attached to a particular column. Instead, it
appears as a separate line item in the comma-separated column list.
The first two column constraints are column constraints, whereas the third one is a table constraint.

10 | P a g e Prepared By: Kassahun T. ADBS


Note that you can write column constraints as table constraints. However, you cannot write table
constraints as column constraints. For example, you can rewrite the above statement as follows:
CREATE TABLE test.products(
product_id INT IDENTITY PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,
unit_price DEC(10,2),
discounted_price DEC(10,2),
CHECK(unit_price > 0),
CHECK(discounted_price > 0),
CHECK(discounted_price > unit_price)
);
Or even,
CREATE TABLE test.products(
product_id INT IDENTITY PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,
unit_price DEC(10,2),
discounted_price DEC(10,2),
CHECK(unit_price > 0),
CHECK(discounted_price > 0 AND discounted_price > unit_price)
);
You can also assign a name to a table constraint in the same way as a column constraint:
CREATE TABLE test.products(
product_id INT IDENTITY PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,
unit_price DEC(10,2),
discounted_price DEC(10,2),
CHECK(unit_price > 0),
CHECK(discounted_price > 0),
CONSTRAINT valid_prices CHECK(discounted_price > unit_price)
);

Add CHECK constraints to an existing table


To add a CHECK constraint to an existing table, you use the ALTER TABLE ADD
CONSTRAINT statement.
CREATE TABLE test.products(
product_id INT IDENTITY PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,

11 | P a g e Prepared By: Kassahun T. ADBS


unit_price DEC(10,2) NOT NULL
);
To add a CHECK constraint to the test.products table, you use the following statement:
ALTER TABLE test.products
ADD CONSTRAINT positive_price CHECK(unit_price > 0);
To add a new column with a CHECK constraint, you use the following statement:
ALTER TABLE test.products
ADD discounted_price DEC(10,2)
CHECK(discounted_price > 0);
To add a CHECK constraint named valid_price , you use the following statement:
ALTER TABLE test.products
ADD CONSTRAINT valid_price
CHECK(unit_price > discounted_price);

Remove CHECK constraints


To remove a CHECK constraint, you use the ALTER TABLE DROP CONSTRAINT statement:
The following statement drops the positive_price constraint:
ALTER TABLE test.products
DROP CONSTRAINT positive_price;

Disable CHECK constraints for insert or update


To disable a CHECK constraint for insert or update, you use the following statement:
The following statement disables the valid_price constraint:
ALTER TABLE test.products
NO CHECK CONSTRAINT valid_price;

5. SQL Server NOTNULL Constraint


The SQL Server NOT NULL constraints simply specify that a column must not assume the
NULL .
The following example creates a table (https://www.sqlservertutorial.net/sql-server-basics/sql-server-create-
table/)
with NOT NULL constraints for the columns: first_name , last_name , and email :

12 | P a g e Prepared By: Kassahun T. ADBS


CREATE SCHEMA hr;
GO
CREATE TABLE hr.persons(
person_id INT IDENTITY PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
phone VARCHAR(20)
);
Note that the NOT NULL constraints are always written as column constraints. By default, if you
don’t specify the NOT NULL constraint, SQL Server will allow the column to accepts NULL. In
this example, the phone column can accept NULL

Add NOT NULL constraint to an existing column


To add the NOT NULL constraint to an existing column, you follow these steps:
For example, to add the NOT NULL constraint to the phone column of the hr.persons table, you
use the following statements:
First, if a person does not have a phone number, then update the phone number to the company
phone number e.g., (408) 123 4567:
UPDATE hr.persons
SET phone = "(408) 123 4567"
WHER phone IS NULL;
Second, modify the property of the phone column:
ALTER TABLE hr.persons
ALTER COLUMN phone VARCHAR(20) NOT NULL;

Removing NOT NULL constraint


To remove the NOT NULL constraint from a column, you use the ALTER TABLE ALTER
COLUMN statement as follows:
ALTER TABLE hr.pesons
ALTER COLUMN phone VARCHAR(20) NULL;
*********************
Next class
*********************
*******************************
SQL Server Joins
*******************************

13 | P a g e Prepared By: Kassahun T. ADBS


Joins Allow you to combine data from two tables. In a relational database, data is distributed in
multiple logical tables. To get a complete meaningful set of data, you need to query data from
these tables by using joins. SQL Server supports many kinds of joins including inner join, left join,
right join, full outer join, and cross join. Each join type specifies how SQL Server uses data from
one table to select rows in another table.
Let`s see an example:
CREATE SCHEMA hr;
GO
CREATE TABLE hr.candidates(
id INT PRIMARY KEY IDENTITY,
fullname VARCHAR(100) NOT NULL
);
CREATE TABLE hr.employees(
id INT PRIMARY KEY IDENTITY,
fullname VARCHAR(100) NOT NULL
);
Third, insert some rows into the candidates and employees tables:
INSERT INTO hr.candidates(fullname)
VALUES
('John Doe'),
('Lily Bush'),
('Peter Drucker'),
('Jane Doe');
INSERT INTO hr.employees(fullname)
VALUES
('John Doe'),
('Jane Doe'),
('Michael Scott'),
('Jack Sparrow');
Having the above two tables, let`s apply the different types of joins
i. SQL Server Inner Join

14 | P a g e Prepared By: Kassahun T. ADBS


Inner join produces a data set that includes rows from the left
table which have matching rows from the right table.
The following example uses the inner join clause to get the rows from the candidates table that
have the corresponding rows with the same values in the fullname column of the employees
table:
SELECT
c.id candidate_id,
c.fullname candidate_name,
e.id employee_id,
e.fullname employee_name
FROM hr.candidates c
INNER JOIN hr.employees e
ON e.fullname = c.fullname;
ii. SQL Server Left Join

Left join selects data starting from the left table and matching rows in the right table. The left
join returns all rows from the left table and the matching rows from the right table. If a row in the
left table does not have a matching row in the right table, the columns of the right table will have
nulls.
The left join is also known as left outer join. The outer keyword is optional.
The following statement joins the candidates table with the employees table using left join:
SELECT
c.id candidate_id,
c.fullname candidate_name,
e.id employee_id,
e.fullname employee_name
FROM

15 | P a g e Prepared By: Kassahun T. ADBS


hr.candidates c
LEFT JOIN hr.employees e
ON e.fullname = c.fullname;
To get the rows that available only in the left table but not in the right table, you add a WHERE
clause to the above query:

SELECT
c.id candidate_id,
c.fullname candidate_name,
e.id employee_id,
e.fullname employee_name
FROM
hr.candidates c
LEFT JOIN hr.employees e
ON e.fullname = c.fullname
WHERE
e.id IS NULL;
iii. SQL Server Right Join
The right join or right outer join selects data starting from the right table. It is a reversed version
of the left join. The right join returns a result set that contains all rows from the right table and the
matching rows in the left table. If a row in the right table that does not have a matching row in the
left table, all columns in the left table will contain nulls.
The following example uses the right join to query rows from candidates and employees tables:
SELECT
c.id candidate_id,
c.fullname candidate_name,
e.id employee_id,
e.fullname employee_name
FROM
hr.candidates c
RIGHT JOIN hr.employees e
ON e.fullname = c.fullname;

16 | P a g e Prepared By: Kassahun T. ADBS


Notice that all rows from the right table (employees) are included in the result set.
Similarly, you can get rows that are available only in the right table by adding a WHERE clause
to the above query as follows:
SELECT
c.id candidate_id,
c.fullname candidate_name,
e.id employee_id,
e.fullname employee_name
FROM
hr.candidates c
RIGHT JOIN hr.employees e
ON e.fullname = c.fullname
WHERE
c.id IS NULL;
iv. SQL Server full join
The full outer join or full join returns a result set that contains all
rows from both left and right tables, with the matching rows from both sides where available. In
case there is no match, the missing side will have NULL values.
The following example shows how to perform a full join between the candidates and employees
tables:
SELECT
c.id candidate_id,
c.fullname candidate_name,
e.id employee_id,
e.fullname employee_name
FROM
hr.candidates c
FULL JOIN hr.employees e
ON e.fullname = c.fullname;
To select rows that exist either left or right table, you exclude rows that are common to both
tables by adding a WHERE clause as shown in the following query:
SELECT
c.id candidate_id,
c.fullname candidate_name,
e.id employee_id,
e.fullname employee_name

17 | P a g e Prepared By: Kassahun T. ADBS


FROM
hr.candidates c
FULL JOIN hr.employees e
ON e.fullname = c.fullname
WHERE
c.id IS NULL OR
e.id IS NULL;
*********************
Next class
*********************

************************************
SQL Server Views
************************************
A view is a named query stored in the database catalog that allows you to refer to it later.
When you use the SELECT statement to query data from one or more tables, you get a result set.
For example, the following statement returns the product name, brand, and list price of all products
from the products and brands tables:
SELECT
product_name,
brand_name,
list_price
FROM
production.products p
INNER JOIN production.brands b
ON b.brand_id = p.brand_id;
Next time, if you want to get the same result set, you can save this query into a text file, open it,
and execute it again.
SQL Server provides a better way to save this query in the database catalog through a view. A
view is a named query stored in the database catalog that allows you to refer to it later.
So the query above can be stored as a view using the CREATE VIEW statement as follows:
CREATE VIEW sales.product_info
AS
SELECT
product_name,
brand_name,
list_price

18 | P a g e Prepared By: Kassahun T. ADBS


FROM
production.products p
INNER JOIN production.brands b
ON b.brand_id = p.brand_id;
Later, you can reference to the view in the SELECT statement like a table as follows:
SELECT * FROM sales.product_info;
When receiving this query, SQL Server executes the following query:
SELECT
*
FROM (
SELECT
product_name,
brand_name,
list_price
FROM
production.products p
INNER JOIN production.brands b
ON b.brand_id = p.brand_id;
);
By definition, views do not store data except for indexed views.
A view may consist of columns from multiple tables using joins or just a subset of columns of a
single table. This makes views useful for abstracting or hiding complex queries.
The following picture illustrates a view that includes columns from multiple tables:

SQL Server List Views

19 | P a g e Prepared By: Kassahun T. ADBS


To list all views in a SQL Server Database, you query the sys.views or sys.objects catalog view.
Here is an example:
SELECT
OBJECT_SCHEMA_NAME(v.object_id) schema_name,
v.name
FROM
sys.views as v;
SQL Server DROP VIEW
DROP VIEW IF EXISTS sales.product_info;
Removing multiple views example
DROP VIEW IF EXISTS
sales.staff_sales,
sales.product_catalogs;

Advantages of views
Generally speaking, views provide the following advantages:
Security: You can restrict users to access directly to a table and allow them to access a subset of
data via views.
For example, you can allow users to access customer name, phone, email via a view but restrict
them to access the bank account and other sensitive information.
Simplicity: A relational database may have many tables with complex relationships e.g., one-to-
one and one-to-many that make it difficult to navigate. However, you can simplify the complex
queries with joins and conditions using a set of views.
Consistency: Sometimes, you need to write a complex formula or logic in every query. To make
it consistent, you can hide the complex queries logic and calculations in views.
Once views are defined, you can reference the logic from the views rather than rewriting it in
separate queries.
*********************
Next class
*********************
************************************
SQL Server Stored Procedures
************************************
i. Creating a simple stored procedure
The following SELECT statement returns a list of products from the products table in the
BikeStores sample database.

20 | P a g e Prepared By: Kassahun T. ADBS


SELECT
product_name,
list_price
FROM
production.products
ORDER BY
product_name;
To create a stored procedure that wraps this query, you use the CREATE PROCEDURE
statement as follows:
CREATE PROCEDURE uspProductList
AS
BEGIN
SELECT
product_name,
list_price
FROM
production.products
ORDER BY
product_name;
END;
In this syntax:
The uspProductList is the name of the stored procedure. The AS keyword separates the heading
and the body of the stored procedure.
If the stored procedure has one statement, the BEGIN and END keywords surrounding the
statement are optional. However, it is a good practice to include them to make the code clear.
Note that in addition to the CREATE PROCEDURE keywords, you can use the CREATE PROC
keywords to make the statement shorter.
To compile this stored procedure, you execute it as a normal SQL statement in SQL Server
Management Studio.
After successful execution, the stored procedure has been successfully compiled and saved into
the database catalog.
You can find the stored procedure in the Object Explorer, under Programmability > Stored
Procedures.

ii. Executing a stored procedure

21 | P a g e Prepared By: Kassahun T. ADBS


To execute a stored procedure, you use the EXECUTE or EXEC statement followed by the name
of the stored procedure:
EXEC uspProductList;

iii. Modifying a stored procedure


To modify an existing stored procedure, you use the ALTER PROCEDURE statement.
First, open the stored procedure to view its contents by right clicking the stored procedure name
and select Modify menu item:
Second, change the body of the stored procedure by sorting the products by list prices instead of
product names:
ALTER PROCEDURE uspProductList
AS
BEGIN
SELECT
product_name,
list_price
FROM
production.products
ORDER BY
list_price
END;
Third, click the Execute button, SQL Server modifies the stored procedure and returns the
following output: Commands completed successfully. Now, if you execute the stored procedure
again, you will see the changes taking effect:
EXEC uspProductList;
Variables in stored procedure
A variable is an object that holds a single value of a specific type e.g., integer, date, or varying
character string.
We typically use variables in the following cases:

 As a loop counter to count the number of times a loop is performed.


 To hold a value to be tested by a control-of-flow statement such as WHILE.
 To store the value returned by a stored procedure or a function
iv. Declaring a variable
To declare a variable, you use the DECLARE statement. For example, the following statement
declares a variable named @model_year :

22 | P a g e Prepared By: Kassahun T. ADBS


DECLARE @model_year SMALLINT;
The DECLARE statement initializes a variable by assigning it a name and a data type. The
variable name must start with the @ sign. In this example, the data type of the @model_year
variable is SMALLINT .
By default, when a variable is declared, its value is set to NULL .
Between the variable name and data type, you can use the optional AS keyword as follows:
DECLARE @model_year AS SMALLINT;
To declare multiple variables, you separate variables by commas:
DECLARE @model_year SMALLINT,
@product_name VARCHAR(MAX);
v. Assigning a value to a variable
To assign a value to a variable, you use the SET statement. For example, the following statement
assigns 2018 to the @model_year variable:
SET @model_year = 2018;
vi. Using variables in a query
The following SELECT statement uses the @model_year variable in the WHERE clause to find
the products of a specific model year:
SELECT
product_name,
model_year,
list_price
FROM
production.products
WHERE
model_year = @model_year
ORDER BY
product_name;
Now, you can put everything together and execute the following code block to get a list of
products whose model year is 2018:
Create procedure spgetModelYear
DECLARE @model_year SMALLINT;
SET @model_year = 2018;
as
SELECT

23 | P a g e Prepared By: Kassahun T. ADBS


product_name,
model_year,
list_price
FROM
production.products
WHERE
model_year = @model_year
ORDER BY
product_name;
************* OR ALTERNATIVELY ***********
Create procedure spgetModelYear
@model_year SMALLINT
AS
SELECT
product_name,
model_year,
list_price
FROM
production.products
WHERE
model_year = @model_year
ORDER BY
product_name;

spgetmodelyear 2018 -- passing the parameter


vii. Storing query result in a variable
The following steps describe how to store the query result in a variable: First, declare a variable
named @product_count with the integer data type:
DECLARE @product_count INT;
Second, use the SET statement to assign the query’s result set to the variable:
SET @product_count = (
SELECT
COUNT(*)
FROM
production.products
);
Third, output the content of the @product_count variable:

24 | P a g e Prepared By: Kassahun T. ADBS


SELECT @product_count;
Or you can use the PRINT statement to print out the content of a variable:
PRINT @product_count;
or
PRINT 'The number of products is ' + CAST(@product_count AS VARCHAR(MAX));
The output in the messages tab is as follows:
The number of products is 204

viii. Deleting a stored procedure


To delete a stored procedure, you use the DROP PROCEDURE or DROP PROC statement:
For example, to remove the uspProductList stored procedure, you execute the following
statement:
DROP PROCEDURE uspProductList;
*********************
Next class
*********************

************************************
SQL Server triggers
************************************
SQL Server triggers are special stored procedures that are executed automatically in response to
the database object, database, and server events. SQL Server provides three type of triggers:
Data manipulation language (DML) triggers which are invoked automatically in response to
INSERT , UPDATE , and DELETE events against tables.
Data definition language (DDL) triggers which fire in response to CREATE, ALTER , and DROP
statements. DDL triggers also fire in response to some system stored procedures that perform
DDL-like operations.
Logon triggers which fire in response to LOGON events
in this section, you will learn how to effectively use triggers in SQL Server.
Creating a trigger in SQL Server – show you how to create a trigger in response to insert and delete
events.
Creating an INSTEAD OF trigger – learn about the INSTEAD OF trigger and its practical
applications.

25 | P a g e Prepared By: Kassahun T. ADBS


Creating a DDL trigger – learn how to create a DDL trigger to monitor the changes made to the
structures of database objects such as tables, views, and indexes.
Disabling triggers – learn how to disable a trigger of a table temporarily so that it does not fire
when associated events occur.
Enabling triggers – show you how to enable a trigger.
Viewing the definition of a trigger – provide you with various ways to view the definition of a
trigger.
Listing all triggers in SQL Server – show you how to list all triggers in a SQL Server by querying
data from the sys.triggers view.
Removing triggers – guide you how to drop one or more existing trigger.

I. Introduction to SQL Server CREATE TRIGGER statement


The CREATE TRIGGER statement allows you to create a new trigger that is fired automatically
whenever an event such as INSERT, DELETE, or UPDATE occurs against a table.
The following illustrates the syntax of the CREATE TRIGGER statement:
CREATE TRIGGER [schema_name.]trigger_name
ON table_name
AFTER {[INSERT],[UPDATE],[DELETE]}
[NOT FOR REPLICATION]
AS
{sql_statements}
In this syntax:
The schema_name is the name of the schema to which the new trigger belongs. The schema
name is optional.
The trigger_name is the user-defined name for the new trigger.
The table_name is the table to which the trigger applies.
The event is listed in the AFTER clause. The event could be INSERT, UPDATE , or DELETE .
A single trigger can fire in response to one or more actions against the table.
The NOT FOR REPLICATION option instructs SQL Server not to fire the trigger when data
modification is made as part of a replication process.
The sql_statements is one or more Transact-SQL used to carry out actions once an event occurs.
“Virtual” tables for triggers: INSERTED and DELETED
SQL Server provides two virtual tables that are available specifically for triggers called
INSERTED and DELETED tables. SQL Server uses these tables to capture the data of the
modified row before and after the event occurs.

26 | P a g e Prepared By: Kassahun T. ADBS


The following table shows the content of the INSERTED and DELETED tables before and after
each event:

DML event INSERTED table holds DELETED table holds


INSERT rows to be inserted empty
new rows modified by the existing rows modified by
UPDATE
update the update
DELETE empty rows to be deleted

A. SQL Server CREATE TRIGGER example


Let’s look at an example of creating a new trigger. We will use the production.products table
from the sample database for the demonstration.
1) Create a table for logging the changes
The following statement creates a table named production.product_audits to record information
when an INSERT or DELETE event occurs against the production.products table:
CREATE TABLE production.product_audits(
change_id INT IDENTITY PRIMARY KEY,
product_id INT NOT NULL,
product_name VARCHAR(255) NOT NULL,
brand_id INT NOT NULL,
category_id INT NOT NULL,
model_year SMALLINT NOT NULL,
list_price DEC(10,2) NOT NULL,
updated_at DATETIME NOT NULL,
operation CHAR(3) NOT NULL,
CHECK(operation = 'INS' or operation='DEL')
);
The production.product_audits table has all the columns from the production.products table. In
addition, it has a few more columns to record the changes e.g., updated_at, operation, and the
change_id.
2) Creating an after DML trigger
First, to create a new trigger, you specify the name of the trigger and schema to which the trigger
belongs in the CREATE TRIGGER clause:
CREATE TRIGGER production.trg_product_audit
Next, you specify the name of the table, which the trigger will fire when an event occurs, in the
ON clause:

27 | P a g e Prepared By: Kassahun T. ADBS


ON production.products
Then, you list the one or more events which will call the trigger in the AFTER clause:
AFTER INSERT, DELETE
The body of the trigger begins with the AS keyword:
AS
BEGIN
After that, inside the body of the trigger, you set the SET NOCOUNT to ON to suppress the
number of rows affected messages from being returned whenever the trigger is fired.
SET NOCOUNT ON;
The trigger will insert a row into the production.product_audits table whenever a row is inserted
into or deleted from the
production.products table. The data for insert is fed from the INSERTED and DELETED tables
via the UNION ALL operator:
INSERT INTO
production.product_audits
(
product_id, product_name, brand_id, category_id, model_year, list_price, updated_at,
operation
)
SELECT
i.product_id, product_name, brand_id, category_id, model_year,
i.list_price, GETDATE(), 'INS'
FROM
inserted AS i
UNION ALL
SELECT
d.product_id, product_name, brand_id, category_id, model_year,
d.list_price, getdate(), 'DEL'
FROM
deleted AS d;
The following put all parts together:
CREATE TRIGGER production.trg_product_audit
ON production.products
AFTER INSERT, DELETE
AS

28 | P a g e Prepared By: Kassahun T. ADBS


BEGIN
SET NOCOUNT ON;
INSERT INTO production.product_audits(
product_id, product_name, brand_id, category_id, model_year, list_price, updated_at,
operation
)
SELECT
i.product_id, product_name, brand_id, category_id, model_year,
i.list_price, GETDATE(), 'INS'
FROM
inserted i
UNION ALL
SELECT
d.product_id, product_name, brand_id, category_id, model_year, d.list_price,
GETDATE(), 'DEL'
FROM
deleted d;
END
Finally, you execute the whole statement to create the trigger. Once the trigger is created, you
can find
it under the triggers folder of the table as shown in the following picture:
3) Testing the trigger
The following statement inserts a new row into the production.products table:
INSERT INTO production.products(
product_name, brand_id, category_id, model_year, list_price
)
VALUES (
'Test product', 1, 1, 2018, 599
);
Because of the INSERT event, the production.trg_product_audit trigger of production.products
table was fired.
Let’s examine the contents of the production.product_audits table:
SELECT
*
FROM production.product_audits;
The following statement deletes a row from the production.products table:

29 | P a g e Prepared By: Kassahun T. ADBS


DELETE FROM
production.products
WHERE
product_id = 322;
As expected, the trigger was fired and inserted the deleted row into the
production.product_audits table:
SELECT
*
FROM
production.product_audits;

B. What is an INSTEAD OF trigger?


An INSTEAD OF trigger is a trigger that allows you to skip an INSERT, DELETE, or UPDATE
statement to a table or a view and execute other statements defined in the trigger instead. The
actual insert, delete, or update operation does not occur at all.
In other words, an INSTEAD OF trigger skips a DML statement and execute other statements.
SQL Server INSTEAD OF trigger syntax
The following illustrates the syntax of how to create an INSTEAD OF trigger:
CREATE TRIGGER [schema_name.] trigger_name
ON {table_name | view_name }
INSTEAD OF {[INSERT] [,] [UPDATE] [,] [DELETE] }
AS
{sql_statements}
In this syntax:
First, specify the name of the trigger and optionally the name of the schema to which the trigger
belongs in the CREATE TRIGGER clause.
Second, specify the name of the table or view which the trigger associated with. Third, specify
an event such as INSERT, DELETE, or UPDATE which the trigger will fire in the INSTEAD
OF clause. The trigger may be called to respond to one or multiple events.
Fourth, place the trigger body after the AS keyword. A trigger’s body may consist of one or
more Transact-SQL statements.
SQL Server INSTEAD OF trigger example
A typical example of using an INSTEAD OF trigger is to override an insert, update, or delete
operation on a view.
Suppose, an application needs to insert new brands into the production.brands table. However,
the new brands should be stored in another table called production.brand_approvals for approval
before inserting into the production.brands table.

30 | P a g e Prepared By: Kassahun T. ADBS


To accomplish this, you create a view called production.vw_brands for the application to insert
new brands. If brands are inserted into the
view, an INSTEAD OF trigger will be fired to insert brands into the
production.brand_approvals table.
The following statement creates a new table named production.brand_approvals for storing
pending approval brands:
CREATE TABLE production.brand_approvals(
brand_id INT IDENTITY PRIMARY KEY,
brand_name VARCHAR(255) NOT NULL
);
The following statement creates a new view named production.vw_brands against the
production.brands and production.brand_approvals tables:

CREATE VIEW production.vw_brands


AS
SELECT
brand_name,
'Approved' approval_status
FROM
production.brands
UNION
SELECT
brand_name,
'Pending Approval' approval_status
FROM
production.brand_approvals;
Once a row is inserted into the production.vw_brands view, we need to route it to the
production.brand_approvals table via the following INSTEAD OF trigger:
CREATE TRIGGER production.trg_vw_brands
ON production.vw_brands
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO production.brand_approvals (
brand_name
)

31 | P a g e Prepared By: Kassahun T. ADBS


SELECT
i.brand_name
FROM
inserted i
WHERE
i.brand_name NOT IN (
SELECT
brand_name
FROM
production.brands
);
END
The trigger inserts the new brand name into the production.brand_approvals if the brand name
does not exist in the production.brands.
Let’s insert a new brand into the production.vw_brands view:
INSERT INTO production.vw_brands(brand_name)
VALUES('Eddy Merckx');
This INSERT statement fired the INSTEAD OF trigger to insert a new row into the
production.brand_approvals table.
If you query data from the production.vw_brands table, you will see a new row appear:
SELECT
brand_name,
approval_status
FROM
production.vw_brands;
The following statement shows the contents of the production.brand_approvals table:
SELECT
*
FROM
production.brand_approvals;

II) SQL Server DDL Trigger


A. Introduction to SQL Server DDL triggers
SQL Server DDL triggers respond to server or database events rather than to table data
modifications.
These events created by the Transact-SQL statement that normally starts with one of the
following keywords CREATE , ALTER , DROP , GRANT, DENY, REVOKE, or UPDATE

32 | P a g e Prepared By: Kassahun T. ADBS


STATISTICS .
For example, you can write a DDL trigger to log whenever a user issues a CREATE TABLE or
ALTER TABLE statement.
The DDL triggers are useful in the following cases:

 Record changes in the database schema.


 Prevent some specific changes to the database schema.
 Respond to a change in the database schema.
The following shows the syntax of creating a DDL trigger:
CREATE TRIGGER trigger_name
ON { DATABASE | ALL SERVER}
[WITH ddl_trigger_option]
FOR {event_type | event_group }
AS {sql_statement}
trigger_name
Specify the user-defined name of trigger after the CREATE TRIGGER keywords. Note that you
don’t
have to specify a schema for a DDL trigger because it isn’t related to an actual database table or
view.
DATABASE | ALL SERVER
Use DATABASE if the trigger respond to database-scoped events or ALL SERVER if the
trigger responds to the server-scoped events.
ddl_trigger_option
The ddl_trigger_option specifies ENCRYPTION and/or EXECUTE AS clause. ENCRYPTION
encrypts the definition of the trigger. EXECUTE AS defines the security context under which the
trigger is executed.
event_type | event_group
The event_type indicates a DDL event that causes the trigger to fire e.g., CREATE_TABLE,
ALTER_TABLE , etc.
The event_group is a group of event_type event such as DDL_TABLE_EVENTS .
A trigger can subscribe to one or more events or groups of events.

Creating a SQL Server DDL trigger example


Suppose you want to capture all the modifications made to the database index so that you can
better monitor the performance of the database server which relates to these index changes.
First, create a new table named index_logs to log the index changes:
CREATE TABLE index_logs (
log_id INT IDENTITY PRIMARY KEY,
event_data XML NOT NULL,

33 | P a g e Prepared By: Kassahun T. ADBS


changed_by SYSNAME NOT NULL
);
GO
Next, create a DDL trigger to track index changes and insert events data into the index_logs
table:
CREATE TRIGGER trg_index_changes
ON DATABASE
FOR
CREATE_INDEX,
ALTER_INDEX,
DROP_INDEX
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO index_logs (
event_data,
changed_by
)
VALUES (
EVENTDATA(),
USER
);
END;
GO
In the body of the trigger, we used the EVENTDATA() function that returns the information
about server or database events. The function is only available inside DDL or logon trigger.
Then, create indexes for the first_name and last_name columns of the sales.customers table:

To be continued ...

34 | P a g e Prepared By: Kassahun T. ADBS

You might also like