- •СОДЕРЖАНИЕ
- •1.1. Эволюция технологии программирования
- •1.2. Сущность технологии объектно-ориентированного программирования
- •1.3. Использование объектных моделей при организации удаленных соединений
- •2.1. Классификация объектов БД
- •2.2. Свойства и особенности элементов языка
- •2.3. Создание и удаление баз данных
- •2.4. Создание и модификация таблиц баз данных
- •ЛЕКЦИЯ 3.
- •РАБОТА С ДАННЫМИ В ЯЗЫКЕ TRANSACT-SQL
- •3.2. Создание
- •3.3. Команды манипуляции данными
- •4.1. Стандарты синтаксиса Transact-SQL
- •4.3. Курсоры
- •5.1. Разграничение прав доступа
- •5.3. Пользователи
- •5.6. Командные манипуляции с БД
- •5.7. Связанные и удаленные серверы
- •СПИСОК РЕКОМЕНДУЕМОЙ ЛИТЕРАТУРЫ
- •ЛАБОРАТОРНАЯ РАБОТА № 3. ГЕНЕРИРОВАНИЕ ОТЧЕТОВ
- •ЛАБОРАТОРНАЯ РАБОТА № 4. УДАЛЕННОЕ СОЕДИНЕНИЕ С БД INTERBASE НА ОСНОВЕ BDE
- •ЛАБОРАТОРНАЯ РАБОТА № 5. РАБОТА С КОМПОНЕНТАМИ MICROSOFT SQL SERVER
- •САМОСТОЯТЕЛЬНАЯ РАБОТА:
- •ЛАБОРАТОРНАЯ РАБОТА № 6. КОМАНДЫ СОЗДАНИЯ, МОДИФИКАЦИИ И УДАЛЕНИЯ ТАБЛИЦ
ЛЕКЦИЯ 3.
РАБОТА С ДАННЫМИ В ЯЗЫКЕ TRANSACT-SQL
На предыдущей лекции были рассмотрены вопросы создания хранилищ данных, а именно команды языка Transact - SQL, позволяющие создавать базу данных и физические таблицы. Однако без данных база данных не имеет смыс ла, а данные существуют для того, чтобы когда-либо их просматривать и исполь зовать для принятия решений. Поэтому основной задачей текущего занятая яв ляется изучение возможностей команд языка TransactSQL, позволяющие полу чать данные из базы, записывать новые данные в базу и изменять их.
Работа команд языка Transact - SQL будет рассмотрена применительно к базе данных BD_work_people, в которой структурирована информация отно сительно нескольких работников, их месте работы и результатов производствен ной деятельности по выпуску нескольких наименований продукции. С целью исключения аномальных ситуаций, могущих возникнуть при выполнении ко манд манипулирования данными, информация размещена в нескольких физи ческих таблицах, связанных друг с другом с помощью механизма «первичный - внешний ключ». Структурная схема БД представлена на рис. 3.1.
Рис. 3.1. Структурная схема (ER - диаграмма) базы данных BD_work_people
Анализ данной базы данных и содержимого физических таблиц, представ ленных на рис. 3.2, показывает, что с большой степенью определенности можно утверждать, что база данных BD_work_people приведена к третьей нормальной форме. Целостность данных в ней поддерживается посредством использования специальных полей (первичных и внешних ключей) и специальных объектов, связей, в качестве которых выступают поименованные ограничения.
В каждой физической таблице первичные ключи имеют обозначения id, обозначения внешних ключей начинается с id_, а далее указывается на звание родительской таблицы. Тип данных первичных и внешних ключей
одинаковый: integer. Атрибуты полей: Fam, Podrazd, Kateg, предназначенные для хранения данных о фамилии работника, его места работы и наимено вании выпускаемой продукции, имеют символьный тип данных - varchar. Атрибуты полей Obem, Cena, Brak используются для хранения данных о объеме выработке работника, стоимости единицы продукции и величине брака и имеют числовой тип данных - decimal, а поля Datar, Dataw, предна значенные для хранения информации о дате рождения работников и дате их работы, имеют тип данных smalldatetime.
Основными командами, предназначенными для работы с данными в язы ке Transact - SQL, являются оператор выборки Select, оператор вставки новых записей Insert, оператор обновления данных Update и оператор удаления уста ревших записей Delete.
И |
_ |
. |
. |
jj |
T _ p o d r a z d |
||
f |
id |
|
1Podrazd |
|
|
||
L t |
1 |
|
Цех №71 |
|
2 |
|
Цех №73 |
r
h |
i |
i ^ P e o p l e |
|
|
|
|
i |
|
|
||
В |
i |
Id |
l ram |
1иасаг |
на доагага |
|
|||||
|
|
||||
1’ |
|
► u — |
Г ришин |
03.05.1976 |
1 |
|
|
2 |
Иванов |
17.04.1981 |
2 |
|
|
3 |
Климов |
13.01.1972 |
1 |
|
|
4 |
Петров |
06.04.1983 |
2 |
|
|
5 |
Сидоров |
07.03.1975 |
2 |
|
T W |
o r k |
|
|
|
|
|
|
id |
1id kateg |
lid |
Dataw lid people |
lObem |
Ice n a |
1Brak |
1 |
1 |
1 |
1 |
1 |
10 |
200,25 |
2 |
|
2 |
1 |
1 |
3 |
9 |
200,25 |
0 |
|
3 |
2 |
1 |
2 |
3,5 |
458,44 |
0,5 |
|
4 |
3 |
1 |
4 |
7 |
356,78 |
1 |
|
5 |
3 |
1 |
5 |
б |
358,78 |
1 |
|
6 |
1 |
> |
1 |
11 |
220,04 |
3 |
|
> |
||||||
|
7 |
2 |
2 |
4 |
460,57 |
0 |
|
|
> |
||||||
|
8 |
3 |
5 |
8 |
356,78 |
2 |
|
|
) |
||||||
|
9 |
1 |
1 |
12 |
220,04 |
0 |
|
|
10 |
1 |
2 |
1 |
10 |
220,04 |
2 |
|
2J |
||||||
|
11 |
3 |
5 |
7 |
358,78 |
0 |
|
|
____ „______ |
__ |
_____ ________ |
|
|
______ _________ |
|
T Kateg |
|
• |
— |
■ ----------------- Й |
|||
! |
|| |
! T_Dataw |
|
jl |
||||
|
|
id |
|Kateg |
I : |
j |
id |
|Dataw |
1! |
! |
► |
1 |
Подш ипник |
j |
Ц_ 1 |
21.01.2008 |
| |
|
|
|
2 |
Вал |
; |
r z |
2 |
23.01.2008 |
! |
У___ |
3 |
Ц и ли н др |
j |
t = |
3 |
25.01.2008 |
1 |
Рис. 3.2. Физические таблицы базы данныхBD_work_people
3.1. Особенности использования оператора SELECT
Оператор выборки предназначен для получения данных от сервера, при чем данные могут выбираться из одной или нескольких связанных таблиц. В упрощенном виде синтаксис данного оператора представлен ниже:
SELECT список полей [INTO новая таблица] FROM перечень таблиц
[W HERE условия фильтрации]
[G RO UP BY выражение группировки] [HAVING фильтрация групп]
[O RDER BY сортировка результата выборки]
Рассмотрим особенности использования этого оператора на нескольких типовых примерах.
На рис. 3.3 представлено два варианта решения задачи, связанной с определением среднего возраста работников подразделений, указанных в базе данных.
Определить средний возраст работников каждого подразделения Вариант № 1
Select p.Podrazd as 'Подразделение', avg(datediff(year,pe.datar,getdateO)) as 'Средний возраст'
From T_podrazd p,t_People pe where p.id=pe.id_podrazd Group by p.Podrazd
Вариант № 2
Select p.Podrazd as 'Подразделение',
(select avg(datediff(year,pe.datar,getdate())) fronyl t_People pe ( where p.id=pe.id_podrazd) as 'Средний возраст'N from t_Podrazd p
£ |
Подразделение |
Средний возраст |
|
| Цех |
№71 |
34 |
|
2 |
Цех |
№73 |
28 |
£ |
Подразделение |
Средний возраст |
|
Цех |
№71 |
34 |
|
2 |
Цех |
№73 |
28 |
Рис. 3.3. Оптимизация запроса группировки данных
Первый вариант является классическим и предполагает использования оператора Group By, который обеспечивает группировку записей по полю Podrazd. После оператора Select нужно перечислить имя колонки и мате матическую функцию Avg, обеспечивающую подсчет среднего значения. Для вычисления возраста в качестве аргумента функция Avg используется встроенная функция datediff, которая возвращает разницу в годах year меж ду текущей датой getdate() и датой рождения работника datar. Для большей наглядности результата в запросе используются псевдонимы полей «Подраз деление» и «Средний возраст», которые не изменяют имена полей в базе, а влияют только на результирующую таблицу. Поскольку выбираемая инфор мация хранится в разных таблицах, имена таблиц и их псевдонимы перечис ляются после ключевого слова From, а после предиката where указывается
логическое высказывание, определяющее условие естественного соедине ния данных из таблиц, участвующих в выборке данных. Запрос выполня ется за несколько шагов. Первоначально производится соединение данных из таблиц, источников информации. Для этого используется условие, запи санное после слова where. Затем выполняется разбивка записей, попавших в выборку на группы, то есть сортировка данных по полю Podrazd, и только после этого - применение к каждой группе математической функции Avg.
Количество шагов запроса можно сократить, если применить второй вариант, представленный на рис. 3.4. При этом варианте не используется явная групповая операция, а принимается во внимание тот факт, что при ведение базы данных к третьей нормальной форме автоматически структу рирует информацию должным образом. Поэтому если запомнить значение ключа id таблицы TPodrazd внешнего запроса и по маске р передавать это значение в подзапрос, то для каждой текущей записи внешнего запроса мож но в родительской таблице T People выделять только одну группу, к которой и применять агрегатную функцию. Таким образом, схема выполнения запро са второго варианта исключает два первых шага схемы выполнения запроса первого варианта, следовательно, такой запрос будет выполняться быстрее.
Определить подразделение, работники которого имеют: Вариант № 1 (наибольший средний возраст)
select top 1 p.Podrazd as 'Подразделение',
(select avg(datediff(year,pe.datar,getdateO)) from tP eople pe
where p.id=pe.id_podrazd) a s' Средний возраст'
from tPodrazd p order by 2 desc Вариант № 2
(наименьший средний возраст)
select top 1 p.Podrazd as 'Подразделение', (select avg(datediff(year,pe.datar,getdate())) from t People pe
where p.id=pe.id_podrazd) as 'Средний возраст’
П одразделение |
Средний в озр аст |
Цех №71 |
34 |
П одразделение |
Средний в озр аст |
Цех №73 |
28 |
Рис. 3.4. Поиск максимумов или минимумов
На рис. 3.5 представлены примеры, поясняющие способ фильтрации записей, содержащих информацию о подразделении, в котором работники имеют наибольший или наименьший средний возраст.
Данная задача может быть решена на основе схемы запроса варианта 2 рис. 3.4, если результат выполнения последнего отсортировать в поряд ке убывания возраста, используя директиву order by 2 desc, или в порядке
возрастания возраста, используя order by 2. А затем к тому, что получилось, применить функцию top 1, которая обеспечивает выбор первой записи ре зультата.
На рис. 3.5 представлена схема запроса по определению возраста ста рейших работников каждого подразделения. Эта схема предполагает ис пользование в предикате where подзапроса, обеспечивающего нахождение значения максимального возраста по подразделению, которое определяется полем id и маской р внешнего запроса. В итоге именно этот параметр пере дается в подзапрос и обеспечивает правильную связь результата выполне ния подзапроса с лицом указанном во внешнем запросе на очередном шаге его выполнения.
Замечательной особенностью языка Transact-SQL является то, что по маске можно в подзапрос передать значение любого поля таблицы, даже того, которое не присутствует при выполнении операции проекции. Приме нительно к данному случаю поля p.id, которое и используется для организа ции условия фильтрации p.id=pp.id подзапроса. В результате подзапрос яв ляется зависимым и будет выполняться при отборе каждой внешней записи, то есть столько раз, сколько записей образуется после выполнения операции естественного соединения данных таблиц, участвующих в запросе.
Определить в каждом подразделении фамилию и возраст старейших работников
select p.Podrazd as 'Подразделение',pex.Fam as 'Фамилия',
datediff(year,pex.datar,getdateO) as 'Возраст' from tPodrazd p,t_people pex
where p.id=pex.id_podrazd and
datediff(year,pex.datar,getdateO)=
(select max(datediff(year,ppex.datar,getdateO)) from t Podrazd pp,t_people ppex
where pp.id=ppex.id_podrazd and p.id=pp.id)
|
|
|
|
г? * |
|
Подразделение Фамилия В озраст |
|||
1 |
Цех |
№71 |
Климов |
3 6 |
2 |
Цех |
№73 |
Сидоров 33 |
|
Рис. 3.5. Использование подзапроса в предикате Where |
||||
На рис. 3.7 представлен |
SQL-код |
запроса, отвечающий на вопрос |
о количестве работников, задействованных в изготовлении соответствующих единиц продукции.
Сколько работников задействованы в изготовлении каждой единицы продукции?
select k.kateg,(select count(distinct w.idjpeople) from tw ork w
where k.id=w.id_kateg)as 'Количество работников' From T kateg k
|
k a teg |
Количество работников |
1 |
Подшипник 2 |
|
2 |
Вал |
1 |
3 |
Цилиндр |
2 |
Рис. 3.6. Использование зависимого подзапроса в секции SELECT
Схема запроса предполагает использование в секции SELECT зависимого подзапроса, обеспечивающего подсчет количества работников, занятых изготовленем одной и той же продукции. Это достигается посредством примене ния агрегатной функции count с аргументом distinct w.id_people, исключающим дубликаты, и использованием поля id таблицы T_kateg, значения которого пе редаются в подзапрос через маску к.
На рис. 3.7 представлен SQL-код запроса, отвечающий на вопрос о количестве работников, задействованных в изготовлении соответствующих единиц продукции и их суммарной стоимости.
Для каждой единицы продукции определить суммарную стоимость и количество человек, занятых в ее изготовлении
select * From
(select k.Kateg,
cast(convert(decimal(10,2),sum(w.obem*w.cena)) as varchar(15))+' руб' as 'Сумма' from T_kateg k, Twork w
where k.id=w.id_kateg Group by k.Kateg) x l,
(select kk.Kateg,count(distinct ww.id_people) as 'Кол человек'
from T_kateg kk, T_work ww |
|
|
|
|
|
|
where kk.id=ww.id_kateg |
|
|
|
|
|
|
group by kk.Kateg) x2 |
|
|
\ |
^ |
|
|
Where xl.Kateg=x2.Kateg |
|
| |
|
^ |
|
|
|
K ateg |
Сумма |
|
K ateg |
Кол человек |
|
1 |
Вал |
3 4 4 6 |
.8 2 |
руб |
Вал |
1 |
2 |
Подшипник 1 1 0 6 6 .0 7 руб |
Подшипник |
2 |
|||
13 |
Цилиндр |
1 0 7 3 |
3 .4 0 |
руб |
Цилиндр |
2 |
Рис. 3.7. Использование подзапросов в секции FROM
Примечательной особенностью данного запроса является то, что в сек ции FROM вместо указания таблиц представлены запросы, подсчитываю щие суммарную стоимость и количество человек, задействованных для из готовления соответствующей категории продукции. Причем при подсчете стоимости с помощью функции convert производится округление результата до двух знаков после запятой - тип decimal(10,2), а затем его преобразование к символьному типу varchar с последующим сцеплением с символьной кон стантой ‘руб’. Для каждого подзапроса указывается псевдоним х1 и х2. Вне шний объединяющий запрос связывает обе полученные таблицы, используя условие xl.Kateg=x2.Kateg. Для таких запросов есть только одно ограниче ние - у каждого поля подзапросов секции FROM должно быть имя.
На рис. 3.9 представлен запрос, обеспечивающий подсчет суммарной сто имости продукции, выпущенной каждым работником 25.01.2008. В этот день трудились не все работники. Поэтому если в предикате WHERE записать ус ловие естественного соединения данных из таблиц, участвующих в выборке p.id=w.id_people, то запрос вернет только две записи. Использование естест венного объединения со знаком равенства называется внутренним объедине нием. Чтобы увидеть записи, которые не связаны, нужно использовать внешнее объединение, которое бывает левым или правым. В запросе на рис. 3.8 исполь зовано левое внешнее объединение данных, для чего слева от знака равенства в условии p.id*=w.id_people стоит знак «*».
Определить сумму произведенных деталей каждым работником 25.01.2008
|
|
1 |
select p.Fam, |
А—----12 |
|
cast(convert(decimal(10,2), |
V —---- 3 |
|
sum(w.obem*w.cena)) as varchar(15))+' руб' as 'Сумма' |
4 |
from T_people p,T_work w |
5 |
|
where p.id*=w.id_people |
||
|
||
and w.id_dataw=3 |
|
|
Group by p.Fam |
|
|Fam |
Сумма |
|
|
Гришин |
4 8 4 0 .8 8 |
руб |
|
Иванов |
NULL |
|
|
Климов |
NULL |
|
|
Петров |
NULL |
|
|
Сидоров 2 5 1 1 |
.4 6 |
руб |
. p r
Рис. 3.8. Использование явного левого (внешнего) объединения данных
На рис. 3.9 представлен запрос, обеспечивающий подсчет смен, который отработал каждый работник 25.01.2008.
Схема выполнения запроса предполагает использование информации из трех таблиц T People p,t_work w,t_dataw d, где p, w, d - маски таблиц, при чем условие d.dataw= convert(smalldatetime,’25.01.2008’,104) означает выборку данных, относящихся только к дате 25.01.2008. Для выборки данных, отно сящихся к этой дате, символьная константа ’25.01.2008’ с помощью функции convert преобразуется к типу smalldatetime, а константа 104 обеспечивает со гласование с германским форматом даты - ‘дд.мм.гпт.’
Определить,сколько смен отработано
каждым работником 25.01.2008
Вариант № 1
select p.Fam,count(w.id) as 'Количество смен' From T_People p,t_work w,t_dataw d
where p.id=w.id_people and d.id=w.id_dataw
and d.dataw=convert(smalldatetime,'25.01.2008',104)
group by p.Fam |
|
Вариант № 2 |
|
select p.Fam,(select count(w.id) |
и |
from twork w,t_dataw d |
< |
where p.id=w.id_people and d.id=w.id_dataw N
and d.dataw=convert(smalldatetime,'25.01.2008',104) )as 'Количество смен'
From T_People p Вариант № 3 select p.Fam,
(select case count(w.id) when 1 then
'1-я смена' when 2 then '2-е смены' else
'сегодня отдыхал' end
from t work w,t_dataw d
where p.id=w.id_people and d.id=w.id_dataw
and d.dataw=convert(smalldatetime,'25.01.2008',104) )as 'Количество смен'
From TPeople p
|
|Fain_____ Количество сиен |
1 |
.Гришин 2 |
2 |
Сидоров 1 |
|Fain_____ Количество сиен 1___Гришин 2
2Иванов О
3Климов О
4Петров О
5Сидоров1
Таш |
Количество смен |
1 Гришин |
2 -е смены |
2Иванов сегодн я отдыхал
3Климов сегодня отдыхал
4Петров сегодня отдыхал
5Сидоров 1 -а смена
Рис. 3.9. Использование неявного левого объединения данных и функции CASE
Первый вариант запроса описывает условие внутреннего (жесткого) объ единения данных. Второй и третий, посредством использования подзапроса в секции SELECT, обеспечивают внешнее (левое) объединение данных. Кроме того, в третьем варианте использована функция Case, которая в зависимости от результата возвращаемого функцией count подзапроса отобранные записи снаб жает соответствующим комментарием.
На рис. 3.10 представлен запрос, обеспечивающий подсчет статистики ра ботников, родившихся зимой и весной.
Данный запрос является перекрестным. Источником строк его являет ся поле Podrazd, а источником столбцов —данные, возвращаемые подзапроса ми с псевдонимами «Зимой» и «Весной», которые описаны в секции SELECT. Для фильтрации данных, относящихся к определенному периоду, использована функция Datepart, возвращающая при обработке данных поля datar номер меся ца. Фильтрация зимних месяцев производится функцией in (12,1,2), а весенних - функцией between 3 and 5. Связь данных внешнего запроса с данными подза просов производится через маску р таблицы t Podrazd по полю id.
Определить для каждого подразделения количество работников, родившихся зимой и весной (перекрестный запрос)
select p.Podrazd as 'Подразделение', (select count(pe.id) from t_People pe where p.id=pe.id_podrazd and
(datepart(month,pe.datar) in(12,l,2))) as 'Зимой', (select count(pee.id) from tJPeople pee
where p.id=pee.id_podrazd and (datepart(month,pee.datar) between 3 and 5)) as 'Весной' from t_Podrazd p
[подразделение Зимой Весной
1__ Цех |
№71 |
1 |
1 |
2__ ; Цех |
№73 |
О |
3 |
Рис. 3.10. Перекрестный запроси функция datepart
На рис. 3.11 представлен запрос, обеспечивающий подсчет суммарной стоимости каждой единицы выпущенной продукции.
Определить для каждого подразделения суммарную стоимость каждой единицы выпущенной продукции (перекрестный запрос)
select p.Podrazd as |
'Подразделение', |
|
|
|
(select sum((w.obem |
-w.brak)*w.cena) from t_People pe,t_work w,t_kateg k |
|||
where p.id=pe.id_podrazd and |
|
|
|
|
pe.id=w.id_people and |
|
|
|
|
k.id=w.id_kateg and |
|
|
|
|
k.Kateg Like'% |
цил%') as12Цилиндр ', |
|
|
|
(select sum((w.obem |
-w.brak)*w.cena) from t_People pe,t_work w,t_kateg k |
|||
where p.id=pe.id_podrazd and |
|
|
|
|
pe.id=w.idjpeople and |
|
|
|
|
k.id=w.id_kateg and |
|
|
|
|
k.Kateg Like'% |
вал%') as' Вал', |
|
|
|
(select sum((w.obem |
-w.brak)*w.cena) from t_People pe,t_work w,t_kateg k |
|||
where p.id=pe.id_podrazd and |
|
|
|
|
pe.id=w.id_people and |
|
|
|
|
k.id=w.id_kateg and |
|
|
|
|
k.Kateg Like'% |
подш %') as' Подшипник ' |
|
|
|
from t_Podrazd p |
|
.— |
— |
|
|
Подразделение Цилиндр |
Вал |
Подшипник |
|
1 |
Цех №71 |
NULL |
NULL |
9565.37D 00 |
2 |
Цех №73 |
9304 .28000 3217 .60000 |
NULL |
Рис. 3.11. Перекрестный запрос и функция Like