699
.pdf,hD,slr,title, count(c.Memberof) as Member-ship,count(c.manages) as projects FROM Manager c
--SELECT fnm,lnm,BDt,cmt,age,gnd,adrs,eml,ppth,clgr
,hD,slr,title,count(c.spouse) |
as |
|
Spouse,count(c.children) |
|
as |
Children,count(c.Memberof) |
as |
as |
Membership,count(edocs) |
Docu- |
|
ments,count(c.manages) |
|
as |
Projects,count(team) as |
Team,count(cabs) |
|
as Cabinets,count(priemm) |
as |
Receptions |
FROM Manager c |
|
|
--SELECT |
|
|
fnm,lnm,BDt,cmt,age,gnd,adrs,eml,ppth,clgr
,hD,slr,title,count(c.spouse) |
as |
||
Spouse,count(c.children) |
|
as |
|
Children,count(c.Memberof) |
as |
as |
|
Membership,count(edocs) |
Docu- |
||
ments,count(c.manages) |
|
as |
|
Projects,count(team) as |
Team,count(cabs) |
||
as |
Cabinets,count(Direct) |
as |
|
DirectMovie,count(priemm) |
as |
Receptions |
|
FROM MovieDirector c |
|
|
|
|
--SELECT |
|
|
fnm,lnm,BDt,cmt,age,gnd,adrs,eml,ppth,clgr
,hD,slr,title,count(c.spouse) |
|
as |
Spouse,count(c.children) |
|
as |
Children,count(c.Memberof) |
as |
as |
Membership,count(edocs) |
Docu- |
|
ments,count(c.manages) |
|
as |
Projects,count(team) as Team,count(cabs) |
||
as Cabinets,count(priemm)as |
|
Receptions, |
count(patients) as Patients FROM Doctor c --SELECT
fnm,lnm,BDt,cmt,age,gnd,adrs,eml,ppth,clgr
,hD,slr,count(c.spouse) |
as |
171 |
|
Spouse,count(c.children) as Children,count(c.Memberof) as Membership,count(c.WorksIn) as Projects,count(c.reportsto) as Reportsto,count(priemp)as Receptions,count(edocs) as Documents, count(assistantof) as Assistantof FROM Employee c
--SELECT fnm,lnm,BDt,cmt,age,gnd,adrs,eml,ppth,clgr ,hD,slr,count(c.spouse) as Spouse,count(c.children) as Children,count(c.Memberof) as Membership,count(c.WorksIn) as Projects,count(c.reportsto) as Reportsto,count(priemp)as Receptions,count(edocs) as Documents,count(c.Biography) as Biography, count(assistantof) as Assistantof FROM Artist c
SELECT fnm,lnm,BDt,cmt,age,gnd,adrs,eml,ppth,clgr ,hD,slr,count(c.spouse) as Spouse,count(c.children) as Children,count(c.Memberof) as Membership,count(c.WorksIn) as Projects,count(c.reportsto) as Reportsto,count(priemp)as Receptions,count(edocs) as Documents,count(c.Doctors) as Doctors, count(assistantof) as Assistantof FROM Patient c
2.21. Вложенные запросы
Предикат с квантором имеет следующий синтаксис:
<quantified predicate>::= <value expression>
172
<comp op> <quantifier> <subquery> <quantifier>::=
<all> | <some> <all>::= ALL <some>::= SOME | ANY
Обозначим через x результат вычисления арифметического выражения левой части предиката, а через S – результат вычисления подзапроса.
Предикат "x <comp op> ALL S" имеет значение true, если S пусто или значение предиката "x <comp op> s" равно true для каждого s, входящего в S. Предикат "x <comp op> ALL S" имеет значение false, если значение предиката "x <comp op> s" равно false хотя бы для одного s, входящего в S. В остальных случаях значение предиката "x <comp op> ALL S" равно unknown.
Предикат "x <comp op> SOME S" имеет значение false,
если S пусто или значение предиката "x <comp op> s" равно false для каждого s, входящего в S. Предикат "x <comp op> SOMES" имеет значение true, если значение предиката "x <comp op>s" равно true хотя бы для одного s, входящего в S. В остальных случаях значение предиката "x <comp op> SOME S" равно unknown.
Мы можем использовать любые операторы, используемые с ключевым словом WHERE (рассмотрены в под-
разд. 2.19).
Водном запросе может быть несколько подзапросов, синтаксис у такого запроса следующий: SELECT имя_столбца FROM имя_таблицы WHERE часть условия
IN (SELECT имя_столбца FROM имя_таблицы WHERE
часть условия IN (SELECT имя_столбца FROM имя_таблицы WHERE условие));
Впримере указано два запроса, которые выдают один
итот же результат:
173
SELECT name FROM users WHERE id_user IN (SELECT id_author FROM topics WHERE top-ic_name='велосипеды');
SELECT name FROM users WHERE id_user = (SELECT id_author FROM topics WHERE topic_name='велосипеды');.
Предикат exists
Предикат exists имеет следующий синтаксис:
< exists predicate>::= EXISTS <subquery>
Значением этого предиката всегда является true или false, и это значение равно true тогда и только тогда, когда результат вычисления подзапроса не пуст.
Выдать названия поставщиков, поставляющих продукт
с номером 11. |
|
Название |
||
SELECT |
||||
FROM |
Поставщики |
|
|
|
WHERE EXISTS |
|
* |
||
|
( |
SELECT |
||
|
|
FROM |
Поставки |
|
|
|
WHERE ПС = Поставщики.ПС |
||
Система |
|
AND |
ПР = 11 ); |
|
последовательно |
выбирает строки таблицы |
«Поставщики», выделяет из них значения столбцов «Название» и ПС, а затем проверяет, является ли истинным условие существования, т.е. существует ли в таблице «Поставки» хотя бы одна строка со значением ПР = 11 и значением ПС, рав-ным значению ПС, выбранному из таблицы «Поставщики». Если условие выполняется, то полученное значение столбца «Название» включается в результат.
Выдать название и статус поставщиков, не поставляющих продукт с номером 11 [19]:
SELECT Название, Статус FROM Поставщики
174
WHERE NOT EXISTS |
* |
||
( |
SELECT |
||
|
FROM |
Поставки |
|
|
WHERE ПС = Поставщики.ПС |
||
|
AND |
ПР = 11 ); |
Раздел GROUP BY и раздел HAVING
Если в табличном выражении присутствует раздел GROUP BY, то далее выполняется он. Синтаксис раздела GROUP BY следующий:
< group by clause>::=GROUP BY <column specification>[{, <column specification>}...]
Синтаксис раздела HAVING следующий:
<having clause>::=HAVING <search condition>
Результатом выполнения раздела HAVING с GROUP BY является сгруппированная таблица, содержащая только те группы строк, для которых результат вычисления условия поиска есть true. Можно применять агрегатные функ-
ции COUNT, SUM, AVG, MIN и MAX.
Следующий запрос вернет список отделов, в которых работает более одного сотрудника [20]:
SELECT DepartmentName, COUNT(*) FROM employee,department
WHERE employee.DepartmentID = department.DepartmentID
GROUP BY DepartmentName HAVING COUNT(*)>1;
Агрегатные функции и результаты запросов
в стандарте SQL/89 определены пять стандартных агрегатных функций: COUNT – число строк или значений, MAX – максимальное значение, MIN – минимальное значение, SUM – суммарное значение и AVG – среднее значение.
175
Вычисление функции COUNT(*) производится путем подсчета числа строк в заданном множестве. Все строки считаются различными, даже если они состоят из одного столбца со значением null во всех строках.
Если агрегатная функция специфицирована с ключевым словом DISTINCT, то список значений строится из значений указанного столбца. В нем устраняются значениядубликаты [33].
2.22.Запрос с выборкой из нескольких таблиц
Впримере таблицы связываются по полям (внешним и первичным ключам). Ищутся значения «Код группы» и внешний ключ на группу из таблицы «Расписание» и т.д.
Врезультате выдаются только те записи, которые полностью совпадают, т.е. строки, где отсутствует поле (ключ), отбрасываются.
Пример T-Sql
/*Расписание лекций*/
select s.fam 'Фамилия преподавателя', p.pred 'Предмет', e.d1 ' Дата лекции',e.t1 'Время ', g.cgr 'Группа', g.course 'Курс', g.cur 'Куратор'
from Gro g,pred p, rasp e,prep s
where e.cgr=g.cgr and e.Cprep=s.Cprep and e.cpr=p.cpr
order by s.fam
Запрос Кафедра + преподаватель + должность:
select k.kaf 'Кафедра',d.dolj'Должность',s.fam 'Фамилия преподават.'
from prep s,dolj d,kafed k,kaf_prep kp where s.Cprep=kp.Cprep and kp.Ckaf=k.Ckaf and kp.Cdolj=d.Cdl
order by k.kaf, s.fam
176
Пример Oracle
Создайте запрос, который бы возвращал информацию из таблиц employees и jobs схемы hr:
SELECT first_name AS "Имя", last_name As "Фамилия", Job_Title As "Должность", (max_salary - salary) AS "Разница с макси-
мальной"
FROM hr.employees, hr.jobs WHERE (hr.employees.job_id = hr.jobs.JOB_ID) ORDER BY "Разница с максимальной" DESC Результат:
Steven King President 16000
Lex De Haan Administration Vice President 13000 [17]
Объединение нескольких таблиц. Оператор JOIN
Чтобы получить строки из нескольких таблиц, можно использовать оператор JOIN. JOIN – оператор языка SQL, который является реализацией операции соединения реляционной алгебры. Входит в раздел FROM операторов SELECT, UPDATE или DELETE. В большинстве СУБД при указании слов LEFT, RIGHT, FULL слово OUTER можно опустить. Слово INNER также в большинстве СУБД можно опустить. В общем случае СУБД при выполнении соединения проверяет условие (предикат) condition. Для CROSS JOIN условие не указывается [20].
Внутреннее объединение таблиц. Оператор INNER JOIN
Объединения, которые связывают строки одной таблицы со строками другой таблицы (а может, еще и третьей таблицы), называются внутренними объединениями [20].
SELECT * FROM
Person
177
INNER JOIN
City
ON Person.CityId = City.Id
Результат: |
|
|
|
Person.Name |
Person.CityId |
City.Id |
City.Name |
Андрей |
1 |
1 |
Москва |
Леонид |
2 |
2 |
Санкт- |
|
|
|
Петербург |
Сергей |
1 |
1 |
Москва |
Пример для T-SQL
/*Общее кол-во часов для преподавате-
лей s.fam='Ухов'*/ |
|
|
SELECT Cpr,d1,t1,clock,fam |
AS |
e |
FROM prep AS s INNER JOIN Rasp |
||
ON s.Cprep=e.Cprep where s.fam='Ухов' |
|
|
SELECT SUM(e.clock) AS 'Общее кол-во' |
||
FROM prep AS s INNER JOIN Rasp |
AS |
e |
ON s.Cprep=e.Cprep where s.fam='Ухов' |
|
|
Результат запроса «Общее количество часов для преподавателя 24»:
/*Студенты: факультет, группа, форма
обучения, направление */ |
f.fac |
AS |
|||
SELECT |
f.Cfc |
+ |
' ' + |
||
'Факультет', g.Cgr AS |
'Группа', |
g.Course |
|||
AS 'Курс', |
g.Cur |
AS |
'Куратор', |
s.FIO |
AS |
'Студент', s.fact_adr AS 'Фактич. адрес', s.Nstudbil AS 'Студ. билет', s.adr AS 'Адрес', s.tel AS 'Телефон', Fob.fob, napr.napr, f.fac
FROM fac AS f INNER JOIN
Gro AS g ON f.Cfc = g.Cfc INNER JOIN stud AS s ON g.Cgr = s.Cgr INNER
JOIN
Fob ON g.Cu = Fob.Cu INNER JOIN napr ON g.Cna = napr.Cna
178
Внешнее объединение таблиц. Оператор OUTER JOIN
Возможно полное внешнее объединение, которое извлечет все строки из обеих таблиц и свяжет между собой те, которые могут быть связаны. Ключевое слово для полного внешнего объединения – FULL OUTER JOIN.
SELECT * FROM
Person
FULL OUTER JOIN City
ON Person.CityId = City.Id
Результат:
Person.Name |
Person.CityId |
City.Id |
City.Name |
Андрей |
1 |
1 |
Москва |
Сергей |
1 |
1 |
Москва |
Леонид |
2 |
2 |
Санкт- |
|
|
|
Петербург |
NULL |
NULL |
3 |
Казань |
Григорий |
4 |
NULL |
NULL |
LEFT OUTER JOIN
Оператор левого внешнего соединения LEFT OUTER JOIN соединяет две таблицы. Ключевое слово – LEFT OUTER JOIN, указывает, что из таблицы слева надо взять все строки.
SELECT * FROM
Person
LEFT OUTER JOIN City
ON Person.CityId = City.Id
Результат:
Person.Name |
Person.CityId |
City.Id |
City.Name |
Андрей |
1 |
1 |
Москва |
Леонид |
2 |
2 |
Санкт- |
|
179 |
|
|
|
|
1 |
Петербург |
Сергей |
1 |
Москва |
|
Григорий |
4 |
NULL |
NULL |
Запрос для получения всех пользователей и тем, ими созданных. Если пользователь не создавал тему, но в соответствующем столбце стоит значение NULL:
SELECT users.name, topics.topic_name FROM users LEFT OUTER JOIN topics ON
users.id_user=topics.id_author;
RIGHT OUTER JOIN
Оператор правого внешнего соединения RIGHT OUTER JOIN соединяет две таблицы. В запросе будут выбираться все строки из правой таблицы и имеющиеся, связанные с ними из левой таблицы [11, 20].
SELECT * FROM
Person
RIGHT OUTER JOIN City
ON Person.CityId = City.Id
Результат:
Person.Name |
Person.CityId |
City.Id |
City.Name |
Андрей |
1 |
1 |
Москва |
Сергей |
1 |
1 |
Москва |
Леонид |
2 |
2 |
Санкт- |
|
|
|
Петербург |
NULL |
NULL |
3 |
Казань |
CROSS JOIN
Оператор перекрестного соединения, или декартова произведения, CROSS JOIN соединяет две таблицы.
Заголовок таблицы-результата является объединением (конкатенацией) заголовков соединяемых таблиц.
Тело результата логически формируется следующим образом. Каждая строка одной таблицы соединяется с каж-
180