Chapter 4 Database Management-1
Chapter 4 Database Management-1
Presented by
Prof. Pooja Mhatre
• Syntax:
CREATE TABLE table_name ( column_1 datatype,
column_2 datatype, column_3 datatype, .... );
• Example:
CREATE TABLE Student_info ( College_Id
number(2), College_name varchar(30), Branch
varchar(10) );
ALTER command
• This command is used to add, delete or change columns in
the existing table.
• The user needs to know the existing table name and can do
add, delete or modify tasks easily.
• Syntax :
Syntax to add a column to an existing table.
ALTER TABLE table_name ADD column_name datatype;
• Example :
In our Student_info table, we want to add a new column for
CGPA. The syntax would be as below as follows.
ALTER TABLE Student_info ADD CGPA number;
TRUNCATE command
• This command is used to remove all rows from the table,
but the structure of the table still exists.
• Syntax:
Syntax to remove an existing table.
TRUNCATE TABLE table_name;
• Example:
The College Authority wants to remove the details of all
students for new batches but wants to keep the table
structure. The command they can use is as follows.
TRUNCATE TABLE Student_info;
DROP command
• This command is used to remove an existing table
along with its structure from the Database.
• Syntax :
Syntax to drop an existing table.
DROP TABLE table_name;
• Example :
If the College Authority wants to change their
Database by deleting the Student_info Table.
DROP TABLE Student_info;
RENAME command
• It is possible to change name of table with or without data
in it using simple RENAME command.
• We can rename any table object at any point of time.
• Syntax:
RENAME TABLE <Table Name> To
<New_Table_Name>;
• Example:
If you want to change the name of the table from
Employee to Emp we can use rename command as
RENAME TABLE Employee To EMP;
Data Manipulation
Language (DML)
• The SQL commands that deal with the manipulation
of data present in the database belong to DML or
Data Manipulation Language and this includes most
of the SQL statements.
• It is the component of the SQL statement that
controls access to data and to the database.
Basically, DCL statements are grouped with DML
statements.
• DML commands
i. INSERT
ii. UPDATE
iii. DELETE
INSERT Command
• This command is used to enter the information or values
into a row. We can connect one or more records to a
single table within a repository using this instruction.
This is often used to connect an unused tag to the
documents.
• Syntax:
INSERT INTO <table_name> VALUES ('column_name1'
<datatype>, 'column_name2' <datatype>)
• Example :
INSERT INTO students VALUES ('1', 'Nirmit', 'Gorakhpur');
UPDATE Command
• This command is used to alter existing table
records. Within a table, it modifies data from one or
more records. This command is used to alter the
data which is already present in a table.
• Syntax:
UPDATE <table_name> SET <column_name =
value> WHERE condition;
• Example:
UPDATE students SET due_fees = 20000 WHERE
stu_name = 'Mini';
DELETE Command
• It deletes all archives from a table. This command is
used to erase some or all of the previous table’s
records. If we do not specify the ‘WHERE’ condition then
all the rows would be erased or deleted.
• Syntax:
DELETE FROM <table_name> WHERE <condition>;
• Example:
DELETE FROM students WHERE stu_id = '001';
Advantages & Disadvantages
of DML
Advantages of DML
i. DML statements could alter the data that is contained or
stored in the database.
ii. It delivers effective human contact with the machine.
iii. User could specify what data is required.
iv. DML aims to have many different varieties and
functionalities between vendors providing databases.
Disadvantages of DML
v. We cannot use DML to change the structure of the database.
vi. Limit table view i.e., it could conceal some columns in tables.
vii. Access the data without having the data stored in the object.
viii. Unable to build or erase lists or sections using DML.
Data Query Language
(DQL)
• DQL statements are used for performing queries on
the data within schema objects.
• The purpose of the DQL Command is to get some
schema relation based on the query passed to it.
• This command allows getting the data out of the
database to perform operations with it.
• When a SELECT is fired against a table or tables the
result is compiled into a further temporary table,
which is displayed or perhaps received by the
program.
• DQL Command
i. SELECT
SELECT Command
• This command is used to get data out of the database.
It helps users of the database to access from an
operating system, the significant data they need. It
sends a track result set from one tables or more.
• Syntax :
SELECT * FROM <table_name>;
• Example:
SELECT * FROM students;
OR
SELECT * FROM students where due_fees
<=20000;
Data Control Language
(DCL)
• DCL commands are used to control privileges in the
database.
• The privileges (right to access the data) are
required for performing all the database
operations, like creating tables, views, or
sequences.
• DCL statements are used to perform the work
related to the rights, permissions, and other control
of the database system.
• DCL Commands
i. GRANT
ii. REVOKE
GRANT command
• This command is used to grant permission to the user
to perform a particular operation on a particular object.
• If we are a database administrator and we want to
restrict user accessibility such as one who only views
the data or may only update the data.
• we can give the privilege permission to the users
according to our wish.
• Syntax
• GRANT privilege_list ON Object_name TO user_name;
REVOKE command
• This command is used to take permission/access back from
the user.
• If we want to return permission from the database that we
have granted to the users at that time we need to run
REVOKE command.
• Syntax:
REVOKE privilege_list ON object_name FROM
user_name;
Advantages & Disadvantages
Of DCL commands
Advantages Of DCL commands
i. It allows to restrict the user from accessing data in database.
ii. It ensures security in database when the data is exposed to multiple
users.
iii. It is the wholesome responsibility of the data owner or data
administrator to maintain the authority of grant and revoke privileges to
the users preventing any threat to data.
iv. It prevents other users to make changes in database who have no
access to Database
Syntax:
column name datatype [CONSTRAINT constraint_name]
PRIMARY KEY
Example:
CREATE TABLE Employee ( id number(5), name char(20),
dept char(10), age number(2), salary number(10), location
char(10), CONSTRAINT emp_id_pk PRIMARY KEY (id) );
Primary Key Constraints
The primary key constraint at the table level
Syntax:
[CONSTRAINT constraint_name] PRIMARY KEY
(column_name1,column_name2,..)
Example:
CREATE TABLE Employee ( id number(5), NOT NULL,
name char(20), dept char(10), age number(2), salary
number(10), location char(10), ALTER TABLE employee
ADD CONSTRAINT PK_EMPLOYEE_ID PRIMARY KEY (id) );
Unique Key Constraints
• A Unique Key ensures that the values in a column are
unique, but unlike a primary key, it allows one NULL value.
• Both the UNIQUE and PRIMARY KEY constraints provide a
guarantee for uniqueness for a column or set of columns.
• Example:
Syntax:
[CONSTRAINT constraint_name] UNIQUE
Example:
CREATE TABLE Employee ( id number(5) PRIMARY KEY,
name char(20), dept char(10), age number(2), salary
number(10), location char(10) UNIQUE );
Unique Key Constraints
Syntax:
[CONSTRAINT constraint_name] UNIQUE(column_name) ;
Example:
CREATE TABLE Employee ( id number(5) PRIMARY KEY,
name char(20), dept char(10), age number(2), salary
number(10), location char(10), CONSTRAINT loc_un
UNIQUE(location) );
Domain Constraints
• Domain constraints are a type of integrity constraint that
ensure the values stored in a column (or attribute) of a
database are valid and within a specific range or domain.
• In simple terms, they define what type of data is allowed in
a column and restrict invalid data entry.
• The data type of domain include string, char, time, integer,
date, currency etc.
• The value of the attribute must be available in comparable
domains.
• Types of Domain Constraints
1. NOT NULL Constraint
2. CHECK Constraint
Example
• This table demonstrates domain
constraints in action by enforcing rules
for each column:
Student_Id Name Semester Age
• Student_Id: Must be unique and
follow a specific format
Aniket
like 21CSE###. No duplicates or 21CSE100
Kumar
6th 20
invalid formats allowed.
• Name: Accepts only valid text (no
Shashwat
21CSE101 7th 21
numbers) and cannot be left empty Dubey
(NOT NULL constraint).
• Semester: Allows specific values Manvendr
21CSE102 8th 22
like 5th, 6th, etc., and ensures valid a Sharma
• Example:
CREATE TABLE employee ( id number(5), name char(20) CONSTRAINT
nm_nn NOT NULL, dept char(10), age number(2), salary number(10), location
char(10) );
OR
Syntax:
CREATE TABLE table_name ( col1 datatype [CONSTRAINT
constraint_name] CHECK (condition), col2 datatype );
Example:
CREATE TABLE employee ( id number(5) PRIMARY KEY,
name char(20), dept char(10), age number(2), gender
char(1) CHECK (gender in ('M','F')), salary number(10),
location char(10) );
Referential integrity
constraints
• A referential integrity constraint is also known as
foreign key constraint.
• Referential integrity constraints are rules that
ensure relationships between tables remain
consistent.
• The FOREIGN KEY constraint is used to prevent
actions that would destroy links between tables.
• A FOREIGN KEY is a field (or collection of fields) in
one table, that refers to the PRIMARY KEY in
another table.
• The table with the foreign key is called the child
table, and the table with the primary key is called
the referenced or parent table.
Referential integrity
constraints
Syntax:
[CONSTRAINT constraint_name] REFERENCES
Referenced_Table_name(column_name)
Example:
CREATE TABLE product ( product_id number(5) CONSTRAINT
pd_id_pk PRIMARY KEY, product_name char(20), supplier_name
char(20), unit_price number(10) );
Syntax:
[CONSTRAINT constraint_name] FOREIGN KEY(column_name)
REFERENCES referenced_table_name(column_name);
Example:
CREATE TABLE order_items ( order_id number(5) , product_id
number(5), product_name char(20), supplier_name char(20),
unit_price number(10) CONSTRAINT od_id_pk PRIMARY
KEY(order_id), CONSTRAINT pd_id_fk FOREIGN
KEY(product_id) REFERENCES product(product_id) );
SET Operators in SQL
• SET operators are special type of operators which
are used to combine the result of two queries.
• Syntax:
1 Jack
2 Harry
3 Jackson
3 Jackson
4 Stephan
5 David
2 Harry
3 Jackson
4 Stephan
5 David
UNION ALL OPERATION
• Union All operation is equal to the Union operation.
• It returns the set without removing duplication and
sorting the data.
• The SQL UNION ALL command combines the result of
two or more SELECT statements in SQL.
• Syntax:
SELECT column_name FROM table1
UNION ALL
SELECT column_name FROM table2;
The First table
ID NAME
1 Jack
2 Harry
3 Jackson
3 Jackson
4 Stephan
5 David
2 Harry
3 Jackson
3 Jackson
4 Stephan
5 David
INTERSECT OPERATION
• It is used to combine two SELECT statements. The
Intersect operation returns the common rows from
both the SELECT statements.
• In the Intersect operation, the number of datatype
and columns must be the same.
• It has no duplicates and it arranges the data in
ascending order by default.
• Syntax
SELECT column_name FROM table1
INTERSECT
SELECT column_name FROM table2;
The First table
ID NAME
1 Jack
2 Harry
3 Jackson
3 Jackson
4 Stephan
5 David
3 Jackson
MINUS OPERATION
• It combines the result of two SELECT statements.
Minus operator is used to display the rows which
are present in the first query but absent in the
second query.
• It has no duplicates and data arranged in
ascending order by default.
• Syntax:
SELECT column_name FROM table1
MINUS
SELECT column_name FROM table2;
The First table
ID NAME
1 Jack
2 Harry
3 Jackson
3 Jackson
4 Stephan
5 David
1 Jack
2 Harry
String Functions
• SQL String Functions are powerful tools that allow
us to manipulate, format, and extract specific parts
of text data in our database.
• Query:
SELECT CONCAT('John', ' ', 'Doe') AS FullName;
• Output:
John Doe
CHAR_LENGTH() / CHARACTER_LENGTH()
• Query:
SELECT CHAR_LENGTH('Hello') AS StringLength;
• Output:
5
UPPER() and LOWER():
• Convert Text Case
• These functions convert the text to uppercase or
lowercase, respectively. They are useful for normalizing
the case of text in a database.
• Query:
SELECT UPPER('hello') AS UpperCase;
SELECT LOWER('HELLO') AS LowerCase;
• Output:
HELLO
hello
LENGTH()
• Length of String in Bytes
• LENGTH() returns the length of a string in bytes.
• This can be useful for working with multi-byte character
sets.
• Query:
SELECT LENGTH('Hello') AS LengthInBytes;
• Output:
5
REPLACE()
• Replace Substring in String
• The REPLACE() function replaces occurrences of a
substring within a string with another substring.
• This is useful for cleaning up data, such as replacing invalid
characters or formatting errors.
• Query:
SELECT REPLACE('Hello World', 'World', 'SQL') AS
UpdatedString;
• Output:
Hello SQL
SUBSTRING() / SUBSTR()
• Extract Part of a String
• The SUBSTRING() (or SUBSTR()) function is used to extract
a substring from a string, starting from a specified
position.
• It is especially useful when we need to extract a specific
part of a string, like extracting the domain from an email
address.
• Query:
SELECT SUBSTRING('Hello World', 1, 5) AS
SubStringExample;
• Output:
Hello
7. LEFT() and RIGHT():
• Extract Substring from Left or Right
• The LEFT() and RIGHT() functions allow you to extract a
specified number of characters from the left or right side of
a string, respectively.
• It is used for truncating strings for display.
• Query:
SELECT LEFT('Hello World', 5) AS LeftString;
SELECT RIGHT('Hello World', 5) AS RightString;
• Output:
Hello
World
8. INSTR()
• Query:
SELECT INSTR('Hello World', 'World') AS SubstringPosition;
• Output:
7
9. TRIM()
• Remove Leading and Trailing Spaces
• The TRIM() function removes leading and trailing spaces (or
other specified characters) from a string.
• By default, it trims spaces but can also remove specific
characters using TRIM(character FROM string).
• This is helpful for cleaning text data, such as user inputs or
database records.
• Query:
SELECT TRIM(' ' FROM ' Hello World ') AS TrimmedString;
• Output:
Hello World
10. REVERSE()
• Reverse the String
• The REVERSE() function reverses the characters in a
string.
• It’s useful in situations where we need to process data
backward, such as for password validation or
certain pattern matching.
• Query:
SELECT REVERSE('Hello') AS ReversedString;
• Output:
olleH
❖ Some Other String Function
⮚ CONCAT_WS(): This function is used to add two words or strings with a symbol
as concatenating symbol.
1. Count()
2. Sum()
3. Avg()
4. Min()
5. Max()
COUNT FUNCTION
• COUNT function is used to Count the number of rows in a
database table. It can work on both numeric and non-
numeric data types.
• COUNT function uses the COUNT(*) that returns the count
of all the rows in a specified table. COUNT(*) considers
duplicate and Null.
Syntax
COUNT(*)
or
COUNT( [ALL|DISTINCT] expression )
PRODUCT_MAST
Item1 Com1 2 10 20
Item2 Com2 3 25 75
Item3 Com1 2 30 60
Item4 Com3 5 10 50
Item5 Com2 2 20 40
Item6 Cpm1 3 25 75
Item8 Com1 3 10 30
Item9 Com2 2 25 50
Example: COUNT()
SELECT COUNT(*) FROM PRODUCT_MAST;
Output: 10
Example: COUNT with Example: COUNT() with
WHERE DISTINCT
SELECT COUNT(*) FROM SELECT COUNT ( DISTINCT
PRODUCT_MAST COMPANY) FROM
WHERE RATE>=20; PRODUCT_MAST;
Output: 7 Output: 3
• Syntax
SUM()
or
SUM( [ALL|DISTINCT] expression )
PRODUCT_MAST
Item1 Com1 2 10 20
Item2 Com2 3 25 75
Item3 Com1 2 30 60
Item4 Com3 5 10 50
Item5 Com2 2 20 40
Item6 Cpm1 3 25 75
Item8 Com1 3 10 30
Item9 Com2 2 25 50
Example: SUM()
SELECT SUM(COST) FROM PRODUCT_MAST;
Output: 670
Example: SUM() with WHERE
SELECT SUM(COST)
FROM PRODUCT_MAST
WHERE QTY>3; Example: SUM() with
Output: 320 HAVING
SELECT COMPANY,
Example: SUM() with GROUP SUM (COST)
BY FROM PRODUCT_MAST
SELECT SUM(COST) GROUP BY COMPANY
FROM PRODUCT_MAST HAVING SUM(COST)>=17
WHERE QTY>3 0;
GROUP BY COMPANY; Output:
Output: Com1 335
Com1 150
Com2 170
AVG function
• The AVG function is used to calculate the
average value of the numeric type.
• AVG function returns the average of all non-Null
values.
• Syntax
AVG()
or
AVG( [ALL|DISTINCT] expression )
PRODUCT_MAST
Item1 Com1 2 10 20
Item2 Com2 3 25 75
Item3 Com1 2 30 60
Item4 Com3 5 10 50
Item5 Com2 2 20 40
Item6 Cpm1 3 25 75
Item8 Com1 3 10 30
Item9 Com2 2 25 50
Example:
SELECT AVG(COST) FROM PRODUCT_MAST;
Output: 67.00
MAX Function
• MAX function is used to find the maximum
value of a certain column.
• This function determines the largest value of
all selected values of a column.
• Syntax
MAX()
or
MAX( [ALL|DISTINCT] expression )
PRODUCT_MAST
Item1 Com1 2 10 20
Item2 Com2 3 25 75
Item3 Com1 2 30 60
Item4 Com3 5 10 50
Item5 Com2 2 20 40
Item6 Cpm1 3 25 75
Item8 Com1 3 10 30
Item9 Com2 2 25 50
Example:
SELECT MAX(RATE) FROM PRODUCT_MAST;
Output: 30
MIN Function
• MIN function is used to find the minimum value of a
certain column.
• This function determines the smallest value of all
selected values of a column.
• Syntax
MIN()
or
MIN( [ALL|DISTINCT] expression )
PRODUCT_MAST
Item1 Com1 2 10 20
Item2 Com2 3 25 75
Item3 Com1 2 30 60
Item4 Com3 5 10 50
Item5 Com2 2 20 40
Item6 Cpm1 3 25 75
Item8 Com1 3 10 30
Item9 Com2 2 25 50
Example:
SELECT MIN(RATE) FROM PRODUCT_MAST;
Output:
GROUP BY clause
• The GROUP BY statement in SQL is used for organizing and
summarizing data based on identical values in specified columns.
• By using the GROUP BY clause, users can apply aggregate functions
like SUM, COUNT, AVG, MIN, and MAX to each group, making it
easier to perform detailed data analysis.
• GROUP BY clause is used with the SELECT statement.
• In the query, the GROUP BY clause is placed after the WHERE
clause.
• In the query, the GROUP BY clause is placed before the ORDER BY
clause if used.
• In the query, the Group BY clause is placed before the Having
clause.
• Syntax:
SELECT column1, function_name(column2)
FROM table_name
GROUP BY column1, column2
Example:
SELECT name, SUM(sal) FROM emp GROUP BY name;
HAVING clause
• The HAVING clause in SQL is used to filter query results based on
aggregate functions.
• Unlike the WHERE clause, which filters individual rows before
grouping, the HAVING clause filters groups of data after
aggregation.
• It is commonly used with functions like SUM(), AVG(), COUNT(),
MAX(), and MIN().
• Works with Boolean conditions (AND, OR)
Output:
LEFT JOIN
• LEFT JOIN returns all the rows of the table on the left side of the
join and matches rows for the table on the right side of the join.
• For the rows for which there is no matching row on the right
side, the result-set will contain null. LEFT JOIN is also known
as LEFT OUTER JOIN.
• Syntax
SELECT table1.column1,table1.column2,table2.column1,....
FROM table1
LEFT JOIN table2
ON table1.matching_column = table2.matching_column;
LEFT JOIN Example
• In this example, the LEFT JOIN retrieves all rows from
the Student table and the matching rows from
the StudentCourse table based on the ROLL_NO column.
• Query:
SELECT Student.NAME,StudentCourse.COURSE_ID
FROM Student
LEFT JOIN StudentCourse
ON StudentCourse.ROLL_NO = Student.ROLL_NO;
• Output:
RIGHT JOIN
• RIGHT JOIN returns all the rows of the table on the right side
of the join and matching rows for the table on the left side of
the join.
• It is very similar to LEFT JOIN for the rows for which there is no
matching row on the left side, the result-set will contain null.
• RIGHT JOIN is also known as RIGHT OUTER JOIN.
• Syntax
SELECT table1.column1,table1.column2,table2.column1,....
FROM table1
RIGHT JOIN table2
ON table1.matching_column = table2.matching_column;
RIGHT JOIN Example
• In this example, the RIGHT JOIN retrieves all rows from
the StudentCourse table and the matching rows from
the Student table based on the ROLL_NO column.
• Query:
SELECT Student.NAME,StudentCourse.COURSE_ID
FROM Student
RIGHT JOIN StudentCourse
ON StudentCourse.ROLL_NO = Student.ROLL_NO;
• Output:
FULL JOIN
• FULL JOIN creates the result-set by combining results of
both LEFT JOIN and RIGHT JOIN.
• The result-set will contain all the rows from both tables.
• For the rows for which there is no matching, the result-set will
contain NULL values.
• Syntax
SELECT table1.column1,table1.column2,table2.column1,....
FROM table1
FULL JOIN table2
ON table1.matching_column = table2.matching_column;
FULL JOIN Example
• This example demonstrates the use of
NAME COURSE_ID
a FULL JOIN, which combines the
results of both LEFT JOIN and RIGHT HARSH 1
JOIN. PRATIK 2
• The query retrieves all rows from
the Student and StudentCourse tabl RIYANKA 2
es. DEEP 3
• Both table must have at least one common column with same column
name and same data type.
Natural join Example
C_ID
C1
C3
• Step 2: Use the result of Step 1 to find the
corresponding S_IDs:
The inner query finds the course IDs, and the outer query retrieves
the student IDs associated with those courses from
the STUDENT_COURSE table
S_ID
S1
S2
S4
2. Correlated Nested
Queries
• In correlated nested queries, the inner query depends on the
outer query for its execution. For each row processed by the
outer query, the inner query is executed.
• The EXISTS keyword is often used with correlated queries.
• Example 2: Using EXISTS
Find the names of students who are enrolled in the course
with C_ID = ‘C1’:
SELECT S_NAME FROM STUDENTS
WHERE EXISTS (
SELECT 1 FROM STUDENT_COURSE SC
WHERE S.S_ID = SC.S_ID AND SC.C_ID = 'C1'
);
S_NAME
RAM
RAMESH
Advantages of Nested
Queries
• Simplifies complex queries: Nested queries allow us to divide
complicated SQL tasks into smaller, more manageable parts. This
modular approach makes queries easier to write, debug, and
maintain.
• Enhances flexibility: By enabling the use of results from one
query within another, nested queries allow dynamic filtering and
indirect joins, which can simplify query logic.
• Supports advanced analysis: Nested queries empower
developers to perform operations like conditional aggregation,
subsetting, and customized calculations, making them ideal for
sophisticated data analysis tasks.
• Improves readability: When properly written, nested queries
can make complex operations more intuitive by encapsulating
logic within inner queries.
SQL Trigger
• SQL triggers are a critical feature in database
management systems (DBMS) that provide automatic
execution of a set of SQL statements when specific
database events, such as INSERT, UPDATE,
or DELETE operations, occur.
• Triggers are commonly used to maintain data
integrity, track changes, and enforce business
rules automatically, without needing manual input.
• A trigger is a stored procedure in a database that
automatically invokes whenever a special event in the
database occurs.
• By using SQL triggers, developers can automate tasks,
ensure data consistency, and keep accurate records
of database activities.
SQL Trigger
• Syntax
create trigger [trigger_name]
[before | after]
{insert | update | delete}
on [table_name]
FOR EACH ROW
BEGIN
END;
• Syntax:
SELECT name, is_instead_of_trigger
FROM sys.triggers
WHERE type = ‘TR’;
BEFORE and AFTER
Triggers
• SQL triggers can be specified to run BEFORE or AFTER the
triggering event.
• BEFORE Triggers: Execute before the actual SQL statement is
executed. Useful for validating data before insertion or updating.
• AFTER Triggers: Execute after the SQL statement completes.
Useful for logging or cascading updates to other tables.
• Example: Using BEFORE Trigger for Calculations
Given Student Report Database, in which student
marks assessment is recorded. In such a schema, create a
trigger so that the total and percentage of specified marks are
automatically inserted whenever a record is inserted. Here,
a trigger will invoke before the record is inserted so BEFORE
Tag can be used.
Advantages of Triggers
• Data Integrity: Triggers help enforce
consistency and business rules, ensuring that
data follows the correct format.
• Automation: Triggers eliminate the need for
manual intervention by automatically performing
tasks such as updating, inserting, or deleting
records when certain conditions are met.
• Audit Trail: Triggers can track changes in a
database, providing an audit trail of INSERT,
UPDATE, and DELETE operations.
• Performance: By automating repetitive tasks,
triggers improve SQL query performance and
reduce manual workload.
End of Chapter - 4