Программирование >>  Программирование баз данных 

1 ... 151 152 153 [ 154 ] 155 156 157 ... 346


Учет требований, связанных с совместным использованием нескольких таблиц

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

В качестве иллюстрации рассмотрим таблицы Products и SalesOrderDetail базы данньгх AdventureWorks, а также связанную с ними таблицу SpecialOf f erProduct. Связь между этими таблицами показана на рис. 13.2.

Product (Production)

ProductID Name

SpecielOfferProduct (Sales)

SpecialOfferlD <J ProductID

rowguid

Modif iedDate

SalesOrderDetail (Sales)

9 SalesOrderlD

? SalesOrderDetaillD

CarrierTrachingNumber OrderQty ProductID 5pecialOfferID UnitPrice

UnitPriceDiscount Unelotal

ModlfiedDate ~

ProductNumber MakeFlag FinishedGoodFlag Color

SafetyStockLevel

ReorderPoint

StandardCost

ListPrice

SiseUNtMeasureCode

WeightUritMeasureCode

Weight

DaysToMdnufacture

ProductLine

Class

Style

ProductSubcategorylD

ProductHodellD

5ell5tartDate

SeUEndDate

DiscontinuedDdte

rowguid

ModifiedDate

InformationFlag

Puc. 13.2. Связь между таблицами Products, SalesOrderDetail иSpecialOfferProduct

Следует отметить, что с помощью обычных декларативных средств поддержки ссылочной целостности можно исключить возможность вставки каких-либо позиций заказа в таблицу SalesOrderDetail, если отсутствуют соответствующие значения идентификаторов товаров, ProductID, в таблице Products (доступ к информации об идентификаторах товаров предоставляется через таблицу SpecialOf ferProduct).



Однако для решения сформулированной выше задачи требуется нечто большее, чем обычные средства.

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

Указанную задачу невозможно решить с помощью ограничения CHECK, поскольку о том, что поставка товара прекращена, можно узнать только с помощью отдельной таблицы (таблицы Products), на основании данных которой должно контролироваться ограничение (распространяющееся на таблицу SalesOrderDetail). Но такую задачу несложно решить с помощью триггера. Проверим полученные результаты.

USE AdventureWorks GO

CREATE TRIGGER OrderDetailNotDiscontinued ON Sales.SalesOrderDetail AFTER INSERT, UPDATE

IF EXISTS (

SELECT True

FROM Inserted i

JOIN Production.Product p

ON i.ProductID = p.ProductID vmERE p.DiscontinuedDate IS NOT NULL

BEGIN

RAISERROR(Order Item is discontinued. Transaction Failed.16,1) ROLLBACK TRAN

Приступим к проверке проделанной нами работы. Прежде всего необходимо ввести в базу данных по крайней мере одну строку, при обнаружении которой в ходе выполнения кода триггера будет активизирована ошибка. Иными словами, в таблицу Products необходимо ввести данные хотя бы об одном товаре, поставка которого прекращена; в настоящее время при проверке триггера возникают затруднения, поскольку таких данных в таблице нет.

SELECT ProductID, Name FROM Production.Product WHERE DiscontinuedDate IS NOT NULL ProductID Name

(0 row(s) affected)

Далее, можно выбрать эту строку и попытаться внести в нее изменения для проверки работы триггера:

UPDATE Production.Product

SET DiscontinuedDate = GETDATE()

WHERE ProductID = 680

После завершения этого этапа подготовки можно перейти к проверке работы триггера, поэтому приступим к следующему этапу и введем данные о товарной позиции, которые нарушают указанное ограничение целостности. Для этого достаточно воспользоваться данными о заказе, которые уже существуют в таблице SalesOrderHeader, чтобы нам не приходилось применять сложную процедуру подготовки полного заказа:



INSERT Sales.SalesOrderDetail

(SalesOrderlD, OrderQty, ProductID, SpecialOfferlD, UnitPrice, UnitPriceDiscount) VALUES

(43660, 5, 680, 1, 1431, 0)

В результате попытка ввода недопустимых данных будет отвергнута, как и следовало ожидать:

Msg 50000, Level 16, State 1, Procedure OrderDetailNotDiscontinued, Line 14 Order Item is discontinued. Transaction Failed. Msg 3609, Level 16, State 1, Line 1

The transaction ended in the trigger. The batch has been aborted.

Необходимо также учитывать, что можно было бы также при желании создать определяемое пользователем сообщение об ошибке, которое активизировалось бы вместо произвольного сообщения, используемого в команде RAISERROR.

Применение триггеров для проверки дельты обновления

Иногда интерес представляет не то, каким было или стало значение в результате обновления, а то, насколько изменилось это значение. Безусловно, подобную информацию невозможно найти в каком-либо одном столбце или таблице, но величину изменения можно вычислить с помощью триггера, воспользовавшись таблицами Inserted и Deleted.

Информация о том, что происходит в результате обновления, может применяться во многих цел51х, в частности для обеспечения защиты данных. Например, предположим, что для контроля над модификацией данных необходимо отслеживать любые изменения в информации о товарных запасах, независимо от того, кто был инициатором этих изменений (это позволяет, например, отличить непосредственно внесенные в таблицы корректировки данных о товарных запасах от изменений, которые возникают после оформления прихода или расхода товаров).

Для реализации такого замысла необходимо создать таблицу аудита и обеспечить применение таблиц Inserted и Deleted:

CREATE TABLE Production.InventoryAudit (

TransactionID int IDENTITY PRIMARY KEY,

ProductID int NOT NULL

REFERENCES Production.Product(ProductID), NetAdjustment smallint NOT NULL,

ModifiedDate datetime DEFAULT(CURRENT TIMESTAMP)

CREATE TRIGGER ProductAudit

ON Production.ProductInventory FOR INSERT, UPDATE, DELETE

INSERT INTO Production.InventoryAudit (ProductID, NetAdjustment)

SELECT COALESCE(i.ProductID, d.ProductID),

ISNULL(i.Quantity, 0) - ISNULL(d.Quantity, 0) AS NetAdjustment FROM Inserted i FULL JOIN Deleted d

ON i.ProductID = d.ProductID AND i.LocationID = d.LocationID WHERE ISNULL(i.Quantity, 0) - ISNULL(d.Quantity, 0) != 0



1 ... 151 152 153 [ 154 ] 155 156 157 ... 346

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика