Sql-запити в delphi, delphi - sql, статті, програмування - програмування c, delphi, c #

1. Введення

Компоненти Delphi для роботи з базами даних були створені в розрахунку на роботу з SQL і архітектурою клієнт / сервер. При роботі з ними ви можете скористатися характеристиками розширеної підтримки віддалених серверів. Delphi здійснює цю підтримку двома способами. По-перше, безпосередні команди з Delphi дозволяють розробнику управляти таблицями, встановлювати межі, видаляти, вставляти і редагувати існуючі записи. Другий спосіб полягає у використанні запитів на мові SQL, де рядок запиту передається на сервер для її розбору, оптимізації, виконання та передачі назад результатів.







2. Компонент TQuery

Якщо в ваших додатках ви збираєтеся використовувати SQL, то вам неодмінно доведеться познайомитися з компонентом TQuery. Компоненти TQuery і TTable успадковуються від TDataset. TDataset забезпечує необхідну функціональність для отримання доступу до баз даних. Як такі, компоненти TQuery і TTable мають багато спільних ознак. Для підготовки даних для показу у візуальних компонентах використовується все той же TDatasource. Також, для визначення до якого сервера і бази даних необхідно отримати доступ, необхідно задати ім'я псевдоніма. Це повинно виконуватися установкою властивості aliasName об'єкта TQuery.

Все ж TQuery має деяку унікальну функціональність. Наприклад, у TQuery є властивість з ім'ям SQL. Властивість SQL використовується для зберігання SQL-запиту. Нижче наведені основні кроки для складання запиту, де всі службовці мають зарплату понад $ 50,000.

Створіть об'єкт TQuery

Задайте псевдонім властивості DatabaseName. (Даний приклад використовує псевдонім IBLOCAL, пов'язаний з демонстраційною базою даних employee.gdb).

Введіть: Select * from EMPLOYEE where SALARY> 50000. Натисніть OK.

Виберіть в інспектор об'єктів властивість Active і встановіть його в TRUE.

Додайте на формі об'єкт TDatasource.

Встановіть властивість Dataset у TDatasource в Query1.

Додайте на формі TDBGrid.

Встановіть його властивість Datasource в Datasource1.
Властивість SQL має тип TStrings. Об'єкт TStrings є список рядків, і чимось схожий на масив. Тип даних TStrings має в своєму арсеналі команди додавання рядків, їх завантаження з текстового файлу і обміну даними з іншим об'єктом TStrings. Інший компонент, який використовує TStrings - TMemo. У демонстраційному проекті ENTRSQL.DPR (по ідеї, він повинен знаходиться на окремій діскетте, але до "Радам по Delphi" вона не додається - В.О.), користувач повинен ввести SQL-запит і натиснути кнопку "Do It" ( "зробити це "). Результати запиту відображаються в табличній сітці. У лістингу 1 повністю приведений код обробника кнопки "Do It".
лістинг 1

procedure TForm1.BitBtn1Click (Sender: TObject);
begin

Цього має бути достатньо для користувача, який знає SQL. Проте, більшість користувачів не знає цієї мови. Отже, ваша робота як розробника полягає в наданні інтерфейсу і створення SQL-запиту. У Delphi, для створення SQL-запиту на льоту можна використовувати динамічні запити. Динамічні запити допускають використання параметрів. Для визначення параметра в запиті використовується двокрапка (:), за яким слідує ім'я параметра. Нижче приведе приклад SQL-запиту з використанням динамічного параметра:

select * from EMPLOYEE
where DEPT_NO =: Dept_no

Якщо вам потрібно протестувати, або встановити для параметра значення за замовчуванням, виберіть властивість Params об'єкта Query1. Клацніть на кнопці '. '. Повинен з'явитися діалог налаштування параметрів. Виберіть параметр Dept_no. Потім в списку, що випадає типів даних виберіть Integer. Для того, щоб задати значення за замовчуванням, введіть потрібне значення в поле редагування "Value".
Для зміни SQL-запиту під час виконання програми, параметри необхідно пов'язати (bind). Параметри можуть змінюватися, запит виконуватися повторно, а дані оновлюватися. Для безпосереднього редагування значення параметра використовується властивість Params або метод ParamByName. Властивість Params вдає із себе масив TParams. Тому для отримання доступу до параметру, необхідно вказати його індекс. Для прикладу,

Query1.params [0] .asInteger: = 900;

Властивість asInteger читає дані як тип Integer (назва говорить сама за себе). Це не обов'язково має вказувати але те, що поле має тип Integer. Наприклад, якщо тип поля VARCHAR (10), Delphi здійснить перетворення даних. Так, наведений вище приклад міг би бути записаний таким чином:

Query1.params [0] .asString: = '900';

Query1.params [0] .asString: = edit1.text;

Якщо замість номера індексу ви хотіли б використовувати ім'я параметра, то скористайтеся методом ParamByName. Даний метод повертає об'єкт TParam з заданим ім'ям. наприклад:

Query1.ParamByName ( 'DEPT_NO') .asInteger: = 900;


У лістингу 2 наведено повний код прикладу.

procedure TForm1.BitBtn1Click (Sender: TObject);
begin


Зверніть увагу на процедуру, насамперед подготовлівающую запит. При виклику методу prepare, Delphi посилає SQL запит на віддалений сервер. Сервер виконує граматичний розбір і оптимізацію запиту. Перевага такої підготовки запиту полягає в його попередньому розборі і оптимізації. Альтернативою тут може служити підготовка сервером запитував, чи потрібно його виконанні. Як тільки запит підготовлений, підставляються необхідні нові параметри, і запит виконується.

У попередньому прикладі користувач міг ввести номер відділу, і після виконання запиту відображався список співробітників цього відділу. А як щодо використання таблиці DEPARTMENT, що дозволяє користувачеві легко переміщатися між користувачами і відділами?

Примітка: Наступний приклад використовує TTable з ім'ям Table1. Для Table1 ім'я бази даних IBLOCAL, ім'я таблиці - DEPARTMENT. DataSource2 TDatasource пов'язаний з Table1. Таблиця також активна і відображає записи в TDBGrid.

Спосіб підключення TQuery до TTable - через TDatasource. Є два основних способи зробити це. По-перше, розмістити код в обробнику події TDatasource OnDataChange. Наприклад, лістинг 3 демонструє цю техніку.







procedure TForm1.DataSource2DataChange (Sender: TObject; Field: TField);
begin

Query1.ParamByName ( 'Dept_no') .asInteger: = Table1Dept_No.asInteger;

On e. EDatabaseError do

messageDlg (e. message. mtError, [mbOK], 0);

Техніка з використанням OnDataChange дуже гнучка, але є ще легше спосіб підключення Query до таблиці. Компонент TQuery має властивість Datasource. Визначаючи TDatasource для властивості Datasource, об'єкт TQuery порівнює імена параметрів в SQL-запиті з іменами полів у TDatasource. У разі загальних імен, такі параметри заповнюються автоматично. Це дозволяє розробнику уникнути написання коду, наведеного в лістингу 3 (*** наведено вище ***).

Фактично, техніка використання Datasource не вимагає ніякого додаткового кодування. Щоб увійти запиту до таблиці DEPT_NO виконайте дії, наведені в лістингу 4.

Лістинг 4 - Скріплення TQuery c TTable через властивість Datasource

Виберіть у Query1 властивість SQL і введіть:

select * from EMPLOYEE
where DEPT_NO =: dept_no

Виберіть властивість Datasource і призначте джерело даних, пов'язаний з Table1 (Datasource2 в нашому прикладі)
Виберіть властивість Active і встановіть його в True

Це все, якщо ви хочете створити такий тип відносин. Проте, існують деякі обмеження на параметризрвані запити. Параметри обмежені значеннями. Наприклад, ви не можете використовувати параметр з ім'ям Column або Table. Для створення запиту, динамічно змінюваного ім'я таблиці, ви могли б використовувати техніку конкатенації рядка. Інша техніка полягає у використанні команди Format.

Команда Format замінює параметри форматування (% s,.,% N і ін.) Передаються значеннями. наприклад,

Format ( 'Select * from% s'. [ 'EMPLOYEE'])

Результатом вищенаведеної команди буде 'Select * from EMPLOYEE'. Функція буквально робить заміну параметрів форматування значеннями масиву. При використанні декількох параметрів форматування, заміна відбувається зліва направо. наприклад,

tblName: = 'EMPLOYEE';
fldName: = 'EMP_ID';
fldValue: = 3;
Format ( 'Select * from% s where% s =.'. [TblName, fldName, fldValue])


Результатом команди форматування буде 'Select * from EMPLOYEE where EMP_ID = 3'. Така функціональність забезпечує надзвичайну гнучкість при динамічному виконанні запиту. Приклад, наведений нижче в лістингу 5, дозволяє вивести в результатах поле salary. Для поля salary користувач може задавати критерії.

Лістинг 5 - Використання команди Format для створення SQL-запиту

begin
<Создание каркаса запроса>
sqlString: = 'Select EMP_NO% s from employee where SALARY% s';

У цьому прикладі ми використовуємо методи Clear і Add властивості SQL. Оскільки "підготовлений" запит використовує ресурси сервера, і немає ніякої гарантії що новий запит буде використовувати ті ж таблиці і стовпчики, Delphi, при кожній зміні властивості SQL, здійснює операцію, зворотну "підготовці" (unprepare). Якщо TQuery не був підготовлений (тобто властивість Prepared встановлено в False), Delphi автоматично готує його при кожному виконанні. Тому в нашому випадку, навіть якби був викликаний метод Prepare, з додатком від цього не буде ніякої користі.

Open проти ExecSQL

У попередніх прикладах TQuerie виконували Select-запити. Delphi розглядає результати Select-запиту як набір даних, типу таблиці. Це просто один клас допустимих SQL-запитів. Наприклад, команда Update оновлює вміст запису, але не повертає записи або будь-якого значення. Якщо ви хочете використовувати запит, що не повертає набір даних, використовуйте ExecSQL замість Open. ExecSQL передає запит для виконання на сервер. У загальному випадку, якщо ви очікуєте, що отримаєте від запиту дані, то використовуйте Open. В іншому випадку допускається використання ExecSQL, хоча його використання з Select НЕ буде конструктивним. Лістинг 6 містить код, що пояснює сказане на прикладі.

procedure TForm1.BitBtnClick (sender: TObject)
begin
Query1.Close;
Query1.Clear;
Query1.SQL.Add ( 'Update SALARY from EMPLOYEE' +
'Where SALARY<:salary values (SALARY*(1+:raise)' );
Query1.paramByName ( 'salary') .asString: = edit1.text;
Query1.paramByName ( 'raise') .asString: = edit2.text;
try
Query1.ExecSQL;
except
on e: EDatabaseError do
messageDlg (e. message. mtError, [mbOK], 0);
end;
end;

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

3. Компонент TStoredProc

Процедура є список команд (SQL або певного сервера), що зберігаються і виконуваних на стороні сервера. Збережені процедури не мають концептуальних відмінностей з іншими типами процедур. TStoredProc успадковується від TDataset, тому він має багато спільних характеристик з TTable і TQuery. Особливо помітно схожість з TQuery. Оскільки збережені процедури не вимагають повернення значень, ті ж правила діють і для методів ExecProc і Open. Кожен сервер реалізує роботу збережених процедур з невеликими відмінностями. Наприклад, якщо в якості сервера ви використовуєте Interbase, збережені процедури виконуються у вигляді Select-запитів. Наприклад, щоб подивитися на результати процедури, що, ORG_CHART, в демонстраційній базі даних EMPLOYEE, використовуйте наступних SQL-запит:

Select * from ORG_CHART

При роботі з іншими серверами, наприклад, Sybase, ви можете використовувати компонент TStoredProc. Даний компонент має властивості для імен бази даних і процедури, що. Якщо процедура вимагає на вході якихось параметрів, використовуйте для їх введення властивість Params.
4. TDatabase

Компонент TDatabase забезпечує функціональність, якої не вистачає TQuery і TStoredProc. Зокрема, TDatabase дозволяє створювати локальні псевдоніми BDE, так що з додатком не будуть потрібні псевдоніми, що містяться в файлі конфігурації BDE. Цим локальним псевдонімом в додатку можуть скористатися всі наявні TTable, TQuery і TStoredProc. TDatabase також дозволяє розробнику налаштовувати процес підключення, пригнічуючи діалог введення імені і пароля користувача, або заповнюючи необхідні параметри. І, нарешті, найголовніше, TDatabase може забезпечувати єдиний зв'язок з базою даних, підсумовуючи всі операції з базою даних через один компонент. Це дозволяє елементам управління для роботи з БД мати можливість управління транзакціями.

Транзакцією можна вважати передачу пакета інформації. Класичним прикладом транзакції є передача грошей на рахунок банку. Транзакція має складатися з операції внесення суми на новий рахунок і видалення тієї ж суми з поточного рахунку. Якщо один з цих кроків з якоїсь причини був не виконаний, транзакція також вважається невиконаним. У разі такої помилки, SQL сервер дозволяє виконати команду відкату (rollback), без внесення змін до бази даних. Управління транзакціями залежить від компонента TDatabase. Оскільки транзакція зазвичай складається з декількох запитів, ви повинні відзначити початок транзакції і її кінець. Для виділення початку транзакції використовуйте TDatabase.BeginTransaction. Як тільки транзакція почне виконуватися, всі виконувані команди до виклику TDatabase.Commit або TDatabase.Rollback переводяться в тимчасовий режим. При виклику Commit всі змінені дані передаються на сервер. При виклику Rollback всі зміни втрачають силу. Нижче в лістингу 7 наведено приклад, де використовується таблиця з ім'ям ACCOUNTS. Показана процедура намагається передати суму з одного рахунку на інший.

procedure TForm1.BitBtn1Click (Sender: TObject);
<ПРИМЕЧАНИЕ: Поле BALANCE у ACCOUNTS имеет триггер, проверяющий
ситуацію, коли віднімається сума перевищує BALANCE. Якщо так, UPDATE
буде скасований>
begin
try
database1.StartTransaction;
query1.SQL.Clear;
<Вычитаем сумму из выбранного счета>
query1.SQL.Add (Format ( 'update ACCOUNTS' +
'Set BALANCE = BALANCE -% s)' +
'Where ACCT_NUM =% s'.
[Edit1.text,
Table1Acct_Num.asString]));
query1.ExecSQL;
query1.SQL.Clear;
<Добавляем сумму к выбранному счету>
query1.SQL.Add (Format ( 'update ACCOUNTS' +
'Set BALANCE = BALANCE +% s' +
'Where ACCT_NUM =% s'.
[Edit1.text,
Table2Acct_Num.asString]));
query1.ExecSQL;
database1.Commit;
table1.Refresh;
table2.Refresh;
except
відкатуємо транзакцію назад>
One: EDatabaseError do
begin
messageDlg (e. message. mtError, [mbOK], 0);
database1.rollback;
exit;
end;
One: Exception do
begin







Схожі статті