metBD (1084482), страница 31
Текст из файла (страница 31)
В языке SQL предусмотрено четыре предложения манипулирования данными: SELECT, UPDATE, DELETE и INSERT. В этой и следующей главе рассматривается предложение SELECT. В части 8.4 рассматриваются три других предложения. Предполагается также, если не оговорено противное, что все предложения языка вводятся интерактивным способом.
Примечание. Многие из примеров, особенно в следующей главе, являются весьма сложными. Дело, скорее, в том, что обычные операции настолько просты в SQL (а фактически, в большинстве реляционных языков), что примеры таких операций оказываются довольно неинтересными и не иллюстрируют полной мощности этого языка. Сначала, конечно, приводятся некоторые простые примеры затем более сложная, но чрезвычайно важная возможность, называемая соединением.
Примеры запросов
Начнем с простого примера — с запроса «Выдать номера и состояния для поставщиков, находящихся в Париже». Этот запрос может быть выражен в SQL следующим образом:
SELECT НОМЕР_ПОСТАВЩИКА, СОСТОЯНИЕ
FROM S
WHERE ГОРОД = ’Париж’;
В качестве результата получим:
НОМЕР_ПОСТАВЩИКА | СОСТОЯНИЕ |
S2 | 10 |
S3 | 30 |
Этот пример иллюстрирует самую общую форму предложения SELECT в языке SQL—
“SELECT (выбрать) специфицированные поля
FROM (из) специфицированной таблицы
WHERE (где) некоторое специфицированное условие является истинным”
Заметим, что результатом запроса является другая таблица — таблица, которая некоторым образом получается из заданных в базе данных таблиц. Иными словами, в реляционной системе типа ORACLE пользователь всегда действует в рамках простой табличной структуры, и это — весьма привлекательная особенность таких систем.
В данном случае было бы вполне возможно сформулировать запрос, используя уточненные имена полей:
SELECT S.HOMEP_ПОСТАВЩИКА, S.СОСТОЯНИЕ
FROM S
WHERE S.ГОРОД = ’Париж’;
Использование уточненных имен никогда не рассматривается как ошибка, и иногда это существенно.
Для справочных целей ниже показана общая форма предложения SELECT, в которой, однако, опущена возможность UNION, обсуждаемая в следующей части:
SELECT [DISTINCT] элемент(ы)
FROM таблица (или таблицы)
[WHERE предикат]
[GROUP BY поле (или поля) [HAVING предикат] ]
[ORDER BY поле (или поля) ];
Перейдем теперь к иллюстрации основных особенностей этого предложения с помощью весьма продолжительной серии примеров.
Простая выборка
Выдать номера для всех поставляемых деталей:
SELECT НОМЕР_ДЕТАЛИ
FROM SP;
Имеем результат:
НОМЕР_ДЕТАЛИ |
P1 |
P2 |
P3 |
P4 |
P5 |
P6 |
P1 |
P2 |
P2 |
P2 |
P4 |
P5 |
Обратим внимание на дубликаты номеров деталей в этом результате. Система не исключает дубликатов из результата предложения SELECT, если пользователь явно не потребует это сделать с помощью ключевого слова DISTINCT (различный, различные), как показано в следующем примере.
Выборка с исключением дубликатов
Выдать номера для всех поставляемых деталей, исключая избыточные дубликаты:
SELECT DISTINCT НОМЕР_ДЕТАЛИ
FROM SP;
В этом случае результат таков:
НОМЕР_ДЕТАЛИ |
P1 |
P2 |
P3 |
P4 |
P5 |
P6 |
Выборка вычисляемых значений
Выдать номер и вес каждой детали в граммах для всех деталей, предполагая, что в таблице P веса деталей заданы в фунтах (454 грамма):
SELECT НОМЕР_ДЕТАЛИ, ВЕС*454
FROM Р;
Получаем результат:
НОМЕР_ДЕТАЛИ | |
P1 | 5448 |
P2 | 7718 |
P3 | 7718 |
P4 | 6356 |
P5 | 5448 |
P6 | 8626 |
Фраза SELECT (и фраза WHERE) может включать арифметические выражения, а также простые имена полей. Можно, кроме того, осуществлять выборку просто констант. Например:
SELECT НОМЕР_ДЕТАЛИ, ’Вес в граммах = ’, ВЕС*454
FROM P;
Получаем результат:
НОМЕР_ДЕТАЛИ | ||
P1 | ’Вес в граммах = | 5448 |
P2 | ’Вес в граммах = | 7718 |
P3 | ’Вес в граммах = | 7718 |
P4 | ’Вес в граммах = | 6356 |
P5 | ’Вес в граммах = | 5448 |
P6 | ’Вес в граммах = | 8626 |
Заметим, что в этом результате три столбца.
В связи с этим примером возникает следующий вопрос: что произойдет, если вес какой-либо детали имеет неопределенное значение (NULL)? Напомним, что NULL представляет неизвестное значение. Предположим, например, что вес детали Р1 задан в базе данных как неопределенное значение вместо значения 12. Каково тогда значение выражения ВЕС*454 для этой детали? Ответ состоит в том, что оно также является неопределенным значением. В общем случае фактически любое арифметическое выражение считается имеющим неопределенное значение, если какой-либо из его операндов сам имеет неопределенное значение. Иными словами, если оказывается, что вес имеет неопределенное значение, то неопределенное значение имеют и все следующие выражения:
ВЕС+454
ВЕС — 454
ВЕС*454
ВЕС/454
Неопределенные значения показываются на терминале как тире или дефис.
Простая выборка «select *»
Выдать полные характеристики для всех поставщиков:
SELECT *
FROM S;
Результатом служит копия полной таблицы S.
Здесь звезда или звездочка служит кратким обозначением списка всех имен полей в таблице (таблицах), указанной(ых) во фразе FROM (из) в том порядке, в котором эти поля определяются в соответствующем(их) предложении(ях) CREATE TABLE. Таким образом, записанное выше предложение SELECT эквивалентно следующему:
SELECT НОМЕР_ПОСТАВЩИКА, ФАМИЛИЯ, СОСТОЯНИЕ, ГОРОД
FROM S;
Обозначение в виде звездочки удобно для интерактивных запросов, поскольку оно уменьшает число ударов по клавишам. Однако оно таит потенциальную опасность при использовании во встроенном SQL (т. е. в предложениях SQL в прикладной программе), поскольку смысл знака «*» может измениться, если для этой программы перегенерируется план прикладной задачи, а в данном промежутке времени к рассматриваемой таблице был добавлен другой столбец. В этом пособии «SELECT *» будет использоваться только в таких контекстах, где так делать безопасно (в основном только в интерактивных контекстах), и фактическим пользователям рекомендуется поступать подобным образом.
Отметим, наконец, что «*» может уточняться именем соответствующей таблицы. Допустима, например, следующая форма записи:
SELECT S.*
FROM S;
Ограниченная выборка
Выдать номера поставщиков, которые находятся в Париже и имеют состояние большее, чем 20:
SELECT НОМЕР_ПОСТАВЩИКА
FROM S
WHERE ГОРОД = ’Париж’
AND СОСТОЯНИЕ > 20;
Результат:
НОМЕР_ПОСТАВЩИКА |
S3 |
Условие, или предикат, следующий за ключевым словом WHERE, может включать операторы сравнения =, != (неравно), >, >=, <, и <=, булевские операторы AND (и), OR (или) и NOT (нет), а скобки указывают требуемый порядок вычислений. В таком предикате числа сравниваются алгебраически — отрицательные числа считаются меньшими, чем положительные, независимо от их абсолютной величины. Строки литер сравниваются в соответствии с их представлением в коде ASCII. Если нужно сравнить две строки литер, имеющих разные длины, более короткая строка концептуально дополняется справа пробелами для того, чтобы обе строки имели одинаковую длину перед тем, как будет осуществляться их сравнение.
Выборка с упорядочением
Выдать номера и состояния поставщиков, находящихся в Париже, в порядке убывания их состояния:
SELECT НОМЕР_ПОСТАВЩИКА, СОСТОЯНИЕ
FROM S
WHERE ГОРОД = ’Париж’
ORDER BY СОСТОЯНИЕ DESC;
Результат:
НОМЕР_ПОСТАВЩИКА | СОСТОЯНИЕ |
S3 | 30 |
S2 | 10 |
В общем случае не гарантируется, что результирующая таблица будет упорядочена каким-либо определенным образом. Здесь, однако, пользователь специфицировал, что результат перед тем, как он будет показан, должен быть организован в определенной последовательности. Упорядочение может быть специфицировано таким же образом, как в предложении CREATE INDEX:
имя—столбца [упорядочение] [, имя—столбца [упорядочение]] ...,
где «упорядочение», как и ранее, это ASC (возрастание) или DECS (убывание), и по умолчанию принимается ASC. Каждое «имя—столбца» должно идентифицировать некоторый столбец результирующей таблицы. Поэтому, например, следующее предложение недопустимо:
SELECT НОМЕР_ПОСТАВЩИКА
FROM S
ORDER BY ГОРОД;
Разрешается также идентифицировать столбцы во фразе ORDER BY (упорядочить по) «номерами—столбцов» вместо «имен—столбцов», где «номер—столбца» указывает порядковую позицию (слева направо) данного столбца в результирующей таблице запроса. Благодаря этому возможно упорядочение результата на основе «вычисляемых столбцов», которые не обладают именем. Например, упорядочить результат по возрастанию номера детали в рамках возрастания веса в граммах:
SELECT НОМЕР_ДЕТАЛИ, ВЕС*454
FROM P
ORDER BY 2, НОМЕР_ДЕТАЛИ; [или ORDER BY 2,1;]
Здесь «2» ссылается на второй столбец результирующей таблицы.