Глава 15. Использование SQL в приложениях

В этой главе...

  • SQL в приложении
  • Совместное использование SQL с процедурными языками
  • Как избежать несовместимости
  • Код SQL, встроенный в процедурный код
  • Вызов модулей SQL из процедурного кода
  • Вызов SQL из RAD-инструмента

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

Хотя синтаксис языка SQL похож на синтаксис английского языка, изучить SQL все равно нелегко. Подавляющее большинство сегодняшних пользователей им не владеют в достаточной мере. И можно предположить, что даже если эта книга и завоюет широкую популярность, то все равно подавляющее большинство компьютерных пользователей так никогда и не будут свободно владеть SQL. Если обычному пользователю поставить задачу, связанную с базой данных, он и не подумает садиться к терминалу и вводить оператор SELECT. Системные аналитики и разработчики приложений, свободно владеющие SQL, также не занимаются вводом разовых (ad hoc) запросов с консоли. Эти специалисты разрабатывают приложения, которые сами создают запросы.

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

SQL в приложении

В главе 2 SQL был назван неполным языком программирования. Для использования в приложении язык SQL необходимо комбинировать с процедурным языком, таким как Pascal, FORTRAN, Visual Basic, С, C++, Java или COBOL. У SQL есть как сильные, так и слабые стороны. У процедурных языков, имеющих другую структуру, также есть сильные и слабые стороны, но не такие, как у SQL. К счастью, сильные стороны SQL обычно компенсируют слабость процедурных языков, а сильные стороны процедурных языков проявляются как раз там, где SQL оказывается не на высоте. Если совместно использовать процедурные языки с SQL, можно создать мощные приложения с широким набором возможностей. Недавно появились объектно-ориентированные RAD-инструменты, которые позволяют встраивать код SQL в приложения, создаваемые из объектов, а не с помощью написания процедурного кода. В качестве примера таких инструментов можно привести Delphi и C++ Builder.

Внимание: В предыдущих главах мы часто использовали звездочку ('*') для краткого обозначения всех столбцов в таблице. Если в таблице много столбцов, то звездочка помогает уменьшить ввод кода. Если же SQL применяется в прикладной программе, лучше раз и навсегда от нее отказаться. После того как приложение будет написано, вы или кто-то другой, возможно, добавите в таблицу новые столбцы или удалите старые. Однако в таком случае меняется значение понятия "все столбцы". Ваше приложение, когда оно указывает с помощью звездочки "все столбцы", может получить не те столбцы, на которые рассчитывает.

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

Совет: Чтобы обезопасить себя, указывайте имена всех столбцов в явном виде, а не полагайтесь на символ звездочки.

Сильные и слабые стороны SQL

Одной из сильных сторон языка SQL является получение данных. Если важная информация размещена где-то в однотабличной или многотабличной базе данных, то ее можно отыскать с помощью инструментов SQL. Этот язык не работает с отдельными строками или столбцами, поэтому вам не нужно знать порядок расположения в таблице строк или столбцов. Имеющиеся в SQL средства обработки транзакций гарантируют, что на операции, выполняемые с базой данных, не повлияют любые другие пользователи, которые одновременно с вами могут получить доступ к одним и тем же таблицам.

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

Иногда качество, которое в одном случае является достоинством, может в другом оказаться, наоборот, недостатком. Например, одна из сильных сторон языка SQL состоит в том, что он может работать сразу с целой таблицей. Сколько бы в таблице ни было строк: одна, сто или сто тысяч — нужные вам данные можно извлечь из нее с помощью единственного оператора SELECT. Однако SQL не может легко работать с каждой строкой индивидуально. Для этого придется использовать или курсоры, которые описаны в главе 18, или процедурный базовый язык.

Сильные и слабые стороны процедурных языков

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

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

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

Противоположные режимы работы

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

Несовместимость типов данных

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

SQL - код в программе, написанной на процедурном языке

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

Встроенный SQL

Самый распространенный метод сочетания SQL с процедурными языками называется встроенным SQL. Как понятно из названия, операторы SQL вставляются в нужные места процедурной программы. Естественно, внезапно появившись в программе, написанной, скажем, на языке С, оператор SQL может стать неприятным сюрпризом для компилятора. По этой причине программы, в которых имеется встроенный SQL, перед компиляцией или интерпретацией пропускают через препроцессор. О встроенном SQL-коде препроцессор предупреждается директивой EXEC SQL.

В качестве примера использования встроенного SQL рассмотрим программу, написанную на языке Рго*С фирмы Oracle, являющемся вариантом языка С. Программа получает доступ к таблице с данными сотрудников компании, предлагает пользователю ввести имя сотрудника, а затем выводит зарплату и комиссионные этого сотрудника. Затем она предлагает ввести новые данные по зарплате и комиссионным этого же сотрудника и обновляет этими данными таблицу.

EXEC SQL BEGIN DECLARE SECTION;

    VARCHAR uid[20];

    VARCHAR pwd[20];

    VARCHAR ename[10];

    FLOAT salary, comm;

    SHORT salary_ind, comm_ind;

EXEC SQL END DECLARE SECTION;

main ()

{

    int sret;                             /* Возвращаемый код scanf */

    /* Регистрация */

    strcpy(uid.arr,"FRED");             /*Копировать имя пользователя */

    uid.len=strlen(uid.arr);

    strcpy(pwd.arr,"TOWER")    ;             */ Копировать пароль /*

    pwd.len=strlen(pwd.arr);

    EXED SQL WHENEVER SQLERROR STOP;

    EXED SQL WHENEVER NOT FOUND STOP;

EXEC SQL CONNECT :uid;

printf("Соединение с пользователем: percents \n",uid.arr);

    printf("Введите имя пользователя для обновления: ");

    scanf("percents",ename.arr);

    ename.len=strlen(ename.arr);

    EXEC SQL SELECT SALARY,COMM INTO :salary,:cornm

            FROM EMPLOY

            WHERE ENAME=:ename;

    printf("Сотрудник: percents оклад: percent6.2f комиссионные:

        percent6.2f \n",

            ename.arr, salary, comm);

    printf("Введите новый оклад: ");

    sret=scanf("percentf",&salary);

    salary_ind =0; /* Инициализировать индикатор */

    if (sret == EOF !! sret == 0)

        salary_ind =-1; /* Установить индикатор отсутствия ввода */

    printf("Введите новые комиссионные: ");

    sret=scanf("percentf",&comm);

    comm_ind =0; /* Инициализировать индикатор */

    if (sret == EOF !! sret == 0)

        comm_ind=-1; /* Установить индикатор отсутствия ввода */

    EXEC SQL UPDATE EMPLOY

            SET SALARY=:salary:salary_ind

            SET COMM=:comm:comm_ind

            WHERE ENAME=:ename;

printf("Данные сотрудника percents обновлены. \n",ename.arr);

    EXEC SQL COMMIT WORK;

    exit(0);

}

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

  • SQL объявляет базовые переменные.
  • Язык С контролирует процедуру регистрации пользователя.
  • SQL активизирует обработку ошибок и соединяется с базой данных.
  • Язык С запрашивает у пользователя имя сотрудника, которое помещает в переменную rename.
  • Оператор SQL SELECT извлекает данные по зарплате и комиссионным указанного пользователя и сохраняет их в двух переменных базового языка, .salary и xomm.
  • Далее язык С выводит имя сотрудника, его зарплату и комиссионные, а затем требует ввести новые значения зарплаты и комиссионных. Он также проверяет, введены ли требуемые значения, и если нет, то устанавливает индикатор отсутствия ввода.
  • SQL обновляет данные в базе на основе новых значений.
  • Язык С отображает сообщение о завершении операции.
  • SQL завершает транзакцию, и С завершает выполнение программы.

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

Объявление базовых переменных

Помни: Между программой, написанной на базовом языке, и кодом SQL должна передаваться информация. Для этого используются базовые переменные. Чтобы SQL признал эти переменные, их перед использованием необходимо объявить. Объявления находятся в сегменте объявлений, который расположен перед программным сегментом. Сегмент объявлений начинается со следующей директивы:

EXEC SQL BEGIN DECLARE SECTION ;

А конец этого сегмента отмечается с помощью такого выражения:

EХЕС SQL END DECLARE SECTION ;

Перед каждым оператором SQL должна стоять директива SQL EXEC. Конец сегмента SQL может быть отмечен директивой завершения. В языке COBOL такой директивой является '"END-EXEC", I в языке FORTRAN — это конец строки, а в языках Ada, С, Pascal и PL/1 — точка с запятой.

Преобразование типов данных

В зависимости от типов данных, поддерживаемых базовым языком и языком SQL, вам, воз-рсно, для преобразования некоторых из этих типов данных придется использовать оператор CAST. Можно использовать базовые переменные, которые были объявлены с помощью DECLARE SECTION. А когда в операторах SQL применяются имена этих переменных, то не надо забывать следующее: перед этими именами необходимо ставить двоеточие (:). Это как раз и делается в следующем примере с таблицей FOODS (продукты питания) со столбцами FOODNAME (название продукта), CALORIES (калории), PROTEIN (белки), FAT (жиры), CARBOHYDRATE (углеводы):

INSERT INTO FOODS

    (FOODNAME, CALORIES, PROTEIN, FAT, CARBOHYDRATE)

    VALUES

    (: foodname, rcalories, .-protein, :fat, :carbo) ;

Модульный язык

Использовать SQL вместе с процедурным программным языком можно и по-другому — с помощью модульного языка. Благодаря ему вы сможете разместить все операторы SQL в
отдельном модуле SQL.

Помни: Модуль SQL— это список команд SQL. Каждая из этих команд вызывается процедурой SQL, и перед ней стоят имя процедуры, имена и типы ее параметров.

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

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

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

  • Так как SQL полностью отделен от процедурного языка, то для написания модулей можно нанять самых лучших программистов, работающих в SQL. И неважно, имеют они какой-либо опыт работы с процедурным языком или нет. На самом деле решение вопроса о том, какой процедурный язык использовать, можно даже отложить до того времени, пока не будут написаны и отлажены модули SQL.
  • Программу на базовом языке может написать программист, не знакомый с SQL.
  • Важнее всего то, что в процедурном коде не будет фрагментов SQL-кода, поэтому можно будет использовать отладчик, позволяющий сэкономить большое количество времени, которое приходится тратить на разработку. И снова оговоримся: то, что с одной точки зрения может выглядеть как преимущество, с другой может выглядеть как недостаток. Модули SQL отделены от процедурного кода, и если вы попытаетесь понять работу программы, то вам будет труднее это сделать, чем при использовании встроенного SQL.

Объявления модулей

Синтаксис объявлений в модулях имеет такой вид:

MODULE [имя-модуля]

    [NAMES ARE имя-набора-символов]

    LANGUAGE (ADA|С|COBOL|FORTRAN|MUMPS I PASCAL IPLI|SQL}

    [SCHEMA имя - схемы]

    [AUTHORIZATION идентификатор-подтверждения-полномочий]

    [объявления-временных-таблиц.. . ]

    [объявления-курсоров.. . ]

    [объявления-динамических-курсоров...]

    процедуры...

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

Хотя оба предложения, SCHEMA (схема) и AUTHORIZATION (подтверждение полномочий), являются необязательными, непременно надо указать хотя бы одно из них. Можно также указать и оба сразу. Первое из них определяет схему по умолчанию, а второе — идентификатор подтверждения полномочий. Если зы его не укажете, то для предоставления вашему модулю полномочий СУБД будет использовать полномочия текущего сеанса. Если на выполнение операции, которую вызывает ваша процедура, у вас нет прав, то процедура не будет выполняться.

Совет: Если вашей процедуре нужны временные таблицы, то объявляйте их с помощью специального предложения объявлений временных таблиц. Объявляйте курсоры и динамические курсоры еще до того, как они будут использованы какой-либо процедурой. Объявление курсора после процедуры возможно в случае, если его будет использовать не она, а процедуры, объявленные после. Более подробная информация, относящаяся к курсорам, приведена в главе 18.

Процедуры модуля

И наконец, после всех этих объявлений в модуле находятся его функциональные части — процедуры. У процедуры в модульном SQL есть имя, объявления параметров и выполняющиеся операторы SQL. Программа, написанная на процедурном языке, вызывает процедуру по ее имени и передает ей значения через объявленные параметры. Синтаксис процедуры следующий:

PROCEDURE имя-процедуры

    (объявление-параметра [, объявление-параметра]...)

    оператор SQL ;

    [операторы SQL] ;

Объявление параметра должно иметь такой вид:

имя-параметра тип-данных

или такой:

SQLSTATE

Объявляемые вами параметры могут быть входными, выходными или теми и другими одновременно. SQLSTATE является параметром состояния, посредством которого выводится информация об ошибках. Чтобы подробнее разобраться с параметрами, обратитесь к главе 20.

Объектно-ориентированные RAD-инструменты

Используя современные RAD-инструменты, можно создавать сложные приложения и при этом не знать, как написать хотя бы одну строку кода на С, Pascal, COBOL или FORTRAN. Вместо того чтобы писать код, вы выбираете из библиотеки объекты и помещаете каждый из шх в нужное место на экране.

Помни: У объектов разных стандартных типов имеются характеризующие их свойства, а каждому типу объектов свойственны специальные события. С объектом можно также связать какой-либо метод. Метод — это процедура, написанная на процедурном языке. Впрочем, возможно создать очень сложные приложения, не написав при этом ни одного метода.

Хотя и можно написать сложные приложения, не пользуясь при этом процедурным языком, но SQL вам рано или поздно все же понадобится. SQL настолько богат выразительными средствами, что их трудно или даже невозможно выразить в объектной парадигме. Поэтому RAD-инструменты позволяют вставлять операторы SQL в объектно-ориентированные приложения. Примером объектно-ориентированной среды разработки, в которой можно работать с SQL, является Borland C++ Builder. Microsoft Access — это несколько другая среда разработки приложений, которая позволяет использовать язык SQL совместно с процедурным языком VBA.

В главе 4 описывалось создание таблиц базы данных с помощью приложения Access. Эти операции представляют собой лишь малую часть возможностей Access. Основная цель этого инструмента — разработка приложений, которые обрабатывают данные в таблицах базы данных. Разработчик помещает объекты в формы, а затем назначает им свойства, события и возможные методы. Для обработки форм и объектов используется код VBA, содержащий встроенный язык SQL.

Внимание: Хотя RAD-инструменты, подобные Access, могут помочь в создании высококачественных приложений за сравнительно короткое время, но обычно эти инструменты работают только на одной или на нескольких платформах. Например, Access работает только в операционной системе Microsoft Windows. He забывайте об этом, если хотите предусмотреть возможный перенос своих приложений на другую платформу.

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

 
На правах рекламы:
Регистрация. | Забыли пароль?
Логин
Пароль
Запомнить меня