Понимание SQL
Шрифт:
end;
Фрагмент программы на ПАСКАЛЕ, определяет цикл, который будет считывать значения из файла, сохранять их в четырех проименованных переменных, сохранять значения этих переменных в таблице Продавцов, и затем считывать следующие четыре значения, повторяя этот процесс до тех пор пока весь входной файл не прочитается. Считается, что каждый набор значений завершается возвратом каретки (для незнакомых с Паскалем, функция readln считывает вводимую информацию и переходит на следующую строку источника этой информации). Это дает вам простойспособ передать данные из текстового файла в реляционную структуру.
Конечно, вы можете сначала обработать данные
while not end-ot-file (input) do
begin
readln (id_num, salesperson, loc, comm);
if comm >=.12 then
EXEC SQL INSERT INTO Salespeople
VALUES (:id_num, :salesperson, :loc, :comm);
end;
Только строки которые встретят условие comm >=.12 будут вставлены в вывод. Это показывает что можно использовать и циклы и условия как нормальные для главного языка.
Все переменные на которые имеется ссылка в предложениях SQL, должны сначала быть обьявлены в SQL DECLARE SECTION (РАЗДЕЛе ОБЪЯВЛЕНИЙ ), использующем обычный синтаксис главного языка. Вы можете иметь любое число таких разделов в программе, и они могут размещаться где-нибудь в коде перед используемой переменной, подчиненной ограничениям определенным в соответствии с главным языком. Раздел объявлений должен начинать и кончаться вложенными командами SQL - BEGIN DECLARE SECTION (Начало Раздела Объявлений ) и END DECLARE SECTION (Конец Раздела Объявлений ), которым предшествует, как обычно EXEC SQL (Выполнить).
Чтобы обьявить переменные используемые в предыдущем примере, вы можете ввести следующее:
EXEC SQL BEGIN DECLARE SECTION;
Var
id-num: integer;
Salesperson: packed array (1 . .10) ot char;
loc: packed array (1. .10) ot char;
comm: real;
EXEC SQL END DECLARE SECTION;
Для незнакомых с ПАСКАЛем, i - это заголовок который предшествует ряду обьявляемых переменных, и упакованным (или распакованным ) массивам являющимися серией фиксированных переменных значений различаемых
с помощью номеров( например, третий символ loc будет loc (3)). Использование точки с запятой после каждой переменной указывает на то что это - Паскаль, а не SQL.
Кроме помещения значений переменных в таблицы используя команды SQL, вы можете использовать SQL чтобы получать значения для этих переменных. Один из способов делать это - с помощью разновидности команды SELECT которая содержит предложение INTO. Давайте вернемся к нашему предыдущему примеру и переместим строку Peel из таблицы Продавцов в наши переменные главного языка.
EXEC SQL SELECT snum, sname, city, comm
INTO :id_num, :salesperson, :loc, :comm
FROM Salespeople
WHERE snum=1001;
Выбранные значения помещаются в переменные с упорядоченными именами указанными в предложении INTO. Разумееется, переменные с именами указанными в предложении INTO должны иметь соответствующий тип чтобы принять эти значения, и должна быть своя переменная для каждого выбранного столбца. Если не учитывать присутствие предложения INTO, то этот запрос - похож на любой другой. Однако, предложение INTO добавляет значительное ограничение к запросу. Запрос должен извлекать не более одной строки. Если он извлекает много строк, все они не могут быть вставлены одновременно в одну и ту же переменную. Команда естественно потерпит
* когда вы используете предикат проверяющий значения, которое как вы знаете, могут быть уникальным, как в этом примере. Значения которые, как вы знаете, могут быть уникальными - это те значения которые имеют принудительное ограничение уникальности или уникальный индекс, как это говорилось в Главах 17 и 18.
* когда вы используете одну или более агрегатных функций и не используете GROUP BY.
* когда вы используете SELECT DISTINCT во внешнем ключе с предикатом ссылающимся на единственное значение родительского ключа (обеспечивая вашей системе предписание справочной целостность), как в следующем примере:
EXEC SQL SELECT DISTINCT snum
INTO :salesnum
FROM Customers
WHERE snum=
(SELECT snum
FROM Salespeople
WHERE sname='Motika');
Предпологалось что Salespeople.sname и Salespeople.snum - это соответственно, уникальный и первичный ключи этой таблицы, а Customers.snum - это внешний ключ ссылающийся на Salespeople.snum, и вы предполагали что этот запрос произведет единственную строку. Имеются другие случаи, когда вы можете знаете, что запрос должен произвести единственную строку вывода, но они мало известны и, в большинстве случаев, вы основываетесь на том что ваши данные имеют целостность, которая не может быть предписана с помощью ограничений. Не полагайтесь на это! Вы создаете программу которая, вероятно, будет использоваться в течение некоторого времени, и лучше всего проиграть ее чтобы быть гарантированным в будущем от возможных отказов. Во всяком случае, нет необходимости группировать запросы которые производут одиночные строки, поскольку SELECT INTO - используется только для удобства.
Как вы увидите, вы можете использовать запросы выводящие многочисленные строки, используя курсор.
Одна из сильных качеств SQL - это способность функционировать на всех строках таблицы, чтобы встретить определенное условие как блок запись, не зная сколько таких строк там может быть. Если десять строк удовлетворяют предикату, то запрос может вывести все десять строк. Если десять миллионов строк определены, все десять миллионов строк будут выведены. Это несколько затруднительно, когда вы попробуете связать это с другими языками. Как вы сможете назначать вывод запроса для переменных когда вы не знаете как велик будет вывод ? Решение состоит в том, чтобы использовать то, что называется - курсором. Вы вероятно знакомы с курсором, как с мигающей черточкой, которая отмечает вашу позицию на экране компьютера. Вы можете рассматривать SQL курсор как устройство, которое аналогично этому, отмечает ваше место в выводе запроса, хотя аналогия не полная.
Курсор - это вид переменной, которая связана с запросом. Значением этой переменной может быть каждая строка, которая выводится при запросе. Подобно главным переменным, курсоры должны быть обьявлены прежде, чем они будут использованы. Это делается командой DECLARE CURSOR, следующим образом:
EXEC SQL DECLARE CURSOR Londonsales FOR
SELECT *
FROM Salespeople
WHERE city='London';
Запрос не выполнится немедленно; он - только определяется. Курсор немного напоминает представление, в котором курсор содержит запрос, а содержание курсора - напоминает любой вывод запроса, каждый раз когда курсор становится открытым. Однако, в отличие от базовых таблиц или представлений, строки курсора упорядочены: имеются первая, вторая...