СТАТЬЯ |
13.06.02
|
Особенности работы с Microsoft SQL Server
в Delphi 5
(Часть 2)
У
Анатолий Тенцер
Статья была опубликована в "КомпьютерПресс",
№6-2001
В дополнение к стандартным возможностям Microsoft SQL Server позволяет вставить в таблицу набор данных, полученный в результате выполнения хранимой процедуры, при помощи синтаксиса:
INSERT author_sales EXECUTE get_author_sales
Сервер поддерживает расширенный синтаксис
UPDATE MyTable
SET Name = ‘Иванов’
FROM MyTable T INNER JOIN AnotherTable A ON T.Id = A.MyTableId
AND A.SomeField = 20
В версии 7.0 поддерживаются следующие типы данных:
Тип
|
Синоним
|
Примечание
|
BIT | Целое число, равное 0 или 1. В Delphi возможно обращение к полю этого типа при помощи свойства AsBoolean (1 = True, 0 = False) | |
INT | INTEGER | 32-битное целое число в диапазоне от – 2 147 483 648 до 2 147 483 647 |
SMALLINT | 16-битное целое число в диапазоне от 32 768 до 32 767 | |
TINYINT | 8-битное целое число в диапазоне от 0 до 255 | |
DECIMAL[(P[, S])] | NUMERIC, DEC | Десятичное число с фиксированной точностью в диапазоне от – 1038 –1 до 1038 – 1. P — максимальное количество знаков в числе S — количество знаков после запятой |
MONEY | Денежный тип данных. Целое 64-битное число, младшие 4 разряда которого отведены под дробную часть. Может хранить числа в диапазоне от –922 337 203 685 477,5808 до 922 337 203 685 477,5807. В Delphi соответствует типу данных Currency | |
SMALLMONEY | Аналогичен Money, но 32-разрядный и ограничен диапазоном от –214 748,3648 до 214 748,3647 | |
FLOAT | DOUBLE PRECISION | Число с плавающей точкой в диапазоне от –1.79E + 308 до 1.79E + 308 |
REAL | Число с плавающей точкой в диапазоне от –3.40E + 38 до 3.40E + 38 | |
DATETIME | Дата и время в диапазоне от 1 января 1753 г. до 31 декабря 9999 г. с точностью 3.33 мс | |
SMALLDATETIME | Дата и время в диапазоне от 1 января 1900 г. до 6 июня 2079 г. с точностью до 1 мин | |
TIMESTAMP | Уникальный идентификатор в пределах базы данных. Этот тип данных НЕ СОДЕРЖИТ времени и лишь гарантирует, что поле этого типа уникально в рамках базы данных | |
UNIQUEIDENTIFIER | Глобальный уникальный идентификатор. Статистически уникальное 16-битное значение. Над этим типом данных определены лишь операции =, <>, IS NULL и IS NOT NULL | |
CHAR[(N)] | CHARACTER, VARYING VARCHAR |
Строка фиксированной длины. N — длина строки. Максимальная длина — 8 тыс. символов |
VARCHAR[(N)] | CHARACTER VARYING(N) | Строка переменной длины. N — длина строки. Максимальная длина — 8 тыс. символов |
TEXT | Строка произвольной длины (до 2 147 483 647 символов) | |
NCHAR[(N)] | NATIONAL CHARACTER, NATIONAL CHAR |
Строка фиксированной длины в формате Unicode. N — длина строки. Максимальная длина — 4 тыс. символов |
NVARCHAR[(N)] | NATIONAL CHARACTER VARYING(N), NATIONAL CHAR VARYING(N) |
Строка переменной длины в формате Unicode N — длина строки. Максимальная длина — 4000 символов |
NTEXT | NATIONAL TEXT | Строка произвольной длины (до 1 073 741 823 символов) |
BINARY[(N)] | VARYING VARBINARY | Двоичные данные фиксированной длины (до 8000 байт) N — длина данных |
VARBINARY[(N)] | Двоичные данные переменной длины (до 8000 байт) N — длина данных | |
IMAGE | Двоичные данные произвольной длины (до 2 147 483 647 байт) |
В версии SQL 2000 дополнительно предусмотрены следующие типы данных:
Тип
|
Синоним
|
Примечание
|
BIGINT | 64-битное целое число | |
SQL_VARIANT | Может хранить данные произвольного типа |
В версии 7.0 поддерживается создание вычисляемых полей
CREATE TABLE MyTable (
Direction BIT NOT NULL,
Amount MONEY,
CASE Direction
WHEN 1 THEN Amount
ELSE -Amount
END AS SignedAmount
)
Выражение не должно содержать подзапросов. В версии Microsoft SQL Server 2000 по вычисляемому полю может быть построен индекс.
Триггеры в Microsoft SQL Server срабатывают после обновления и лишь один раз на оператор (а не на каждую обновленную запись). Количество триггеров на таблицу не ограничено. В триггере доступны обновленная таблица и две виртуальные таблицы Inserted и Deleted.
В них находятся:
Inserted |
Deleted | |
INSERT | Вставленные записи | Нет записей |
UPDATE | Новые версии записей | Старые версии записей |
DELETE | Нет записей | Удаленные записи |
Основываясь на содержании этих таблиц, триггер может осуществить дополнительную модификацию данных либо отменить транзакцию, вызвавшую этот оператор. Например:
CREATE TRIGGER T1 ON MyTable FOR INSERT, UPDATE
AS BEGIN
-- Заносим в поля:
-- LastUserName – имя пользователя, последним обновившего запись
-- LastDateTime – дату и время последнего обновления
UPDATE MyTable
SET LastUserName = SUSER_NAME(),
LastDateTime = GETDATE()
FROM Inserted I INNER JOIN MyTable T ON I.Id = T.Id
END
CREATE TRIGGER T2 ON MyTable FOR DELETE
AS BEGIN
-- Этот триггер откатывает и снимает всю транзакцию
-- вызвавшую ошибку
IF EXISTS (SELECT * FROM Deleted
WHERE Position = ‘Boss’) BEGIN
RAISERROR(‘Нельзя удалять начальника’, 16, 1)
ROLLBACK
END
END
CREATE TRIGGER T3 ON MyTable FOR DELETE
AS BEGIN
-- А этот просто не дает удалить запись
-- позволяя продолжить транзакцию
IF EXISTS (SELECT * FROM Deleted
WHERE Position = ‘Programmer’) BEGIN
INSERT INTO MyTable
SELECT * FROM Deleted
WHERE Position = ‘Programmer’
RAISERROR(‘Программиста удалить тоже не получится’, 16, 1)
END
END
Поскольку триггер срабатывает после обновления таблицы, в нем нельзя реализовывать каскадные обновления данных при наличии внешних ключей. Например, если есть две таблицы:
CREATE TABLE Main (
Id INTEGER PRIMARY KEY
)
CREATE TABLE Child (
Id INTEGER PRIMARY KEY,
MainId INTEGER NOT NULL REFERENCES Main(Id)
)
то при удалении записи из Main, на которую имеются ссылки в Child, триггер на Main не сработает. Чтобы обойти эту проблему, рекомендуется создать хранимую процедуру
CREATE PROCEDURE DeleteFromMain
@Id INTEGER
AS BEGIN
DECLARE @Result INTEGER
BEGIN TRANSACTION
SAVE TRANSACTION DeleteFromMain
DELETE Child WHERE MainId = @Id
DELETE Main WHERE Id = @Id
SET @Result = @@ERROR
IF @Result <> 0
ROLLBACK TRANSACTION DeleteFromMain
COMMIT
END
Другой способ — реализация ограничений ссылочной целостности только при помощи триггеров.
Кроме того, в версии Microsoft SQL Server 2000 возможно создание триггеров INSTEAD OF, которые выполняются вместо вызвавшей их операции. При этом ответственность за запись данных в таблице полностью лежит на программисте. Такие триггеры могут быть созданы на представлениях (VIEW), что позволяет сделать обновляемым любое представление, независимо от его сложности.
Операторы могут быть отправлены на сервер не поодиночке, а пакетами. Пакетом (batch) называется группа команд, отправленная клиентским приложением на сервер одновременно. Весь пакет компилируется в единый план исполнения. Такая техника позволяет уменьшить сетевой трафик и увеличить эффективность приложения. Типичный пакет может выглядеть следующим образом:
BEGIN TRANSACTION
INSERT One (SomeField) VALUES (:1)
INSERT Two (AnotherField) VALUES (:2)
IF @@ERROR = 0
COMMIT
ELSE
ROLLBACK
Внутри пакета возможно объявление переменных. Область их видимости ограничена пакетом, в котором они объявлены.
Весь пакет не выполняется в случае синтаксической ошибки в любом из операторов пакета. Однако в случае ошибки выполнения любого оператора остальные операторы продолжают исполняться до окончания пакета.
Разделителем пакетов команд служит оператор GO.
Для того чтобы проинформировать клиентское приложение об ошибке, Microsoft SQL Server использует функцию RAISERROR. При этом необходимо помнить, что:
При возникновении ошибки в каком-либо из операторов внутри пакета выполнение пакета продолжается, а функция @@ERROR возвращает код ошибки, который можно обработать.
INSERT MyTable (Name) VALUES (‘Петров’)
IF @@ERROR != 0
PRINT ‘Ошибка вставки’.
После успешного оператора @@ERROR возвращает 0, поэтому если значение ошибки может понадобиться впоследствии, то его необходимо сохранить в переменной.
DECLARE @ErrCode INTEGER
SET @ErrCode = 0
BEGIN TRANSACTION
INSERT MyTable (Name) VALUES (‘Иванов’)
IF @@ERROR != 0
@ErrCode = @@ERROR
INSERT MyTable (Name) VALUES (‘Петров’)
IF @@ERROR != 0
@ErrCode = @@ERROR
IF @ErrCode = 0
COMMIT
ELSE BEGIN
ROLLBACK
RAISERROR(‘Не удалось обновить данные’, 16, 1)
END
Если оператор обновления данных не нашел ни одной записи, ошибки не возникает. Проверить эту ситуацию можно при помощи функции @@ROWCOUNT, которая возвращает количество записей, обработанных последним оператором.
UPDATE MyTable
SET Name = ‘Сидоров’
WHERE Name = ‘Петров’
IF @@ROWCOUNT = 0
PRINT ‘Петров не найден’
Дополнительную информацию Вы можете получить в компании Interface Ltd.
Обсудить на форуме
Borland
Отправить
ссылку на страницу по e-mail
Interface Ltd. Отправить E-Mail http://www.interface.ru |
|
Ваши
замечания и предложения отправляйте
автору По техническим вопросам обращайтесь к вебмастеру Документ опубликован: 13.06.02 |