select name
from instructor| name |
|---|
| Srinivasan |
| Wu |
| Mozart |
| Einstein |
| El Said |
| Gold |
| Katz |
| Califieri |
| Singh |
| Crick |
following can be specified:
create table department (
dept_name varchar(20),
building varchar(15),
budget numeric(12,2),
primary key (dept_name) --primary key integrity constraint
);general form:
create table r(
a1 domain1,
a2 domain2,
...
a_n domain_n
[integrity constraint 1],
...
[integrity constraing 2] -- these are optional
)primary key: a1, …, a_n together form the primary key of the relation:
primary key(a1, a2, ..., a_n)foreign key: a1, …, a_n together form a foreign key over a relation s, i.e. a1, …, a_n must be a primary key of some tuple in s (existence: referential integrity)
foreign key (a1, a2, ..., a_n) references snot null:
name varchar(20) not null, --name can not be nullconcrete example:
create table instructor(
ID varchar(5),
name varchar(20) not null, --name can not be null
dept_name varchar(20),
salary numeric(8,2),
primary key (ID),
foreign key (dept_name) references department
)Note that explicitly specifying the primary key of the referenced relation
foreign key (dept_name) references department(dept_name)is also possible but not required.
remove a relation completely from the database schema:
drop table r; --not to be confused with 'delete from'modify a relation schema:
alter table r add a1 a2; -- add the attributes a1, a2 to the relation ralter table r drop a; -- drop/remove attribute a from the relation rsome dbs’ don’t support dropping single attributes but only whole tables.
A typical sql querry has the form
select a1, ..., a_n
from r1, ..., r_m
where P -- P is a predicate/conditionselect name
from instructor| name |
|---|
| Srinivasan |
| Wu |
| Mozart |
| Einstein |
| El Said |
| Gold |
| Katz |
| Califieri |
| Singh |
| Crick |
select dept_name
from instructor| dept_name |
|---|
| Comp. Sci. |
| Finance |
| Music |
| Physics |
| History |
| Physics |
| Comp. Sci. |
| History |
| Finance |
| Biology |
select distinct dept_name --removes duplicates
from instructor| dept_name |
|---|
| Physics |
| Biology |
| Elec. Eng. |
| Finance |
| Comp. Sci. |
| History |
| Music |
Select allows arbitrary expressions of attributes. we can output 10% salary raise for instructors
select id, name, dept_name, salary * 1.1
from instructor| id | name | dept_name | ?column? |
|---|---|---|---|
| 10101 | Srinivasan | Comp. Sci. | 71500 |
| 12121 | Wu | Finance | 99000 |
| 15151 | Mozart | Music | 44000 |
| 22222 | Einstein | Physics | 104500 |
| 32343 | El Said | History | 66000 |
| 33456 | Gold | Physics | 95700 |
| 45565 | Katz | Comp. Sci. | 82500 |
| 58583 | Califieri | History | 68200 |
| 76543 | Singh | Finance | 88000 |
| 76766 | Crick | Biology | 79200 |
select name
from instructor
where dept_name = 'Comp. Sci.'
and salary > 70000| name |
|---|
| Katz |
| Brandt |
select i.name, d.name as dept_name, building
from instructor i, department d
where i.dept_name = d.name| name | dept_name | building |
|---|---|---|
| Nishimoto | Biology | Watson |
| Crick | Biology | Watson |
| Brandt | Comp. Sci. | Taylor |
| Katz | Comp. Sci. | Taylor |
| Srinivasan | Comp. Sci. | Taylor |
| Kim | Elec. Eng. | Taylor |
| Singh | Finance | Painter |
| Wu | Finance | Painter |
| Roznicki | History | Painter |
| Califieri | History | Painter |
select i.name, t.course_id
from instructor i, teaches t
where i.id = t.instructor_id| name | course_id |
|---|---|
| Srinivasan | CS-101 |
| Srinivasan | CS-315 |
| Srinivasan | CS-347 |
| Wu | FIN-201 |
| Mozart | MU-199 |
| Einstein | PHY-101 |
| El Said | HIS-351 |
| Katz | CS-101 |
| Katz | CS-319 |
| Crick | BIO-101 |
select i.name, t.course_id
from instructor i, teaches t
where i.id = t.instructor_id and i.dept_name = 'Comp. Sci.'| name | course_id |
|---|---|
| Srinivasan | CS-101 |
| Srinivasan | CS-315 |
| Srinivasan | CS-347 |
| Katz | CS-101 |
| Katz | CS-319 |
| Brandt | CS-190 |
| Brandt | CS-190 |
| Brandt | CS-319 |
select i.name as instructor_name, t.course_id -- as can be omitted
from instructor as i, teaches as t -- as can be ommited
where i.id = t.instructor_id| instructor_name | course_id |
|---|---|
| Srinivasan | CS-101 |
| Srinivasan | CS-315 |
| Srinivasan | CS-347 |
| Wu | FIN-201 |
| Mozart | MU-199 |
| Einstein | PHY-101 |
| El Said | HIS-351 |
| Katz | CS-101 |
| Katz | CS-319 |
| Crick | BIO-101 |
Renaming useful when comparing tuples in the same relation:
select distinct i.name
from instructor i , instructor i2
where i.salary > i2.salary and i2.dept_name = 'Biology'| name |
|---|
| Brandt |
| Gold |
| Wu |
| Kim |
| Nishimoto |
| Katz |
| Einstein |
| Singh |
||values
('hey' || ' there!')| column1 |
|---|
| hey there! |
upper() and lower()values
(upper('hey there')),
(lower('HEY THERE'))| column1 |
|---|
| HEY THERE |
| hey there |
trim()values
(trim('hey ' ) || ' there!')| column1 |
|---|
| hey there! |
%: matches any string_: matches any characterintro%: any string beginning with ‘Intro’%Comp%: any string containing ‘Comp’ as a substring___: any string of exactly three characters___%: any string of at least three charactersselect *
from course c
where c.title ilike '%comp%' --ilike is case insensitive like| id | title | dept_name | credits |
|---|---|---|---|
| BIO-399 | Computational Biology | Biology | 3 |
| CS-101 | Intro. to Computer Science | Comp. Sci. | 4 |
*Escaping special characters like “%” with “":
select *
from (
values
('%15')
) r(a)
where a like '\%%' | a |
|---|
| %15 |
select *
from (
values
('%15')
) r(a)
where a like '^%%' escape '^' -- '^' is defined as the escape character| a |
|---|
| %15 |
select name
from instructor
where dept_name = 'Physics'
order by name;| name |
|---|
| Einstein |
| Gold |
select *
from instructor
order by salary desc, name asc| id | name | dept_name | salary |
|---|---|---|---|
| 30765 | Green | Music | NA |
| 22222 | Einstein | Physics | 95000 |
| 83821 | Brandt | Comp. Sci. | 92000 |
| 12121 | Wu | Finance | 90000 |
| 33456 | Gold | Physics | 87000 |
| 98345 | Kim | Elec. Eng. | 80000 |
| 76543 | Singh | Finance | 80000 |
| 45565 | Katz | Comp. Sci. | 75000 |
| 10032 | Nishimoto | Biology | 73120 |
| 76766 | Crick | Biology | 72000 |
SELECT name
from instructor i
where i.salary BETWEEN 90000 and 100000| name |
|---|
| Wu |
| Einstein |
| Brandt |
SELECT i.name, t.course_id
from instructor i, teaches t
where i.id = t.instructor_id and i.dept_name = 'Biology' is equivalent to
SELECT i.name, t.course_id
from instructor i, teaches t
where (i.id, i.dept_name) = (t.instructor_id, 'Biology')| name | course_id |
|---|---|
| Crick | BIO-101 |
| Crick | BIO-301 |
Set operations eliminate duplicates by default. Duplicates retained by all keyword.
corresponds to \(\cup\).
(
select course_id
from section
where semester = 'Fall' and year = 2017
)
UNION
(
select course_id
from section
where semester = 'Spring' and year = 2018
)| course_id |
|---|
| CS-101 |
| CS-315 |
| CS-319 |
| CS-347 |
| FIN-201 |
| HIS-351 |
| MU-199 |
| PHY-101 |
Corresponds to \(\cap\).
(
select course_id
from section
where semester = 'Fall' and year = 2017
)
intersect
(
select course_id
from section
where semester = 'Spring' and year = 2018
)| course_id |
|---|
| CS-101 |
Corresponds to \(\backslash\).
(
select course_id
from section
where semester = 'Fall' and year = 2017
)
except
(
select course_id
from section
where semester = 'Spring' and year = 2018
)| course_id |
|---|
| PHY-101 |
| CS-347 |
all works:union all:
with r(a) as (
values
(1),
(1)
), s(a) as (
values
(1)
)
(select *
from r )
union all
(select *
from s)| a |
|---|
| 1 |
| 1 |
| 1 |
intersect all:
with r(a) as (
values
(1),
(1),
(1)
), s(a) as (
values
(1),
(1)
)
(select *
from r )
INTERSECT all
(select *
from s)| a |
|---|
| 1 |
| 1 |
except all:
with r(a) as (
values
(1),
(1)
), s(a) as (
values
(1)
)
(select *
from r )
except all
(select *
from s)| a |
|---|
| 1 |
with r(a) as (
values
(1),
(1)
), s(a) as (
values
(1)
)
(select *
from s )
except all
(select *
from r)| a |
|---|
null represents values that are not known. (can be anything).null produce null:values
(1 + null)| column1 |
|---|
| NA |
null (other than is [not] null) have a special truth value unknown.
(1 < unknown) = uknownunknown:| p | q | p and q |
|---|---|---|
false |
unknown |
false |
true |
unknown |
unknown |
| p | q | p or q |
|---|---|---|
false |
unknown |
unknown |
true |
unknown |
true |
not unknown = uknown
tuples that evaluate to uknown in the where clause are not included in the result (just like the ones that evaluate to false)
we can test if a value is or isn’t null:
select a
from (
values
(1, 3),
(2, null)
) r(a, b)
where b is null| a |
|---|
| 2 |
select a
from (
values
(1, 3),
(2, null)
) r(a, b)
where b is not null| a |
|---|
| 1 |
uknownselect a
from (
values
(1, 3),
(2, null)
) r(a, b)
where b > 2 is unknown| a |
|---|
| 2 |
select a
from (
values
(1, 3),
(2, null)
) r(a, b)
where b > 2 is not unknown| a |
|---|
| 1 |
avg: input must be numericminmaxsum: computes the total sum of the values in the aggregate, input must be numericcountselect avg(salary) as avg_salary
from instructor
where dept_name = 'Comp. Sci.'| avg_salary |
|---|
| 77333.33 |
Duplicates are retained. Retention of duplicates is obviously important for calculating averages. But sometimes we may want to eliminate duplicates:
select count(distinct t.instructor_id)
from teaches t
where semester = 'Spring' and year = 2018| count |
|---|
| 6 |
as opposed to
select count(t.instructor_id)
from teaches t
where semester = 'Spring' and year = 2018| count |
|---|
| 7 |
count(*):select count(*)
from course| count |
|---|
| 13 |
count(*) retains null values. It is the only aggregate function that does so. All other aggregate functions ignore null values, including count functions applied on a single attribute. That is count(*) and count(attr) are different:
select count(*) as count_star, count(a) as count_attribute
from (
values
(1),
(null)
) r(a)| count_star | count_attribute |
|---|---|
| 2 | 1 |
Instead of applying the aggregate function to a single aggregate (collection), we can apply it to multiple aggregates/collections, that consist of tuples grouped together w.r.t certain grouping attributes:
select dept_name, avg(salary) as avg_dept_salary
from instructor
group by dept_name
order by avg(salary) desc| dept_name | avg_dept_salary |
|---|---|
| Physics | 91000.00 |
| Finance | 85000.00 |
| Elec. Eng. | 80000.00 |
| Comp. Sci. | 77333.33 |
| Biology | 72560.00 |
| History | 59666.67 |
| Music | 40000.00 |
select dept_name, count(*) cnt
from instructor
group by dept_name
order by dept_name| dept_name | cnt |
|---|---|
| Biology | 2 |
| Comp. Sci. | 3 |
| Elec. Eng. | 1 |
| Finance | 2 |
| History | 3 |
| Music | 2 |
| Physics | 2 |
select i.dept_name, count(distinct i.id) as instr_count
from instructor i , teaches t
where i.id = t.instructor_id
and t.semester = 'Spring' and t.year = 2018
group by i.dept_name| dept_name | instr_count |
|---|---|
| Comp. Sci. | 3 |
| Finance | 1 |
| History | 1 |
| Music | 1 |
Note that only attributes allowed to appear in the select clause (other than the attribute being aggregated) are the attributes used in the group by clause. Thus
select a, X, avg(b) -- X doesn't appear in the group by clause below
from r -- some relation r
where P -- some predicate
group by ait not legal.
Specifies a condition that applies to groups rather than to tuples.
select i.dept_name, avg(i.salary)
from instructor i
group by dept_name
having avg(i.salary) > 42000
order by avg(i.salary) desc| dept_name | avg |
|---|---|
| Physics | 91000.00 |
| Finance | 85000.00 |
| Elec. Eng. | 80000.00 |
| Comp. Sci. | 77333.33 |
| Biology | 72560.00 |
| History | 59666.67 |
Like with select the attributes that are allowed in the having clause are either present in the group by clause, it is the attribute that is being aggregated.
Can be understood roughly as:
from is evaluated to get a relationwhere predicate is applied on each tupel to get a new relationgroup by clause are placed into groups.having clause applied to each group, the ones that satisfy it are retianed to obtain a new relationselect clause is applied to the relation to obtain the resulting relation.A query with both where and having:
tot_cred) of all students enrolled in the section, if the section has at least 2 students:select t.course_id, t.sec_id, t.semester, avg(s.tot_cred)
from takes t, student s
where t.student_id = s.id
and t."year" = 2017
group by course_id, sec_id, semester
having count(s.id) > 1;| course_id | sec_id | semester | avg |
|---|---|---|---|
| CS-101 | 1 | Fall | 65 |
| CS-190 | 2 | Spring | 43 |
| CS-347 | 1 | Fall | 67 |
All aggregate functions except of count(*) ignore null values
some() can be applied to an aggregate consisting of boolean values to compute the disjunction of these valuesevery() can be applied to an aggregate consisting of boolean values to compute the conjunction of the values:select every(a)
from (
values
(true),
(true)
) r(a)| every |
|---|
| TRUE |
Nested subqueries are used for:
[not] inwhere clauseQueries can be nested in the
where clausefrom clauseSimple example for a subquery:
-- names of departments and the average pay
-- where average pay in that department is above the overall average pay
select dept_name, avg(i.salary) as avg_dep_pay
from instructor i
group by i.dept_name
having avg(i.salary) > (
select avg(i2.salary)
from instructor i2
)
order by avg(i.salary) desc| dept_name | avg_dep_pay |
|---|---|
| Physics | 91000.00 |
| Finance | 85000.00 |
| Elec. Eng. | 80000.00 |
| Comp. Sci. | 77333.33 |
Reconsider the queries
Previously we used set operations. Now we can use in:
select distinct s.course_id
from "section" s
where s.semester = 'Fall' and s."year" = 2017
and s.course_id in (
select s.course_id
from "section" s
where s.semester = 'Spring' and s."year" = 2018
)| course_id |
|---|
| CS-101 |
select distinct s.course_id
from "section" s
where s.semester = 'Fall' and s."year" = 2017
and s.course_id not in (
select s.course_id
from "section" s
where s.semester = 'Spring' and s."year" = 2018
)| course_id |
|---|
| CS-347 |
| PHY-101 |
where
select course_id
from section
where semester = 'Spring' and year = 2018is a nested subquery.
distinct is used since set operations remove duplicates by default.
[not] in can be used on enumerated sets:
select distinct name
from instructor i
where name not in ('Mozart', 'Einstein')| name |
|---|
| Singh |
| Srinivasan |
| Crick |
| Green |
| Brandt |
| Gold |
| Roznicki |
| Califieri |
| Wu |
| Kim |
enumerated sets shouldn’t be confused with tupels
Reconsider the query:
Previously we used the somewhat awkward solution:
select i.name
from instructor i , instructor i2
where i2.dept_name = 'Biology'
and i.salary > i2.salary Now we can express this much more similar to natural language:
select i.name
from instructor i
where i.salary > some(
select salary
from instructor
where dept_name = 'Biology'
)| name |
|---|
| Wu |
| Einstein |
| Gold |
| Katz |
| Singh |
| Brandt |
| Kim |
| Nishimoto |
Contrast:
| with cross product | with set comparison |
|---|---|
|
|
Consider another query:
select i."name"
from instructor i
where i.salary > all (
select salary
from instructor
where dept_name = 'Biology'
)| name |
|---|
| Wu |
| Einstein |
| Gold |
| Katz |
| Singh |
| Brandt |
| Kim |
= some (...) is identical to in (...)<> some (...) is not identical to not in (...)<> all (...) is identical to not in (...)= all(...) is not identical to in (...)select dept_name
from instructor i
group by i.dept_name
having avg(i.salary) >= all (
select avg(salary)
from instructor
group by dept_name
)| dept_name |
|---|
| Physics |
We can test whether a query has any tuples in its result (whether if it’s non-empty) with exists. Reconsider the query
select course_id
from "section" s
where s.semester = 'Fall' and s."year" = 2017
and exists (
select *
from "section" s2
where s2.semester = 'Spring' and s2."year" = 2018
and s.course_id = s2.course_id
)| course_id |
|---|
| CS-101 |
Above a correlation name from the outer querry has been used in the inner querry. This can equivalently be achieved with a usual join operation:
select s.course_id
from "section" s , "section" s2
where s.semester = 'Fall' and s."year" = 2017
and s2.semester = 'Spring' and s2."year" = 2018
and s.course_id = s2.course_id Non-existence can be queried with not exists. For example we can use it to simulate set containment.
\[ B \subseteq A \equiv \texttt{not exists (B except A)} \]
select s.id, s."name"
from student s
where not exists (
(select c.id
from course c
where c.dept_name = 'Biology')
except
(select t.course_id
from takes t
where s.id = t.course_id)
)| id | name |
|---|
The subquerry
select c.id
from course c
where c.dept_name = 'Biology'finds all courses offered in the Biology department. The subquerry:
select t.course_id
from takes t
where s.id = t.course_idfinds all courses that the student ‘s’ has taken.
Consider the query:
We can construct this query in three different ways:
select count(distinct t.student_id)
from takes t, teaches t2
where t.course_id = t2.course_id
and t.sec_id = t2.sec_id
and t.semester = t2.semester
and t."year" = t2."year"
and t2.instructor_id = '10101'in with a tuple instead of a single attributeselect count(distinct t.student_id)
from takes t
where (t.course_id, t.sec_id, t.semester, t."year") in (
select t2.course_id , t2.sec_id , t2.semester , t2."year"
from teaches t2
where t2.instructor_id = '10101'
)exists constructselect count(distinct t.student_id)
from takes t
where exists (
select t2.course_id , t2.sec_id , t2.semester , t2."year"
from teaches t2
where t.course_id = t2.course_id
and t.sec_id = t2.sec_id
and t.semester = t2.semester
and t."year" = t2."year"
and t2.instructor_id = '10101'
)| count |
|---|
| 6 |
Testing if subquery has duplicate tuples with unique:
select c.id
from course c
where unique (
select
from "section" s
where c.id = s.course_id
and s."year" = 2017
)Since unique not implemented in Postgresql, we can simulate it as follows:
select c.id
from course c
where 1 >= (
select count(s.course_id)
from "section" s
where s."year" = 2017
and c.id = s.course_id
)| id |
|---|
| BIO-101 |
| BIO-301 |
| BIO-399 |
| CS-101 |
| CS-315 |
| CS-319 |
| CS-347 |
| EE-181 |
| FIN-201 |
| HIS-351 |
(For some reason this delivers a different result than two solutions below. Why?)
Another solution using aggregate functions:
select c.id
from course c , "section" s
where c.id = s.course_id
and s."year" = 2017
group by c.id
having count(*) <= 1| id |
|---|
| BIO-101 |
| CS-101 |
| CS-347 |
| EE-181 |
| PHY-101 |
Yet another far less elegant solution:
select course_id
from "section" s
where s."year" = 2017
except all
select distinct course_id
from "section" s
where s."year" = 2017| course_id |
|---|
| CS-190 |
select distinct course_id
from "section" s
where s."year" = 2017
and course_id not in (
select course_id
from "section" s
where s."year" = 2017
except all
select distinct course_id
from "section" s
where s."year" = 2017
)| course_id |
|---|
| BIO-101 |
| CS-101 |
| CS-347 |
| EE-181 |
| PHY-101 |
Since relations appear in the from clause, there is nothing preventing them being subqueries. Reconsider the query
Previously we solved using group by and having - which is the natural way:
select i.dept_name, avg(i.salary) avg_salary
from instructor i
group by i.dept_name
having avg(i.salary) > 42000We can re-write it without having using subquery in the from clause:
select dept_name, avg_salary
from (
select i.dept_name, avg(i.salary)
from instructor i
group by i.dept_name
) dep_salaries(dept_name, avg_salary) --table alias
where avg_salary > 42000| dept_name | avg_salary |
|---|---|
| Physics | 91000.00 |
| Biology | 72560.00 |
| Elec. Eng. | 80000.00 |
| Finance | 85000.00 |
| Comp. Sci. | 77333.33 |
| History | 59666.67 |
Contrast:
with having |
with nested query in from clause |
|
|
Another example:
select max(tot_sal) as max_tot_sal
from (
select sum(i.salary)
from instructor i
group by i.dept_name
) r(tot_sal) -- table alias| max_tot_sal |
|---|
| 232000 |
Correlation variables are allowed in a from subquery using the lateral keyword.
select i.name, i.salary , i.dept_name, avg_dep_salary
from instructor i , lateral (
select avg(i2.salary)
from instructor i2
where i.dept_name = i2.dept_name
) r(avg_dep_salary)| name | salary | dept_name | avg_dep_salary |
|---|---|---|---|
| Srinivasan | 65000 | Comp. Sci. | 77333.33 |
| Wu | 90000 | Finance | 85000.00 |
| Mozart | 40000 | Music | 40000.00 |
| Einstein | 95000 | Physics | 91000.00 |
| El Said | 60000 | History | 59666.67 |
| Gold | 87000 | Physics | 91000.00 |
| Katz | 75000 | Comp. Sci. | 77333.33 |
| Califieri | 62000 | History | 59666.67 |
| Singh | 80000 | Finance | 85000.00 |
| Crick | 72000 | Biology | 72560.00 |
Defines temporary relations whose definition is available only in the query in which with clause occurs.
with max_budget(value) as (
select max(d.budget)
from department d
)
select d."name" , d.budget as budget
from department d, max_budget mb
where d.budget = mb.value | name | budget |
|---|---|
| Finance | 120000 |
Alternatively we can use nested subquerries in the with clause or in the from clause:
where clause:select d."name" , d.budget
from department d
where d.budget = (
select max(d2.budget)
from department d2
)all with a where-clause subquery:select d.name, d.budget
from department d
where d.budget >= all (
select budget
from department d2
)from-clause subquery:select d.name, d.budget
from department d, (
select max(d2.budget)
from department d2
) bd(val)
where d.budget = bd.valUsing with improves readability. Consider another example:
with dep_tot_salary(d_name, t_salary) as (
select i.dept_name, sum(i.salary)
from instructor i
group by i.dept_name
)
select *
from dep_tot_salary
where t_salary > (
select avg(t_salary)
from dep_tot_salary
)| d_name | t_salary |
|---|---|
| Physics | 182000 |
| Finance | 170000 |
| Comp. Sci. | 232000 |
| History | 179000 |
Queries returning one single tuple with one attribute are called scalar. Such queries can be used in place of values as scalar subquerries, even in select-clause:
select d."name" ,
( -- scalare unteranfragen duerfen innerhalb select eingesetzt werden
select count(*)
from instructor i
where d."name" = i.dept_name --d is a correlatin variable
) cnt
from department d
order by cnt desc| name | cnt |
|---|---|
| History | 3 |
| Comp. Sci. | 3 |
| Finance | 2 |
| Biology | 2 |
| Physics | 2 |
| Music | 2 |
| Elec. Eng. | 1 |
Of course this can simply be achieved with grouping:
select i.dept_name , count(*)
from instructor i
group by i.dept_name
order by count(*) desc| dept_name | count |
|---|---|
| History | 3 |
| Comp. Sci. | 3 |
| Physics | 2 |
| Finance | 2 |
| Biology | 2 |
| Music | 2 |
| Elec. Eng. | 1 |
Alternatively as subquery of from with lateral:
select d."name", res.val as cnt
from department d , lateral (
select count(*)
from instructor i
where i.dept_name = d."name"
) res(val)
order by cnt descScalar subqueries can occur in select, where and having clauses.
valuesvalues
(1, 'a'),
(2, 'b')| column1 | column2 |
|---|---|
| 1 | a |
| 2 | b |
selectselect
(1), ('a')
union all
select
(2), ('b')| ?column? | ?column?..2 |
|---|---|
| 1 | a |
| 2 | b |
insert into Rdelete from Rupdate R setinfromation from the database as opposed to querying.
Expressed just like a query,
delete from r -- relation
where P -- predicatedelete from instructor;or equivalently
delete from instructor
where trueThe predicate can be arbitrarily complex,
delete from instructor
where dept_name in (
select dept_name
from department
where building = 'Watson'
)delete deletes tupels from a single relation, but we can still reference any number of relations nested in select, from and where, including the one that we are deleting from. Consider:
delete from instructor
where salary < (
select avg(salary)
from instructor
)delete from instructor i
where i.id not in (
select t.instructor_id
from teaches t
where t."year" = 2018
)above a relation other than the one being deleted was referenced in the nested subquery in the where clause, demonstrating we can reference arbitrary relations.
deletions are performed after the tupels are filtered (the ones that pass the test). Otherwise the result could be influenced.
Any query result delivering a collection of tuples can be inserted into a relation, as long as they agree with the cardinality and domains of the attributes of the relation:
values:insert into course
values
('CS-437', 'Database Systems', 'Comp. Sci.', 4),
('PHY-201', 'Intro. Theo. Phys.', 'Physics', 6)select:insert into course
select
('CS-437'), ('Database Systems'), ('Comp. Sci.'), (4)
union
select
('PHY-201'), ('Intro. Theo. Phys.'), ('Physics'), (6)insert into course(title, id, credits, dept_name)
values ('Database Systems', 'CS-437', 4, 'Comp. Sci.')null):insert into course (title, id)
values ('Baking Cakes', 'BK-101')Above dept_name and credit are set automatically as null.
More generally, results of an arbitary query can be inserted as well. Consider:
insert into instructor
select s.id, s."name", s.dept_name, 18000
from student s
where s.dept_name = 'Music' and tot_cred > 144;insert into s
select *
from sImportantly in the above example:
insert into s
select *
from sthe query is evaluated before the insertion is performed. Otherwise we could face infinite loops. Also note that this operation is only possible if the relation s has no primary key defined. Otherwise duplicates are not allowed.
Changing some values of tuples is possible with update. Consider:
update instructor
set salary = salary * 1.05update instructor
set salary = salary * 1.05
where salary < 70000Nested subqueries are allowed in the where clause, referencing the relation being updated or other arbitrary relations. Consider:
update instructor
set salary = salary * 1.05
where salary < (
select avg(salary)
from instructor
)update instructor i
set i.salary = i.salary * 1.05
where 1 < (
select count(*)
from teaches t
where t.instructor_id = i.id
and t."year" = 2018
)One solution is to write to update statements:
update instructor
set salary = salary * 1.03
where salary > 100000update instructor
set salary = salary * 1.05
where salary <= 100000in the above solution the order of statements is important, otherwise we could end up giving a 8% raise to instructors whose salary is 100000 or just below it.
Alternatively use case statement. Then the order won’t be important.
update instructor
set salary =
case
when salary <= 100000 then salary * 1.05
else salary * 1.03
end General syntax of case statement:
case
when P1 then res1 -- P1 is a predicate
when P2 then res2
...
when Pn then res_n
else res0
endsince case statement is an expression that is evaluated to a value, it can be used any place where a value is used.
Complex subqueries can follow after set clause:
null)update student
set tot_cred = (
select sum(c.credits)
from takes t, course c
where t.course_id = c.id
and t.student_id = student.id
and t.grade is not null
and t.grade not like 'F'
)For student that haven’t successfully completed a course, total credit will be set to null. Instead we may set it to 0 using case:
update student
set tot_cred = (
case
when select sum(c.credits) is not null then sum(credits)
else 0
from takes t, course c
where t.course_id = c.id
and t.student_id = student.id
and t.grade is not null
and t.grade not like 'F'
)Equivalently, this can be ahieved by coalesce provided by some DBs.
update student
set tot_cred = (
select coalesce(sum(c.credits), 0)
from takes t, course c
where t.course_id = c.id
and t.student_id = student.id
and t.grade is not null
and t.grade not like 'F'
)where coalesce(x, y) evaluates to x, if x is not null, and to y otherwise.