Структура языка SQL

Реализация базового и промежуточного уровней языка SQL, создание SQL-ориентированных СУБД. Конструирование схем баз данных и их визуальные инструменты. Рассмотрение уровней изоляции транзакций. Основные методы реализации уровней изоляции и свойств ACID.

Рубрика Программирование, компьютеры и кибернетика
Вид лекция
Язык русский
Дата добавления 06.03.2012
Размер файла 139,5 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Структура языка SQL

В данной лекции мы начинаем систематически описывать базовые механизмы языка SQL. Чтобы пояснить, о какой части языка пойдет речь в этой и следующих лекциях, обратимся к рис. 11.1.

Рис. 11.1. Один из способов разделения языка SQL на уровни

Язык SQL, соответствующий последним стандартам SQL:2003, SQL:1999 (и даже SQL/92), это очень богатый и сложный язык, все возможности которого трудно сразу осознать и тем более понять. Поэтому приходится разбивать язык на уровни, или слои, такие, что каждый уровень языка включает все конструкции, входящие в более низкие уровни. В стандарте определяется несколько способов разбиения языка на уровни. В одной из классификаций язык разбивается на "базовый" (entry), "промежуточный" (intermediate) и "полный" (full) уровни.

Эта классификация ориентирована, прежде всего, на производителей СУБД, в которых поддерживается SQL. Реализация базового уровня языка является обязательным условием хотя бы какого-то соответствия стандарту. Реализация промежуточного уровня желательна, и обычно именно такой уровень языка поддерживается ведущими компаниями-производителями SQL-ориентированных СУБД. Наконец, полный уровень языка является целью, к достижению которой следует стремиться. В данной классификации критерием отнесения той или иной возможности языка к некоторому уровню является оцениваемая создателями стандарта SQL (большая часть которых является сотрудниками ведущих компаний, производящих SQL-ориентированные СУБД) техническая сложность реализации этой возможности. Конечно, такая классификация важна и для программистов приложений баз данных, но только для того, чтобы оценить реальные возможности конкретной СУБД. Для понимания языка SQL это разбиение на уровни несущественно.

Другая классификация показана на рис. 11.1. Среди всех конструкций языка SQL можно выделить такие конструкции, которые можно было использовать при "прямом" (direct) взаимодействии конечного пользователя с СУБД (например, в интерактивном режиме). В некотором смысле этот уровень также является базовым, поскольку соответствующие средства языка в наибольшей степени отражают его ориентированность на работу с множествами. На следующем уровне, уровне "встраиваемого" (embedded) SQL, язык расширяется конструкциями, позволяющими использовать возможности прямого SQL в программах, написанных на традиционных языках программирования. Наконец, на уровне "динамического" (dynamic) SQL во встраиваемый SQL добавляются конструкции, позволяющие приложениям обращаться к СУБД с конструкциями прямого SQL, которые динамически образуются во время выполнения программы.

Нам кажется, что вторая классификация является более полезной для читателя, постигающего основы языка SQL. По нашему мнению, дополнительные возможности, присутствующие во встраиваемом и в динамическом SQL, не слишком сильно влияют на модельное представление языка. Конечно, возможности встраиваемого и динамического SQL необходимо хорошо знать разработчикам приложений SQL-ориентированных баз данных. Но поскольку задачей этого курса не является обучение использованию языка SQL при программировании приложений баз данных, мы не будем затрагивать эти темы. Обратимся к прямому SQL, причем не в полном объеме стандартов SQL:2003 и SQL:1999 (этого не позволяет сделать объем курса). Обсудим только наиболее важные аспекты.

В этой лекции обсуждаются основные аспекты системы типов данных языка SQL и средства определения доменов.

Замечание: Лекции, посвященные языку SQL, опираются, главным образом, на стандарт SQL:1999. В тех случаях, когда будут упоминаться дополнительные возможности, специфицированные в наиболее свежей версии стандарта - SQL:2003, мы будем явно на это указывать. Поэтому здесь мы используем терминологию стандарта (таблицы, строки, столбцы и т. д.).6)

Типы данных SQL

Данные, хранящиеся в столбцах таблиц SQL-ориентированной базы данных, являются типизированными, т. е. представляют собой значения одного из типов данных, предопределенных в языке SQL или определяемых пользователями путем применения соответствующих средств языка. Для этого при определении таблицы каждому ее столбцу назначается некоторый тип данных (или домен), и в дальнейшем СУБД должна следить, чтобы в каждом столбце каждой строки каждой таблицы присутствовали только допустимые значения. В этом разделе мы обсудим систему типов языка SQL.

Все допустимые в SQL типы данных, которые можно использовать при определении столбцов1), разбиваются на следующие категории2):

точные числовые типы (exact numerics);

приближенные числовые типы (approximate numerics);

типы символьных строк (character strings);

типы битовых строк (bit strings)3);

типы даты и времени (datetimes);

типы временных интервалов (intervals);

булевский тип (Booleans);

типы коллекций (collection types);

анонимные строчные типы (anonymous row types);

типы, определяемые пользователем (user-defined types);

ссылочные типы (reference types).

В столбцах таблиц, определенных на любых типах данных, наряду со значениями этих типов, допускается сохранение неопределенного значения, которое обозначается ключевым словом NULL. В языке определено, что результатом выражений вида x a_op NULL, NULL a_op x, NULL a_op NULL является NULL для всех арифметических операций a_op (+, - и т. д.), допустимых для типа данных выражения x (выражение NULL a_op NULL является допустимым для любой арифметической операции a_op). Также по определению полагается, что значением выражений x comp_op NULL, NULL comp_op x, NULL comp_op NULL для всех операций сравнения (=, , >, < и т. д.), определенных для типа выражения x, является третье логическое значение unknown4) (выражение NULL comp_op NULL является допустимым для любой операции сравнения comp_op).

Tочные числовые типы

К категории точных числовых типов в SQL относятся те типы, значения которых точно представляют числа. Типы данных этой категории распадаются на две части: истинно целые типы (INTEGER и SMALLINT) и типы, допускающие наличие дробной части (NUMERIC и DECIMAL). Охарактеризуем эти типы данных более подробно.

Истинно целые типы

Тип INTEGER. Тип служит для представления целых чисел. Точность чисел (число сохраняемых бит) определяется в реализации. При определении столбца данного типа достаточно указать просто INTEGER.

Тип SMALLINT. Тип также служит для представления целых чисел. Точность определяется в реализации, но она не должна быть больше точности типа INTEGER. При определении столбца указывается просто SMALLINT.5)

Литералы типов целых чисел представляются в виде строк символов, изображающих десятичные числа; в начале строки могут присутствовать символы "+" или "-" (если символ знака отсутствует, подразумевается "+"). Примеры литералов типов INTEGER и SMALLINT: 1826545, 876.

Точные типы, допускающие наличие дробной части

Тип NUMERIC. На самом деле, это не просто тип данных, а параметризуемый тип. При определении столбца можно указать спецификацию NUMERIC (p, s), где p и s - литералы истинно целого типа, и p задает точность значений (число сохраняемых бит), а s - шкалу (число десятичных цифр в дробной части). Задаваемая шкала не должна быть отрицательной и не должна превышать значение точности. При определении столбца можно использовать сокращенные формы спецификации типа - NUMERIC и NUMERIC (p). Первая форма предполагает использование точности, определяемое по умолчанию в реализации, и шкалы, равной нулю, а вторая - использование заданной точности и шкалы, равной нулю. Допустимые диапазоны значений p и s определяются в реализации.

Тип DECIMAL. Этот тип аналогичен типу NUMERIC. Отличие состоит в том, что если при определении столбца типа DECIMAL задается точность p, то на самом деле используется точность m, определяемая в реализации, такая, что m > p. Шкала всегда устанавливается такой, как явно или неявно (по умолчанию) задается. При указании типа столбца можно использовать спецификации DECIMAL, DECIMAL (p) и DECIMAL (p, s).

Литералы типов точных чисел, допускающих наличие дробной части, представляются в виде строк символов, изображающих десятичные числа, в начале которых могут присутствовать символы "+" или "-" (если символ знака отсутствует, подразумевается "+"), а внутри последовательности цифр может присутствовать символ ".". Примеры литералов типов NUMERIC и DECIMAL: 125, 26.36.

Приближенные числовые типы

К категории приближенных числовых типов в SQL относятся те типы, значения которых представляют числа приближенным образом. Приближенные числа представляются в виде пары <мантисса, порядок>, где мантисса состоит из значащих цифр числа, а порядок определяет реальный размер числа. В реализациях приближенным числовым типам SQL обычно соответствуют типы с плавающей точкой. В SQL поддерживаются три варианта приближенных числовых типов.

Тип REAL. Значения типа соответствуют числам с плавающей точкой одинарной точности. Точность определяется в реализации, но обычно совпадает с точностью одинарной плавающей арифметики, поддерживаемой на аппаратной платформе, которая используется реализацией. При определении столбца указывается просто REAL.

Тип DOUBLE PRECISION. Точность значений этого типа определяется в реализации, но она должна быть больше точности типа REAL. Обычно приближенным числам SQL с двойной точностью соответствуют поддерживаемые аппаратурой числа с плавающей точкой двойной точности. При определении столбца указывается просто DOUBLE PRECISION.

Тип FLOAT. Это параметризуемый тип, значение параметра p которого задает необходимую точность значений. Требуется, чтобы реально обеспечиваемая реализацией точность значений была не меньше p. Допустимый диапазон значений параметра p определяется в реализации. При определении столбца можно указать либо FLOAT (p), либо просто FLOAT. В последнем случае подразумевается точность, определяемая реализацией по умолчанию.

Литералы приближенных числовых типов представляются в виде литерала точного числового типа, за которым могут следовать символ "E" и литерал целого числового типа. Примеры литералов приближенных числовых типов: 123, 123.12, 123E12, 123.12E12. Литеральное выражение xEy представляет значение x*(10y).

Типы символьных строк

В SQL определены три параметризуемых типа символьных строк: CHARACTER (или CHAR), CHARACTER VARYING (или CHAR VARYING, или VARCHAR) и CHARACTER LARGE OBJECT (или CLOB).6)

Тип CHARACTER. Значениями типа являются символьные строки. Конкретный набор допустимых символов определяется в реализации, но, как правило, включает набор символов ASCII. При определении столбца допускается использование спецификаций CHARACTER (x) и просто CHARACTER. Последний вариант эквивалентен заданию CHARACTER (1). После определения столбца типа CHARACTER (x) СУБД будет резервировать место для хранения x символов этого столбца во всех строках соответствующей таблицы. Если, например, определен столбец типа CHARACTER (8) и в некоторой строке таблицы в него заносится символьная строка длиной пять символов, то реально будут храниться восемь символов, последние три из которых будут пробелами7).

Тип CHARACTER VARYING. При определении столбца допускается использование спецификаций CHARACTER VARYING (x) и просто CHARACTER VARYING. Последний вариант эквивалентен заданию CHARACTER VARYING (1). Если в некоторой таблице определяется столбец типа CHARACTER VARYING (x), то в каждой строке этой таблицы значения данного столбца будут занимать ровно столько места, сколько требуется для сохранения соответствующей символьной строки (но ни одна такая строка не может состоять более чем из x символов).8)

Определен ряд операций, которые можно выполнять над символьными строками. Перечислим некоторые из них.

Операция конкатенации (обозначается в виде "||") возвращает символьную строку, произведенную путем соединения строк-операндов в том порядке, в каком они заданы.

Функция выделения подстроки (SUBSTRING) принимает три аргумента - строку, номер начальной позиции и длину - и возвращает строку, выделенную из строки-аргумента в соответствии со значениями двух последних параметров.

Функция UPPER возвращает строку, в которой все строчные буквы строки-аргумента заменяются прописными. Функция LOWER, наоборот, заменяет в заданной строке все прописные буквы строчными.

Функция определения длины (CHARACTER_LENGTH, OCTET_LENGTH, BIT_LENGTH) возвращает длину заданной символьной строки в символах, октетах или битах (в зависимости от вида вычисляющей функции) в виде целого числа.

Функция определения позиции (POSITION) определяет первую позицию в строке S, с которой в нее входит заданная строка S1 (если не входит, то возвращается значение нуль).

Тип CHARACTER LARGE OBJECT. Этот тип данных предназначен для определения столбцов, хранящих большие и разные по размеру группы символов. При определении столбца задается спецификация CLOB (z), где z задает максимальный размер соответствующей группы символов. Максимально возможное значение параметра z определяется в реализации, но, очевидно, что оно должно быть существенно больше максимально возможного значения параметра x, присутствующего в типах CHAR и CHAR VARYING.9). Литералы типов символьных строк представляются в виде последовательностей символов, заключенных в одинарные или двойные кавычки. В первом случае среди набора символов литерала допускается наличие символов двойной кавычки, а во втором - символов одинарной кавычки. Примеры литералов символьных строк: 'ABCDEF', 'Ab"Ctd', "Fbcdef", "ab'cdtF".

Конструирование схем баз данных (визуальные инструменты для баз данных)

Конструктор баз данных -- это визуальное средство, позволяющее конструировать и визуализировать базу данных, с которой установлено соединение. При конструировании с помощью конструктора баз данных можно создавать, редактировать или удалять таблицы, столбцы, ключи, индексы, связи и ограничения. Для визуализации базы данных можно создать одну или несколько диаграмм, иллюстрирующих некоторые или все имеющиеся в ней таблицы, столбцы, ключи и связи.

Для любой базы данных можно создать любое необходимое количество схем; каждая из таблиц базы данных может использоваться в любом количестве схем. Таким образом, для визуализации различных частей базы данных или для акцентирования различных аспектов ее конструирования можно создавать различные схемы. Например, можно создать большую схему, в которой будут отображаться все таблицы и столбцы, а также меньшую схему, в которой будут отображаться все таблицы, но не будет столбцов.

Каждая созданная схема базы данных хранится в соответствующей базе данных.

Транзакция

Транзамкция (англ. transaction) -- в информатике, группа последовательных операций, которая представляет собой логическую единицу работы с данными. Транзакция может быть выполнена либо целиком и успешно, соблюдая целостность данных и независимо от параллельно идущих других транзакций, либо не выполнена вообще и тогда она не должна произвести никакого эффекта. Транзакции обрабатываются транзакционными системами, в процессе работы которых создаётся история транзакций.

Различают последовательные (обычные), параллельные и распределённые транзакции. Распределённые транзакции подразумевают использование больше чем одной транзакционной системы и требуют намного более сложной логики (например, two-phase commit -- двухфазный протокол фиксации транзакции). Также, в некоторых системах реализованы автономные транзакции, или под-транзакции, которые являются автономной частью родительской транзакции.

Пример транзакции

Пример: Необходимо перевести с банковского счёта номер 5 на счёт номер 7 сумму в 10 денежных единиц. Этого можно достичь, к примеру, приведённой последовательностью действий:

Начать транзакцию

прочесть баланс на счету номер 5

уменьшить баланс на 10 денежных единиц

сохранить новый баланс счёта номер 5

прочесть баланс на счету номер 7

увеличить баланс на 10 денежных единиц

сохранить новый баланс счёта номер 7

Окончить транзакцию

Эти действия представляют собой логическую единицу работы "перевод суммы между счетами", и таким образом, являются транзакцией. Если прервать данную транзакцию, к примеру, в середине, и не аннулировать все изменения, легко оставить владельца счёта номер 5 без 10 единиц, тогда как владелец счета номер 7 их не получит.

Свойства транзакций

Основная статья: ACID

Одним из наиболее распространённых наборов требований к транзакциям и транзакционным системам является набор ACID (Atomicity, Consistency, Isolation, Durability). Вместе с тем, существуют специализированные системы с ослабленными транзакционными свойствами[1].

Уровни изоляции транзакций

В идеале транзакции разных пользователей должны выполняться так, чтобы создавалась иллюзия, что пользователь текущей транзакции -- единственный. Однако в реальности, по соображениям производительности и для выполнения некоторых специальных задач, СУБД предоставляют различные уровни изоляции транзакций. Уровни описаны в порядке увеличения изоляции транзакций и надёжности работы с данными

0 -- Неподтверждённое чтение (Read Uncommited, Dirty Read, грязное чтение) -- чтение незафиксированных изменений своей транзакции и конкурирующих транзакций, возможны нечистые, неповторяемые чтения и фантомы

1 -- Подтверждённое чтение (Read Commited) -- чтение всех изменений своей транзакции и зафиксированных изменений конкурирующих транзакций, нечистые чтения невозможны, возможны неповторяемые чтения и фантомы

2 -- Повторяемое чтение (Repeatable Read ,Snapshot) -- чтение всех изменений своей транзакции, любые изменения, внесённые конкурирующими транзакциями после начала своей недоступны, нечистые и неповторяемые чтения невозможны, возможны фантомы

3 -- Упорядоченный -- (Serializable, сериализуемый) -- упорядоченные (сериализуемые) транзакции. Идентичен ситуации при которой транзакции выполняются строго последовательно одна после другой. То есть транзакции, результат действия которых не зависит от порядка выполнения шагов транзакции (запрещено чтение всех данных изменённых с начала транзакции, в том числе и своей транзакцией). Фантомы невозможны.

Чем выше уровень изоляции, тем больше требуется ресурсов, чтобы их поддерживать.

В СУБД уровень изоляции транзакций можно выбрать как для всех транзакций сразу, так и для одной конкретной транзакции. По умолчанию в большинстве баз данных используется уровень 1 (Read Commited). Уровень 0 используется в основном для отслеживания изменений длительных транзакций или для чтения редкоизменяемых данных. Уровни 2 и 3 используются при повышенных требованиях к изолированности транзакций.

Реализация

Полноценная реализация уровней изоляции и свойств ACID представляет собой нетривиальную задачу. Обработка поступающих данных приводит к большому количеству маленьких изменений, включая обновление как самих таблиц, так и индексов. Эти изменения потенциально могут потерпеть неудачу: закончилось место на диске, операция занимает слишком много времени (timeout) и т. д. Система должна в случае неудачи корректно вернуть базу данных в состояние до транзакции.

Первые коммерческие СУБД (к примеру, IBM DB2), пользовались исключительно блокировкой доступа к данным для обеспечения свойств ACID. Но большое количество блокировок приводит к существенному уменьшению производительности. Есть два популярных семейства решений этой проблемы, которые снижают количество блокировок: Журнализация изменений (write ahead logging, WAL) и механизм теневых страниц (shadow paging)[2]. В обоих случаях, блокировки должны быть расставлены на всю информацию, которая обновляется. В зависимости от уровня изоляции и имплементации, блокировки записи также расставляются на информацию, которая была прочитана транзакцией.

При упреждающей журнализации, используемой в Sybase и MS SQL Server до версии 2005, все изменения записываются в журнал, и только после успешного завершения -- в базу данных. Это позволяет СУБД вернуться в рабочее состояние после неожиданного падения системы. Теневые страницы содержат копии тех страниц базы данных на начало транзакции, в которых происходят изменения. Эти копии активизируются после успешного завершения. Хотя теневые страницы легче реализуется, упреждающая журнализация более эффективна[3]

Дальнейшее развитие технологий управления базами данных привело к появлению безблокировочных технологий. Идея контроля за параллельным доступом с помощью временных меток (timestamp-based concurrency control) была развита и привела к появлению многоверсионной архитектуры MVCC. Эти технологии не нуждаются ни в журнализации изменений, ни в теневых страницах. Архитектура, реализованная в Oracle 7.х и выше, записывает старые версии страниц в специальный сегмент отката, но они все ещё доступны для чтения. Если транзакция при чтении попадает на страницу, временная метка которой новее начала чтения, данные берутся из сегмента отката (то есть используется "старая" версия). Для поддержки такой работы ведётся журнал транзакций, но в отличие от "упреждающей журнализации", он не содержит данных. Работа с ним состоит из трёх логических шагов:

Записать намерение произвести некоторые операции

Выполнить задание, копируя оригиналы изменяемых страниц в сегмент отката

Записать, что всё сделано без ошибок

Журнал транзакций в сочетании с сегментом отката (область, в которой хранится копия всех изменяемых в ходе транзакции данных) гарантирует целостность данных. В случае сбоя запускается процедура восстановления, которая просматривает отдельные его записи следующим образом:

Если повреждена запись, то сбой произошёл во время проставления отметки в журнале. Значит, ничего важного не потерялось, игнорируем эту ошибку.

Если все записи помечены как успешно выполненные, то сбой произошёл между транзакциями, здесь также нет потерь.

Если в журнале есть незавершённая транзакция, то сбой произошёл во время записи на диск. В этом случае мы восстанавливаем старую версию данных из сегмента отката.

Firebird вообще не имеет ни журнала изменений, ни сегмента отката, а реализует MVCC, записывая новые версии строк прямо в активное пространство данных. Также поступает MS SQL 2005. Теоретически это даёт максимальную эффективность при параллельной работе с данными, но ценой является необходимость "сборки мусора", то есть удаления старых и уже не нужных версий строк.

Транзакция - группа логически связанных операторов SQL, результаты которых могут быть зафиксированы или отменены как единое целое.

Используется для многопользовательских баз данных. То есть при сетевых запросах к ней.

Вот к примеру, в инете есть БД авиакомпании. Клиент делает запрос на наличие свободного 14го места на такой то такойто рейс. Место свободно, и он его бронирует. Вот вся эта группа команд и будет транзакцией. Ее результат можно сохранить. То есть вызвать оператор commit и место будет забронировано в базе данных. А можно ROLLBACKом откатить изменения и место останется свободным, если клиент передумал покупать это место.

У нее есть 4 свойства:

1)Атомарность.Это когда все входящие в транзакцию операторы SQL рассматриваются как единая неделимая группа. То есть либо она выполняется ВСЯ, либо никакой из операторов не выполнится.

2)НепротиворечивостьЭто означает, что состояние БД остается согласованным и непротиворечивым после завершения транзакции.

3)ИзолированностьВот это самое интересное

Это свойство при котором множество транзакций, которые выполняются одновременно не должны взаимодействовать. Рассмотрим когда 2 клиента у БД авиакомпании запрашивают место 14 на одном и том же рейсе. При этом тот кто забронирует это место первым должен быть единственным лицом забронировавшим его, а не так что Клиент1 забронировал, Клиент2 тоже забронировал, и в результате они летят друг у друга на коленках

4)ДолговременностьПосле фиксации транзакции изменения в БД сохраняются при отключении компьютера или при выходе его из строя.

Ну вот В ОБЩЕМ что можно сказать по транзакции)

Язык баз данных SQL/89

Как уже отмечалось во введении, стандарт языка баз данных SQL/89 стал первым международно принятым стандартом языка SQL. У этого языка имеется масса недостатков: многие важные понятия не определены, много отдано на откуп реализациям и т.д., но тем не менее этот стандарт сыграл свою роль в становлении действительно стандартизованных реляционных систем управления базами данных (и, на самом деле, значимость SQL/89 сохраняется и сегодня, поскольку большинство производителей современных СУБД поддерживает именно этот стандарт). Более того, с появлением стандарта SQL/89 стало реально возможно проектировать, разрабатывать и сопровождать информационные системы, не слишком привязанные к конкретному производителю СУБД. В некотором смысле появление SQL/89 явилось продвижением технологии баз данных в сторону открытых систем (мобильность, интероперабельность и т.д.).

Структура стандарта и его характеристика

В стандарте определяются два уровня языка и отдельное средство поддержания целостности. Уровень 2 - это полный язык баз данных SQL, не включающий средство поддержания целостности. Уровень 1 - это специфицированное подмножество уровня 2.

Средство поддержания целостности включает возможности определения:

требуемых ограничений на ссылки между таблицами;

проверочных ограничений на строки таблицы;

значений столбца по умолчанию при занесении строки в таблицу.

В приложениях к стандарту определяется синтаксис включения операторов манипулирования данными SQL в обычную во всех остальных отношениях прикладную программу. Такой синтаксис определяется как сокращенная нотация для стандартной прикладной программы, в которой встроенные операторы SQL заменены явными "вызовами" процедур базы данных, содержащими операторы SQL.

Синтаксические элементы стандарта определяются в следующих терминах:

Функция: короткое предложение о назначении элемента.

Формат: БНФ-определение синтаксиса элемента.

Синтаксические правила: дополнительные синтаксические ограничения, которым должен удовлетворять элемент, не выраженные в БНФ.

Общие правила: последовательная спецификация эффекта выполнения элемента.

В синтаксических правилах термин "должен" определяет условия, которым должен удовлетворять любой вариант языка SQL, синтаксически соответствующий стандарту. Вариант языка SQL синтаксически соответствует стандарту, если соответствует и определениям синтаксиса, и синтаксическим правилам.

В общих правилах термин "должен" определяет условия, которые проверяются во время выполнения операторов SQL. Если все эти условия истинны, то оператор выполняется успешно, и в параметр SQLCODE устанавливается определенное неотрицательное число. Если какое-либо из условий ложно, оператор не выполняется успешно, не влияет на состояние базы данных, и в параметр SQLCODE устанавливается определяемое в реализации отрицательное число.

В соответствующей стандарту реализации не требуется выполнение точной последовательности действий, определенных в общих правилах, но должен достигаться тот же эффект, что и при выполнении этой последовательности. Термин "фактически" используется в общих правилах для того, чтобы выделить действия, результат которых может быть достигнут в реализации другим способом.

Термин "долговременно хранимый объект" используется для характеризования таких объектов, как <модуль> (<module>) и <схема> (<schema>), которые создаются и уничтожаются с помощью механизмов, определенных реализатором. язык база данных транзакция

Типы данных

В языке SQL/89 поддерживаются следующие типы данных: CHARACTER, NUMERIC, DECIMAL, INTEGER, SMALLINT, FLOAT, REAL, DOUBLE PRECISION. Эти типы данных классифицируются на типы строк символов, точных чисел и приблизительных чисел.

К первому классу относится CHARACTER. Спецификатор типа имеет вид CHARACTER (length), где length задает длину строк данного типа. Заметим, что в SQL/89 нет типа строк переменного размера, хотя во многих реализациях они допускаются. Литеральные строки символов изображаются в виде 'последовательность-символов' (например, 'example').

Представителями второго класса типов являются NUMERIC, DECIMAL (или DEC), INTEGER (или INT) и SMALLINT. Спецификатор типа NUMERIC имеет вид NUMERIC [(precision [, scale]). Специфицируются точные числа, представляемые с точностью precision и масштабом scale. Здесь и далее, если опущен масштаб, то он полагается равным 0, а если опущена точность, то ее значение по умолчанию определяется в реализации.

Спецификатор типа DECIMAL (или DEC) имеет вид NUMERIC [(precision [, scale]). Специфицируются точные числа, представленные с масштабом scale и точностью, равной или большей значения precision.

INTEGER специфицирует тип данных точных чисел с масштабом 0 и определяемой в реализации точностью. SMALLINT специфицирует тип данных точных чисел с масштабом 0 и определяемой в реализации точностью, не большей, чем точность чисел типа INTEGER.

Литеральные значения точных чисел в общем случае представляются в форме

[+ -] <целое-без-знака> [.<целое-без-знака>].

Наконец, в классу типов данных приблизительных чисел относятся типы FLOAT, REAL и DOUBLE PRECISION. Спецификатор типа FLOAT имеет вид FLOAT [(precision)]. Специфицируются приблизительные числа с двоичной точностью, равной или большей значения precision.

REAL специфицирует тип данных приблизительных чисел с точностью, определенной в реализации. DOUBLE PRECISION специфицирует тип данных приблизительных чисел с точностью, определенной в реализации, большей, чем точность типа REAL.

Литеральные значения приблизительных чисел в общем случае представляются в виде

<литеральное-значение-точного-числа>E<целое-со-знаком>.

Заметим, что хотя с использованием языка SQL можно определить схему БД, содержащую данные любого из перечисленных типов, возможность использования этих данных в прикладных системах зависит от применяемого языка программирования. Весь набор типов данных можно использовать, только если программировать на ПЛ/1. Поэтому в некоторых реализациях SQL типы данных с масштабом и точностью вообще не поддерживаются.

Хотя правила встраивания SQL в программы на языке Си не определены в SQL/89, в большинстве реализаций, поддерживающих такое встраивание, имеется следующее соответствие между типами данных SQL и типами данных Си: CHARACTER соответствует строкам Си; INTEGER соответствует long; SMALLINT соответствует short; REAL соответствует float; DOUBLE PRECISION соответствует double (именно такое соответствие утверждено в стандарте SQL/92).

Заметим еще, что в большинстве реализаций SQL поддерживаются некоторые дополнительные типы данных, например, DATE, TIME, INTERVAL, MONEY. Некоторые из этих типов специфицированы в стандарте SQL/92, но в текущих реализациях синтаксические и семантические свойства таких типов могут различаться.

Структура запросов

Для того, чтобы можно было более или менее точно рассказать про структуру запросов в стандарте SQL/89, необходимо начать со сводки синтаксических правил:

<cursor specification> ::=

<query expression> [<order by clause>]

<query expression> ::=

<query term>

<query expression> UNION [ALL] <query term>

<query term> ::=

<query specification>

| (<query expression>)

<query specification> ::=

(SELECT [ALL DISTINCT] <select list> <table expression>)

<select statement> ::=

SELECT [ALL DISTINCT] <select list> INTO <select target

list> <table expression>

<subquery> ::=

(SELECT [ALL DISTINCT] <result specification>

<table expression>

<table expression> ::=

<from clause>

[<where clause>] [<group by clause>] [<having clause>]

Язык допускает три типа синтаксических конструкций, начинающихся с ключевого словаSELECT: спецификация курсора (cursorspecification), оператор выборки (selectstatement) и подзапрос (subquery). Основой всех них является синтаксическая конструкция "табличное выражение (tableexpression)". Семантика табличного выражения состоит в том, что на основе последовательного применения разделов from, where, groupby и having из заданных в разделе from таблиц строится некоторая новая результирующая таблица, порядок следования строк которой неопределен и среди строк которой могут находиться дубликаты (т.е. в общем случае таблица-результат табличного выражения является мультимножеством строк). На самом деле, именно структура табличного выражения наибольшим образом характеризует структуру запросов языка SQL/89. Мы рассмотрим ниже структуру и смысл разделов табличного выражения, но до этого немного подробнее обсудим три упомянутые конструкции, включающие табличные выражения.

Спецификация курсора

Наиболее общей является конструкция "спецификация курсора". Курсор - это понятие языка SQL, позволяющее с помощью набора специальных операторов получить построчный доступ к результату запроса к БД. К табличным выражениям, участвующим в спецификации курсора, не предъявляются какие-либо ограничения. Как видно из сводки синтаксических правил, при определении спецификации курсора используются три дополнительных конструкции: спецификация запроса, выражение запросов и раздел ORDERBY.

Спецификация запроса. В спецификации запроса задается список выборки (список арифметических выражений над значениями столбцов результата табличного выражения и констант). В результате применения списка выборки к результату табличного выражения производится построение новой таблицы, содержащей то же число строк, но, вообще говоря, другое число столбцов, содержащих результаты вычисления соответствующих арифметических выражений из списка выборки. Кроме того, в спецификации запроса могут содержаться ключевые слова ALL или DISTINCT. При наличии ключевого слова DISTINCT из таблицы, полученной применением списка выборки к результату табличного выражения, удаляются строки-дубликаты; при указании ALL (или просто при отсутствии DISTINCT) удаление строк-дубликатов не производится.

Выражение запросов

Выражение запросов - это выражение, строящееся по указанным синтаксическим правилам на основе спецификаций запросов. Единственной операцией, которую разрешается использовать в выражениях запросов, является операция UNION (объединение таблиц) с возможной разновидностью UNIONALL. К таблицам-операндам выражения запросов предъявляется то требование, что все они должны содержать одно и то же число столбцов, и соответствующие столбцы всех операндов должны быть одного и того же типа. Выражение запросов вычисляется слева направо с учетом скобок. При выполнении операции UNION производится обычное теоретико-множественное объединение операндов, т.е. из результирующей таблицы удаляются дубликаты. При выполнении операции UNIONALL образуется результирующая таблица, в которой могут содержаться строки-дубликаты.

Раздел ORDERBY

Наконец, раздел ORDERBY позволяет установить желаемый порядок просмотра результата выражения запросов. Синтаксис ORDERBY следующий:

<order by clause> ::=

ORDER BY <sort specification> [{,<sort specification>}...]

<sort specification> ::=

{<unsigned integer> <column specification>} [ASC DESC]

Как видно из этих синтаксических правил, фактически задается список столбцов результата выражения запросов, и для каждого столбца указывается порядок просмотра строк результата в зависимости от значений этого столбца (ASC - по возрастанию, этот режим используется по умолчанию, DESC - по убыванию). Столбцы можно задавать их именами в том и только в том случае, когда (1) выражение запросов не содержит операций UNION или UNIONALL и (2) в списке выборки спецификации запроса этому столбцу соответствует арифметическое выражение, состоящее только из имени столбца. Во всех остальных случаях в разделе ORDERBY должен указываться порядковый номер столбца в таблице-результате выражения запросов.

Оператор выборки

Оператор выборки - это отдельный оператор языка SQL/89, позволяющий получить результат запроса в прикладной программе без привлечения курсора. Поэтому оператор выборки имеет синтаксис, отличающийся от синтаксиса спецификации курсора, и при его выполнении возникают ограничения на результат табличного выражения. Фактически и то, и другое диктуется спецификой оператора выборки как одиночного оператора SQL: при его выполнении результат должен быть помещен в переменные прикладной программы. Поэтому в операторе появляется раздел INTO, содержащий список переменных прикладной программы, и возникает то ограничение, что результирующая таблица должна содержать не более одной строки. Соответственно, результат базового табличного выражения должен содержать не более одной строки, если оператор выборки не содержит спецификации DISTINCT, и таблица, полученная применением списка выборки к результату табличного выражения, не должна содержать несколько несовпадающих строк, если спецификация DISTINCT задана.

Замечание: В диалекте SQL СУБД Oracle поддерживается расширенный вариант оператора выборки, результатом которого не обязательно является таблица из одной строки. Такое расширение не поддерживается ни в SQL/89, ни в SQL/92.

Подзапрос

Наконец, последняя конструкция SQL/89, которая может содержать табличные выражения, - это подзапрос, т.е. запрос, который может входить в предикат условия выборки оператора SQL. В SQL/89 к подзапросам применяется то ограничение, что результирующая таблица должна содержать в точности один столбец. Поэтому в синтаксических правилах, определяющих подзапрос, вместо списка выборки указано "выражение, вычисляющее значение", т.е. арифметическое выражение. Заметим еще, что поскольку подзапрос всегда вложен в некоторый другой оператор SQL, то в качестве констант в арифметическом выражении выборки и логических выражениях разделов WHERE и HAVING можно использовать значения столбцов текущих строк таблиц, участвующих в (под)запросах более внешнего уровня. Более подробно об этом см. ниже, при описании семантики табличных выражений.

Табличное выражение

Стандарт SQL/89 рекомендует рассматривать вычисление табличного выражения как последовательное применение разделов FROM, WHERE, GROUPBY и HAVING к таблицам, заданным в списке FROM.

Раздел FROM

Раздел FROM имеет следующий синтаксис:

<from clause> ::=

FROM <table reference> ({,<table reference>}...]

<table reference> ::=

<table name> [<correlation name>]

Результатом выполнения раздела FROM является расширенное декартово произведение таблиц, заданных списком таблиц раздела FROM. Расширенное декартово произведение (расширенное, потому что в качестве операндов и результата допускаются мультимножества) в стандарте определяется следующим образом:

"Расширенное произведение R есть мультимножество всех строк r таких, что r является конкатенацией строк из всех идентифицированных таблиц в том порядке, в котором они идентифицированы. Мощность R есть произведение мощностей идентифицированных таблиц. Порядковый номер столбца в R есть n+s, где n - порядковый номер порождающего столбца в именованной таблице T, а s - сумма степеней всех таблиц, идентифицированных до T в разделе FROM". Как видно из синтаксиса, рядом с именем таблицы можно указывать еще одно имя "correlationname". Фактически, это некоторый синоним имени таблицы, который можно использовать в других разделах табличного выражения для ссылки на строки именно этого вхождения таблицы. Если табличное выражение содержит только раздел FROM (это единственный обязательный раздел табличного выражения), то результат табличного выражения совпадает с результатом раздела FROM. Раздел WHERE. Если в табличном выражении присутствует раздел WHERE, то следующим вычисляется он. Синтаксис раздела WHERE следующий:

<where clause> ::= WHERE <search condition>

<search condition> ::=

<boolean term>

<search condition> OR <boolean term>

<Boolean term> ::=

<boolean factor>

<boolean term> AND <boolean factor>

<boolean factor> ::= [NOT] <boolean primary>

<boolean primary> ::= <predicate> (<search condition>)

Вычисление раздела WHERE производится по следующим правилам: Пусть R - результат вычисления раздела FROM. Тогда условие поиска применяется ко всем строкам R, и результатом раздела WHERE является таблица, состоящая из тех строк R, для которого результатом вычисления условия поиска является true. Если условие выборки включает подзапросы, то каждый подзапрос вычисляется для каждого кортежа таблицы R (в стандарте используется термин "effectively" в том смысле, что результат должен быть таким, как если бы каждый подзапрос действительно вычислялся заново для каждого кортежа R). Заметим, что поскольку SQL/89 допускает наличие в базе данных неопределенных значений, то вычисление условия поиска производится не в булевой, а в трехзначной логике со значениями true, false и unknown (неизвестно). Для любого предиката известно, в каких ситуациях он может порождать значение unknown. Булевские операции AND, OR и NOT работают в трехзначной логике следующим образом:

trueANDunknown = unknown

unknownANDtrue = unknown

unknownANDunknown = unknown

trueORunknown = true

unknownORtrue = true

unknownORunknown = unknown

NOTunknown = unknown

Среди предикатов условия поиска в соответствии с SQL/89 могут находиться следующие предикаты: предикат сравнения, предикат between, предикат in, предикат like, предикат null, предикат с квантором и предикат exists. Сразу заметим, что во всех реализациях SQL на эффективность выполнения запроса существенно влияет наличие в условии поиска простых предикатов сравнения (предикатов, задающих сравнение столбца таблицы с константой). Наличие таких предикатов позволяет СУБД использовать индексы при выполнении запроса, т.е. избегать полного просмотра таблицы. Хотя в принципе язык SQL позволяет пользователям не заботиться о конкретном наборе предикатов в условии выборки (лишь бы они были синтаксически и семантически правильны), при реальном использовании SQL-ориентированных СУБД такие технические детали стоит иметь в виду.

Предикат сравнения

Синтаксис предиката сравнения определяется следующими правилами:

<comparison predicate> ::=

<value expression> <comp op>

{<value expression> <subquery>}

<comp op> ::=

= <> < > <= >=

Через "<>" обозначается операция "неравенства". Арифметические выражения левой и правой частей предиката сравнения строятся по общим правилам построения арифметических выражений и могут включать в общем случае имена столбцов таблиц из раздела FROM и константы. Типы данных арифметических выражений должны быть сравнимыми (например, если тип столбца a таблицы A является типом символьных строк, то предикат "a = 5" недопустим).

Если правый операнд операции сравнения задается подзапросом, то дополнительным ограничением является то, что мощность результата подзапроса должна быть не более единицы. Если хотя бы один из операндов операции сравнения имеет неопределенное значение, или если правый операнд является подзапросом с пустым результатом, то значение предиката сравнения равно unknown.

Заметим, что значение арифметического выражения не определено, если в его вычислении участвует хотя бы одно неопределенное значение. Еще одно важное замечание из стандарта SQL/89: в контексте GROUPBY, DISTINCT и ORDERBY неопределенное значение выступает как специальный вид определенного значения, т.е. возможно, например, образование группы строк, значение указанного столбца которых является неопределенным. Для обеспечения переносимости прикладных программ нужно внимательно оценивать специфику работы с неопределенными значениями в конкретной СУБД.

Предикат between

Предикат between имеет следующий синтаксис:

<between predicate> ::=

<value expression>

[NOT] BETWEEN <value expression> AND <value expression>

Результат "x BETWEEN y AND z" тот же самый, что результат "x >= y AND x <= z". Результат "x NOT BETWEEN y AND z" тот же самый, что результат "NOT (x BETWEEN y AND z)".

Предикат in

Предикат in определяется следующими синтаксическими правилами:

<in predicate> ::=

<value expression> [NOT] IN

{<subquery> (<in value list>)}

<in value list> ::=

<value specification>

{,<value specification>}...

Типы левого операнда и значений из списка правого операнда (напомним, что результирующая таблица подзапроса должна содержать ровно один столбец) должны быть сравнимыми.

Значение предиката равно true в том и только в том случае, когда значение левого операнда совпадает хотя бы с одним значением списка правого операнда. Если список правого операнда пуст (так может быть, если правый операнд задается подзапросом), или значение "подразумеваемого" предиката сравнения x = y (где x - значение арифметического выражения левого операнда) равно false для каждого элемента y списка правого операнда, то значение предиката in равно false. В противном случае значение предиката in равно unknown. По определению значение предиката "x NOT IN S" равно значению предиката "NOT (x IN S)".

Предикат like

Предикат like имеет следующий синтаксис:

<like predicate> ::=

<column specification>

[NOT] LIKE <pattern> [ESCAPE <escape character>]

<pattern> ::= <value specification>

<escape character> ::= <value specification>

Типы данных столбца левого операнда и образца должны быть типами символьных строк. В разделе ESCAPE должен специфицироваться одиночный символ.

Значение предиката равно true, если pattern является подстрокой заданного столбца. При этом, если раздел ESCAPE отсутствует, то при сопоставлении шаблона со строкой производится специальная интерпретация двух символов шаблона: символ подчеркивания ("_") обозначает любой одиночный символ; символ процента ("%") обозначает последовательность произвольных символов произвольной длины (может быть, нулевой).

Если же раздел ESCAPE присутствует и специфицирует некоторый одиночный символ x, то пары символов "x_" и "x%" представляют одиночные символы "_" и "%" соответственно.

Значение предиката like есть unknown, если значение столбца либо шаблона неопределено.

Значение предиката "x NOT LIKE y ESCAPE z" совпадает со значением "NOT x LIKE y ESCAPE z".

Предикат null

Предикат null описывается синтаксическим правилом:

<null predicate> ::=

<column specification> IS [NOT] NULL

Этот предикат всегда принимает значения true или false. При этом значение "x IS NULL" равно true тогда и только тогда, когда значение x неопределено. Значение предиката "x NOT IS NULL" равно значению "NOT x IS NULL".

Предикат с квантором

Предикат с квантором имеет следующий синтаксис:

<quantified predicate> ::=

<value expression> <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> SOME S" имеет значение true, если значение предиката "x <comp op> s" равно true хотя бы для одного s, входящего в S. В остальных случаях значение предиката "x <comp op> SOME S" равно unknown.

Предикат exists

Предикат exists имеет следующий синтаксис:

<exists predicate> ::=

EXISTS <subquery>

Значением этого предиката всегда является true или false, и это значение равно true тогда и только тогда, когда результат вычисления подзапроса не пуст.

Раздел GROUPBY

Если в табличном выражении присутствует раздел GROUPBY, то следующим выполняется он. Синтаксис раздела GROUPBY следующий:

<group by clause> ::=

GROUP BY <column specification>

[{,<column specification>}...]

Если обозначить через R таблицу, являющуюся результатом предыдущего раздела (FROM или WHERE), то результатом раздела GROUPBY является разбиение R на множество групп строк, состоящего из минимального числа групп таких, что для каждого столбца из списка столбцов раздела GROUPBY во всех строках каждой группы, включающей более одной строки, значения этого столбца равны. Для обозначения результата раздела GROUPBY в стандарте используется термин "сгруппированная таблица".

Раздел HAVING

Наконец, последним при вычислении табличного выражения используется раздел HAVING (если он присутствует). Синтаксис этого раздела следующий:

<having clause> ::=

HAVING <search condition>

Раздел HAVING может осмысленно появиться в табличном выражении только в том случае, когда в нем присутствует раздел GROUPBY. Условие поиска этого раздела задает условие на группу строк сгруппированной таблицы. Формально раздел HAVING может присутствовать и в табличном выражении, не содержащем GROUPBY. В этом случае полагается, что результат вычисления предыдущих разделов представляет собой сгруппированную таблицу, состоящую из одной группы без выделенных столбцов группирования.

Условие поиска раздела HAVING строится по тем же синтаксическим правилам, что и условие поиска раздела WHERE, и может включать те же самые предикаты. Однако имеются специальные синтаксические ограничения по части использования в условии поиска спецификаций столбцов таблиц из раздела FROM данного табличного выражения. Эти ограничения следуют из того, что условие поиска раздела HAVING задает условие на целую группу, а не на индивидуальные строки.

Поэтому в арифметических выражениях предикатов, входящих в условие выборки раздела HAVING, прямо можно использовать только спецификации столбцов, указанных в качестве столбцов группирования в разделе GROUPBY. Остальные столбцы можно специфицировать только внутри спецификаций агрегатных функций COUNT, SUM, AVG, MIN и MAX, вычисляющих в данном случае некоторое агрегатное значение для всей группы строк. Аналогично обстоит дело с подзапросами, входящими в предикаты условия выборки раздела HAVING: если в подзапросе используется характеристика текущей группы, то она может задаваться только путем ссылки на столбцы группирования.

Результатом выполнения раздела HAVING является сгруппированная таблица, содержащая только те группы строк, для которых результат вычисления условия поиска есть true. В частности, если раздел HAVING присутствует в табличном выражении, не содержащем GRОUPBY, то результатом его выполнения будет либо пустая таблица, либо результат выполнения предыдущих разделов табличного выражения, рассматриваемый как одна группа без столбцов группирования.


Подобные документы

  • Конечная цель любой компьютерной программы – управление аппаратными средствами. Пирамидальная конструкция уровней ПО. Характеристика базового, системного и служебного уровней. Системное, прикладное, инструментальное и сервисное программное обеспечение.

    контрольная работа [27,7 K], добавлен 03.01.2011

  • Определение абсолютных и относительных показателей изменения уровней ряда динамики. Определение абсолютного размера одного процента прироста и средних показателей ряда динамики. Реализация численных методов при использовании алгоритмического языка Pascal.

    курсовая работа [174,9 K], добавлен 06.10.2013

  • Языки программирования низкого и высокого уровней и среды реализации. Особенности процедурных, логических, объектно-ориентированных языков. Состав системы программирования: трансляторы, библиотеки и отладчик программ, компоновщик, средства редактирования.

    презентация [11,9 K], добавлен 23.10.2013

  • Интерфейсные средства СУБД MS Access 2003. Проектирование схемы данных. Создание составного отчёта, содержащего диаграмму. Группировка и сортировка в отчётах. Использование языка программирования VBА, создание макросов. Разработка программы и функций.

    курсовая работа [5,2 M], добавлен 20.06.2010

  • Взаимодействие уровней в процессе связи, его эталонная модель для открытых систем. Функции уровней модели OSI. Сетезависимые протоколы, а также протоколы, ориентированные на приложениях, их сравнительное описание и использование в современных сетях.

    реферат [361,5 K], добавлен 16.04.2015

  • Краткая история развития СУБД ORACLE, основные понятия и определения, архитектура. Принципы работы с СУБД ORACLE. Разработка баз данных, средства и технологии их реализации; возможности процедурного языка PL/SQL. Приемы администрирования СУБД ORACLE.

    презентация [609,2 K], добавлен 14.02.2014

  • Общие сведения о компьютерном математическом моделировании. Принцип построения и функционирования распределенных систем. Технологии объектного связывания данных. Механизм изоляции транзакций и преодоления ситуаций несогласованной обработки данных.

    курсовая работа [92,5 K], добавлен 13.12.2014

  • Понятие и концепция базы данных и СУБД. Независимость приложений от организации данных во внешней памяти. Типы данных SQL, таблицы, структура языка и операторы. Преимущества модели реляционного подхода к организации баз данных и ее эффективность.

    курсовая работа [69,6 K], добавлен 30.11.2009

  • Различия между существующими диалектами SQL. Стандартизация языка SQL. Концепция баз данных. Эффективность организации данных. Структура языка SQL. Приближенные числовые типы. Интервальный тип данных. Обработка сложно структурированной информации.

    курсовая работа [50,7 K], добавлен 29.05.2014

  • Объекты модели хранения данных базы данных ORACLE. Взаимосвязь между логическими структурами. Средства манипулирования данными языка SQL, данными языка SQL. Структура выполнения простейших запросов. Формирование критерия отбора. Сортировка данных.

    презентация [120,1 K], добавлен 14.02.2014

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.