Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Проектирование и разработка баз данных. Лаборат...doc
Скачиваний:
0
Добавлен:
04.01.2020
Размер:
3.07 Mб
Скачать

4.5Курсоры

В листингах будут использоваться курсоры.

Курсор – это указатель на набор записей. Обычно курсоры определяются с помощью операторов SELECT. Например, оператор в листинге 3 определяет курсор под названием TransCursor, действующий на наборе строк, указанном в операторе SELECT. Когда прикладная программа открывает курсор и считывает первую строку, о курсоре говорят, что он «указывает на первую строку».

Листинг 3

DECLARE TransCursor CURSOR

FOR SELECT *

FROM TRANS

WHERE SalesPrice > 10000;

4.6Хранимые процедуры

Хранимые процедуры используются для многих целей. Хотя администраторы баз данных используют их для выполнения рутинных задач администрирования, главной областью их применения являются все же приложения баз данных. Эти процедуры могут вызываться из прикладных программ, написанных на таких языках, как Java, C#, C++ или VB.Net, а также из веб-сценариев, написанных на VBScript или JavaScript. Кроме того, эти процедуры можно вызывать в интерактивном режиме из командной оболочки СУБД – например, SQL*Plus в Oracle или Query Analyzer в SQL Server. Наконец, хранимые процедуры как Oracle, так и SQL Server могут вызываться из среды Microsoft Visual Studio.NET.

Как и с другими структурами базы данных, вы можете записать текст процедуры в файл и выполнить ее в среде Microsoft SQL Server Management Studio Express. Есть только одна особенность, которую необходимо знать. В первый раз, когда вы записываете процедуру в текстовый файл, начните ее ключевыми словами CREATE PROCEDURE. Потом, если вы захотите изменить процедуру, поменяйте эти слова на ALTER PROCEDURE, противном случае при попытке запуска измененной процедуры вы получите общение об ошибке, гласящее, что такая процедура уже существует.

Внимание! Помните, что вы не сможете сохранить процедуру в базе данных, пока не исправите все синтаксические ошибки.

4.6.1 Хранимая процедура Customer_Insert. В листинге 4 изображена хранимая процедура, которая сохраняет в базе данных информацию о новом клиенте и связывает этого клиента со всеми художниками заданной национальности. Процедура имеет четыре входных параметра: @NewName, @NewAreaCode, @NewPhone и @Nationality. Как вы можете видеть, параметры и переменные в TRANSACT-SQL предваряются символом @. Первые три параметра – это данные нового клиента, а четвертый параметр представляет собой национальность художников, которыми интересуется новый клиент.

Листинг 4. Хранимая процедура Customer_Insert

CREATE PROCEDURE dbo.Customer_Insert

@NewName char(25),

@NewAreaCode char(3),

@NewPhone char(8),

@Nationality char(30)

AS

DECLARE @Count as smallint

DECLARE @Aid as int

DECLARE @Cid as int

/* Проверяем, нет ли данного клиента в базе */

SELECT @Count=Count(*)

FROM dbo.CUSTOMER

WHERE [Name] = @NewName AND AreaCode = @NewAreaCode AND

PhoneNumber = @NewPhone;

IF @Count > 0

BEGIN

PRINT 'Клиент уже есть в базе данных - никаких действий не предпринято' RETURN

END

/* Добавляем данные о новом клиенте */

INSERT INTO dbo.CUSTOMER ([Name], AreaCode, PhoneNumber)

VALUES (@NewName, @NewAreaCode, @NewPhone);

/* Получаем новое значение суррогатного ключа */

SELECT @Cid=CustomerID

FROM dbo.CUSTOMER

WHERE [Name] = @NewName AND AreaCode = @NewAreaCode AND

PhoneNumber = @NewPhone;

/* Создаем запись в таблице пересечения для каждого художника */

DECLARE Artist_Cursor CURSOR FOR

SELECT ArtistID

FROM dbo.ARTIST

WHERE Nationality=@Nationality;

/* Обрабатываем каждого художника выбранной национальности */

OPEN Artist_Cursor

FETCH NEXT FROM Artist_Cursor INTO @Aid

WHILE @@FETCH_STATUS = 0

BEGIN

INSERT INTO dbo.[CUSTOMER_ARTIST_INT](ArtistID, CustomerID)

VALUES (@Aid, @Cid)

FETCH NEXT FROM Artist_Cursor INTO @Aid

END

CLOSE Artist_Cursor

DEALLOCATE Artist_Cursor

Первая задача, которую выполняет данная хранимая процедура, – проверить, нет ли записи об этом клиенте в базе данных. Если count в первом операторе SELECT оказывается больше 0, это значит, что строка для данного клиента уже существует. Тогда никаких действий не предпринимается, хранимая процедура выводит сообщение об ошибке и завершает свою работу. Это сообщение об ошибке, между прочим, будет видно в Query Analyzer или в Management Sdudio Express, но в общем случае не будет видимым для прикладных программ, вызывающих данную процедуру. Передать сообщение об ошибке пользователю через прикладную программу можно с помощью параметра или каким-нибудь другим способом.

Далее процедура вставляет новые данные в таблицу dbo.CUSTOMER и считывает новое значение CustomerID в переменную @Cid.

Чтобы создать соответствующие строки в таблице пересечения, с помощью SQL-оператора открывают курсор, возвращающий все строки из таблицы ARTIST, в которых значение столбца Nationality равно значению параметра @Nationality. Курсор обрабатывается в цикле LOOP, в процессе чего в таблицу пересечения CUSTOMER_ARTIST_INT вставляются новые строки. Оператор FETCH передвигает курсор на следующую строку.

На рис. 4.3 показано, как с помощью этой хранимой процедуры, вызываемой из Management Sdudio Express, добавить в базу данных нового клиента, интересующегося художниками из США. В таблицу CUSTOMER был добавлен покупатель Michael Bench.

exec Customer_Insert @NewName='Michael Bench', @NewAreaCode='203',

@NewPhone='555-3014', @Nationality='US';

Рис. 4.3. Вызов процедуры Customer_Insert

Рис. 4.4. Повторный вызов процедуры Customer_Insert с теми же параметрами

4.6.2 Хранимая процедура NewCustomerWithTransaction. В листинге 5 представлена хранимая процедура, добавляющая в базу данных информацию о новом клиенте и регистрирующая покупку им произведения. Эта процедура принимает семь параметров, содержащих данные о новом клиенте и его покупке.

Листинг 5. Хранимая процедура NewCustomerWithTransaction

CREATE PROCEDURE dbo.NewCustomerWithTransaction

@NewName char(25), @NewAreaCode char(3), @NewPhone char(8),

@ArtistName char(25), @WorkTitle char (25), @WorkCopy char (8),

@Price numeric(8,2)

AS

DECLARE @Count as int,

@Aid as int,

@Cid as int,

@Wid as int,

@Tid as int

SELECT @Count=Count(*)

FROM dbo.CUSTOMER

WHERE [Name] = @NewName AND AreaCode = @NewAreaCode AND

PhoneNumber=@NewPhone;

IF @Count > 0

BEGIN

PRINT 'Клиент уже есть в базе данных - никаких действий не предпринято' RETURN

END

BEGIN TRANSACTION /* Начинаем транзакцию: если есть проблемы, производим откат */

INSERT INTO dbo.CUSTOMER ([Name], AreaCode, PhoneNumber)

VALUES (@NewName, @NewAreaCode, @NewPhone);

SELECT @Cid=CustomerID

FROM dbo.CUSTOMER

WHERE [Name] = @NewName AND AreaCode = @NewAreaCode AND

PhoneNumber = @NewPhone;

SELECT @Aid=ArtistID

FROM dbo.Artist

WHERE ArtistName = @ArtistName

IF @Aid IS NULL /* Неправильный ArtistID */

BEGIN

Print 'Неправильное значение ArtistID'

ROLLBACK

RETURN

END

SELECT @Wid=WorkID

FROM dbo.[WORK]

WHERE ArtistID = @Aid AND Title = @WorkTitle AND Copy = @WorkCopy

IF @Wid IS NULL /* Неправильный WorkID */

BEGIN

Print 'Неправильное значение WorkID'

ROLLBACK

RETURN

END

SELECT @Tid=TransactionID

FROM dbo.[TRANS]

WHERE WorkID = @Wid AND SalesPrice IS NULL

IF @Tid IS NULL /* Неправильный TransactionID */

BEGIN

Print 'Нет ни одной транзакции'

ROLLBACK

RETURN

END

UPDATE dbo.[TRANS] /* Все в порядке, обновляем строку в таблице TRANS */SET PurchaseDate = GETDATE(), SalesPrice = @Price, CustomerID = @Cid

WHERE TransactionID = @Tid

INSERT INTO dbo.[CUSTOMER_ARTIST_INT] (ArtistID, CustomerID)

VALUES (@Aid, @Cid)

COMMIT

Первое, что нужно сделать, – это проверить, не существует ли уже этот клиент в базе данных; если да, то процедура завершает работу с сообщением об ошибке. Если этого клиента нет в базе данных, процедура начинает транзакцию. Транзакции гарантируют атомарность действий, выполняемых с базой данных: либо выполняются все обновления, либо не выполняется ни одного. Итак, начинается транзакция, и в таблицу CUSTOMER вставляется строка для нового клиента. Далее считывается новое значение CustomerID, как показано выше. Затем процедура проверяет допустимость значений ArtistID, WorkID и TransactionID. Если хотя бы одно из них является некорректным, происходит откат транзакции.

Если все перечисленные значения правильны, оператор UPDATE обновляет столбцы PurchaseDate, Price и CustomerID в соответствующей строке таблицы TRANS. В столбец PurchaseDate записывается системная дата (с помощью системной функции GETDATE()), в столбец SalesPrice — значение параметра @Рriсе, а в столбец CustomerID – значение переменной @Cid. Наконец, добавляется строка в таблицу CUSTOMER_ARTIST_INT, чтобы зарегистрировать интерес клиента к данному художнику. Если до этого момента все идет нормально, транзакция сохраняется.

На рис. 4.5 показан вызов этой процедуры с тестовыми данными.

exec NewCustomerWithTransaction

@NewName='Иванов Иван', @NewAreaCode='203', @NewPhone='2242-2678',

@ArtistName=Дэвид Шор', @WorkTitle=Доктор Хаус',

@WorkCopy='1', @Price=100000

Рис. 4.5 Вызов процедуры NewCustomerWithTransaction