Автор работы: Пользователь скрыл имя, 26 Января 2013 в 14:13, лекция
Программирование баз данных - очень большой и серьезный раздел самого что ни на есть практического программирования. На предыдущем курсе "Введение в программирование на Delphi" мы лишь коснулись этой темы, затронули даже не верхушку айсберга под названием Базы Данных, а только его макушку. Между тем, многие программисты большую часть своего времени тратят именно на проектирование баз данных и разработку приложений, работающих с ними. Это неудивительно - в настоящее время каждая государственная организация, каждая фирма или крупная корпорация имеют рабочие места с к
Строки в примере написаны по правилам и рекомендациям языка SQL, то есть, операторы пишутся заглавными буквами, каждый оператор на отдельной строке, а в конце ставится точка с запятой. Однако рекомендации можно нарушать, а правила в Delphi более мягкие. Так, мы можем написать весь текст маленькими буквами, в одну строку, не ставить точку с запятой и не обращать внимания на регистр букв:
select * from lichdata
Запрос все равно будет
Что же написано у нас в этом запросе? Оператор SELECT означает "выделить", звездочка означает "все поля", оператор FROM означает "из…". Таким образом, запрос означает:
ВЫДЕЛИТЬ все поля ИЗ таблицы LichData
Но такой запрос ничем не отличается от применения табличных компонентов, а ведь мы можем создавать и гораздо более сложные запросы! Предположим, нам нужно получить фамилию, имя и отчество сотрудника, а также город его проживания. Основные данные находятся в таблице LichData, а вот город находится в таблице Adres, связанной с таблицей LichData релятивной связью один-к-одному по полю "Ключ" таблицы LichData, и по полю "Сотрудник" таблицы Adres. В этом случае запрос будет выглядеть так:
SELECT Фамилия, Имя, Отчество, Город
FROM LichData, Adres
WHERE Ключ = Сотрудник;
Как видите, в операторе SELECT поля перечисляются через запятую. Также через запятую перечисляются используемые таблицы в операторе FROM. А вот оператор WHERE указывает, что нужны только те записи, в которых значения поля "Ключ" и "Сотрудник" равны. Если бы мы не использовали оператор WHERE, то получили бы кучу недостоверных записей, где к каждой записи одной таблицы добавлялись бы все записи другой. Оператор WHERE позволил нам получить связные данные, в которых к одной записи первой таблицы добавляется соответствующая запись из другой таблицы. С этими и другими операторами мы подробней познакомимся на следующей лекции.
Теперь предположим, что в одном наборе данных нам нужно получить записи из двух таблиц, связанных релятивной связью один-ко-многим. Так, у одного сотрудника может быть несколько телефонов. В этом случае придется смириться, что некоторые данные будут продублированы. Например, запрос:
SELECT Фамилия, Имя, Телефон
FROM LichData, Telephones
WHERE Ключ = Сотрудник;
выдаст нам набор данных, в
котором фамилия и имя
Компонент-запрос может формировать
набор данных двух типов: изменяемый,
в котором пользователь может
менять (редактировать, удалять или
добавлять) записи, и не изменяемый,
предназначенный только для просмотра
данных или для составления
Компонент TQuery/TADOQuery может выполнять запросы двумя разными способами. Вначале в свойство SQL компонента помещается необходимый запрос. Это можно сделать программно, как в нашем SQL-мониторе, так и на этапе проектирования приложения. Дальнейшие действия зависят от того, какой запрос нам нужно выполнить. Если это запрос на получение набора данных, то есть, оператор SELECT, то достаточно просто открыть TQuery/TADOQuery методом Open, или присвоив True свойству Active. Если же запрос должен модифицировать данные, то есть, используются такие операторы, как INSERT, UPDATE, DELETE, то тогда запрос выполняется методом ExecSQL.
С работой компонента-запроса TQuery (TADOQuery) мы поработали на практике. Как и табличные компоненты, компонент-запрос произошел от родительского класса TDBDataSet. Унаследовав его свойства, методы и события, он имеет и собственные, отличительные черты. Так, например, запрос может быть изменяемым (живым), при котором пользователь может модифицировать записи набора данных, и не изменяемым, при котором данные доступны только для просмотра и составления отчетности. Наиболее важные свойства, методы и события, отличные от TDBDataSet, рассматриваются ниже.
Constrained - Свойство логического типа. Если свойство имеет значение True, то в изменяемом наборе данных на модифицируемые записи накладываются ограничения блока WHERE оператора SELECT (с операторами SQL-запросов вплотную познакомимся на следующей лекции).
DataSource - Указывает тот компонент TDataSource, который используется для формирования параметрического запроса.
Local - Свойство логического типа. Если свойство имеет значение True, это означает, что компонент-запрос работает с локальной или файл-серверной базой данных.
ParamCheck - Логическое свойство. При значении True список параметров автоматически обновляется при каждом программном изменении SQL-запроса.
Params - Свойство имеет тип TParams и содержит массив объектов-параметров этого типа. На этом типе данных следует остановиться подробнее:
Таблица 7.1. Свойства и методы типа TParams | |
Свойство |
Описание |
Items |
Содержит массив параметров типа TParams и является свойством "по умолчанию". Индексация массива начинается с 0. |
ParamValues() |
Открывает доступ к значению параметра по его имени, указанному в скобках. |
Count |
Количество параметров в массиве. |
Метод |
Описание |
AddParam() |
Добавляет параметр в массив параметров. |
CreateParam() |
Создает параметр и добавляет его к массиву. |
FindParam() |
Ищет параметр по его имени, указанному в скобках. |
RemoveParam() |
Удаляет параметр из массива. |
Prepared - Свойство логического типа. Содержит значение True, если SQL-запрос был подготовлен методом Prepare.
RequestLive - Логическое свойство. Если компонент-запрос содержит изменяемый (живой) набор данных, то RequestLive содержит True.
RowsAffected - Свойство содержит количество записей, которые были удалены или отредактированы в наборе данных в результате выполнения SQL-запроса.
SQL - Свойство типа TStrings, то есть, набор строк. Содержит SQL-запрос, который выполняется, как только компонент-запрос становится активным (открывается). При изменении этого свойства, компонент-запрос автоматически закрывается, так что программисту требуется перевести свойство Active набора данных в True (или вызвать метод Open), чтобы запрос выполнился, и в НД появились запрошенные данные. Помещать строки запроса в свойство SQL можно как при проектировании, так и программно. В случае если программист создает запрос и открывает набор данных при проектировании приложения, он имеет возможность создать объекты-поля (см. предыдущую лекцию), и настраивать их свойства по своему усмотрению. При программном формировании НД такой возможности у него нет.
UniDirectional - Свойство логического типа. Содержит True, если курсор набора данных может перемещаться только вперед (типы курсоров см. в лекции №4). Это свойство используется, в основном, при работе с клиент-серверными СУБД, не поддерживающими курсоры, которые могут двигаться как вперед, так и назад.
ExecSQL() - Выполняет модифицирующие запросы, то есть запросы на изменение, добавление или удаление записей, а также создание или удаление таблиц. В случае обычных запросов, выполненных с помощью оператора SELECT, используется метод Open, или присвоение значения True свойству Active набора данных.
ParamByName() - Метод дает доступ к значению параметра по его имени, указанному в скобках.
Prepare() - Метод используется для передачи SQL-запроса механизму доступа к данным, чтобы последний оптимизировал запрос. Оптимизация запроса происходит следующим образом: при выполнении любого запроса, механизм доступа к данным проверяет его синтаксис, что отнимает некоторое время. В случае многократного применения запроса, его можно выполнить методом Prepare(). При этом запрос компилируется и запоминается в буфере. При повторном выполнении этого запроса его синтаксис уже не проверяется.
UnPrepare() - Этот метод отменяет результаты действия метода Prepare(), и освобождает буфер от хранения компилированного запроса.
8.
Лекция: Краткий курс языка запросов SQL:
версия для печати и PDA
На этой лекции вы познакомитесь с основными
командами языка запросов SQL и научитесь
формировать как простые, так и сложные
запросы.
SQL (Structured Query Language) - Это Язык Структурированных Запросов. Он не такой богатый, как языки программирования высокого уровня. Тем не менее, это язык, без владения которым программисту, работающему с базами данных, не обойтись. Запросы, написанные на SQL, часто называют скриптами. Как вы уже знаете, эти скрипты можно непосредственно вводить в свойство SQL компонента-запроса в момент проектирования приложения, а можно значение этого свойства менять и в процессе прогона программы. Однако нередко используют и третий способ: программист создает набор скриптовых файлов, в процессе работы программа считывает из них SQL-инструкции в компоненты запросов и выполняет их. Это простые текстовые файлы, созданные в любом редакторе текстов, например, стандартном Блокноте Windows. Расширение может быть любым, но традиционно используется *.sql. Все это позволяет создавать гибкие программы. Если организации, использующей ваше приложение, в дальнейшем потребуются какие-то новые возможности, например, им нужно дополнительно создать еще один отчет, то применение скриптовых файлов избавит вас от необходимости переделывать программу, для этого достаточно будет написать скрипт.
В этой лекции мы разберем работу основных операторов SQL, после чего вы сможете создавать простые и сложные запросы и получать необходимые наборы данных. Тем, кто пожелает расширить свои познания SQL, рекомендую пройти соответствующий курс, посвященный этому языку, или прочитать книгу М. Грубера "Понимание SQL". Книга описывает стандартный синтаксис языка SQL и затрагивает все его возможности.
Команда SELECT является основой запроса. Большинство SQL-запросов начинаются с нее. Множество других команд вкладываются в блок SELECT. Полный синтаксис этой команды таков:
SELECT * | { [ DISTINCT | ALL] <value expression>.,..}
FROM { <table name> [ <alias> ] }.,..
[ WHERE <predicate>]
[ GROUP BY { <column name> | <integer> }.,..]
[ HAVING <predicate>]
[ ORDER BY { <column name> | <integer> }.,..];
Здесь используются следующие элементы:
Таблица 8.1 . Элементы команды SELECT | |
Элемент |
Описание |
<value expression> |
Выражение, которое производит значение. Оно может включать имена столбцов. |
<table name> |
Имя или синоним таблицы или представления |
<alias> |
Временный синоним для <table name>, определенный в этой таблице и используемый только в этой команде. |
<predicate> |
Условие, которое может быть верным или неверным для каждой строки или комбинации строк таблицы в предложении FROM. |
<column name> |
Имя столбца в таблице. |
<integer> |
Число с десятичной точкой. В этом случае, оно показывает <value expression> в предложении SELECT с помощью идентификации его местоположения в этом предложении. |
В простейшем случае применение команды SELECT выглядит так:
SELECT *
FROM Table_Name;
Звездочка указывает, что нужно показать все поля. Вместо звездочки можно указать конкретное поле или поля, разделяя их запятыми. Иногда бывает, что требуются данные из разных таблиц, которые имеют поля с одинаковым именем. В этом случае, перед именем полей указывают имя таблицы, или ее псевдоним, разделяя имена таблицы и поля точкой:
SELECT Field1, Table1.Field2, Table2.Field2…
FROM Table1, Table2;
Команда FROM определяет имена таблиц, из которых осуществляется выборка данных. Если таблиц несколько, их имена разделяются запятыми. Иногда таблицы имеют длинные имена. В этом случае бывает выгодно использовать псевдонимы (alias) имен таблиц, указывая их через пробел после имени таблицы:
SELECT Field1, f.Field2, s.Field2
FROM Table1 f, Table2 s;
Команда WHERE позволяет использовать условие, которые может быть верным или нет для каждой записи БД. Если условие верное, то запись добавляется в набор данных, иначе отвергается. Давайте рассмотрим пример. Загрузите SQL-монитор из прошлой лекции. Предположим, нам нужно получить следующие данные на каждого сотрудника: Фамилия, Имя, Отдел, Должность. Пишем соответственный SQL-запрос:
SELECT Фамилия, Имя, Отдел, Должность
FROM LichData, Doljnost;
Выполнив этот запрос, вы получите нечто непонятное. В полученном наборе данных всем сотрудникам подряд присваивается вначале первая должность, затем вторая, и так до конца. Другими словами, если у вас 10 сотрудников и 10 должностей, то вместо ожидаемых десяти записей вы получите 10 * 10 = 100 записей! Полученные данные называют недостоверными. Чтобы избежать этого, существует команда WHERE, которая позволяет задать условие выборки данных: