Смекни!
smekni.com

Разработка физической модели базы данных "Учёт характеристик сигналов телемеханики" (стр. 2 из 4)

ALTER TABLE TUTSSignals ADD CONSTRAINT

СK_TUTSSignals_SignificantBit CHECK (SignificantBit]<8)

Декларативный механизм не позволил задать некоторых ограничений целостности. Вместо этого использовались триггеры.

Во-первых, номера ПЛК в пределах одного РНУ должны быть уникальны.

CREATE TRIGGER UniquePLCNumberInRNU

ON PLCs

FOR INSERT, UPDATE

AS

DECLARE @NumPLCs INT

SELECT @NumPLCs = COUNT(ALL i.ID_PLC)

FROM PLCs p INNER JOIN inserted i

ON p.ID_RNU = i.ID_RNU

WHERE p.NumberPLC = i.NumberPLC

IF @NumPLCs > 0

BEGIN

raiserror(Попытка внести в базу данных ПЛК с уже занятым номером!', 16, 1)

ROLLBACK TRAN

END

Во-вторых, адреса МЭК сигналов, принадлежащих одному ПЛК должны быть уникальны.

CREATE TRIGGER UniqueMEKAdressOnPLC

ON TITRSignals

FOR INSERT, UPDATE

AS

DECLARE @NumTITRS INT

DECLARE @NumTUTSS INT

SELECT @NumTITRS = COUNT(ALL s.ID_TITRSignal)

FROM TITRSignals s INNER JOIN inserted i

ON s.ID_PLC = i.ID_PLC

WHERE s.MEKAdress = i.MEKAdress

SELECT @NumTUTSS = COUNT(ALL s.ID_TUTSSignal)

FROM TUTSSignals s INNER JOIN inserted i

ON s.ID_PLC = i.ID_PLC

WHERE s.MEKAdress = i.MEKAdress

IF (@NumTITRS + @NumTUTSS) > 0

BEGIN

raiserror(Попытка внести в базу данных сигнал с уже занятым МЭК адресом для данного ПЛК!', 16, 1)

ROLLBACK TRAN

END

В данных случаях программная поддержка целостности является единственным способом обеспечения согласованности и корректности хранимых данных.

Поддержание бизнес-логики и бизнес-правил

При выполнении курсового проекта по дисциплине «Информационные технологии» была построена DFD процесса «Учёт сигналов телемеханики» (Приложение 2). На этом этапе он был декомпозирован на 4 подпроцесса;

1. Выдать данные о несовпадающих сигналах

2. Принять заявку

3. Выдать данные о сигналах

4. Найти заявку

Произведя анализ входных и выходных потоков, был составлен словарь данных, на основании которого в конечном итоге мы получили сначала концептуальную, а затем логическую модели БД (курсовой проект по дисциплине «Управление данными»). Физическая модель, созданная при выполнении данного проекта, поддерживает бизнес-логику данного процесса.

Для ввода новых данных по характеристикам сигналов составляется специальная заявка (Приложение 3). В выполнении данной операции участвует 12 хранимых процедур. Внесение заявки в базу данных выполняется в рамках одной сериализуемой транзакции. Такой уровень изоляции был выбран для обеспечения лучшей изоляции обрабатываемых данных во время транзакции. Учитывая то, что заявки выполняются намного реже просмотра данных, это оправданное решение. Если во время какой-либо из процедур произошёл сбой, она откатывает транзакцию.

Ниже они изображены на диаграмме в той последовательности, в которой вызываются.



Сперва хранимее процедуры GetTITRSignalsOnPLC и GetTUTSSignalsOnPLC возвращают администратору СПТЗ список сигналов соответствующих данному ПЛК.

CREATE proc GetTITRSignalsOnPLC

@NameRNU VARCHAR(50),

@NumberPLC INT

AS

DECLARE @ID_PLC INT

exec @ID_PLC = FindPLC @NameRNU, @NumberPLC, 0

SELECT NameDataType, NameSignal, MEKAdress, MaxEnginGrade, MinEnginGrade, MaxPhysicGrade, MinPhysicGrade, IsTISignal

FROM (SELECT *

FROM TITRSignals s

WHERE s.ID_PLC = @ID_PLC AND isDeleted != 1) s INNER JOIN DataTypes d

ON s.ID_DataType = d.ID_DataType

Затем, используя предоставленный клиентским приложением интерфейс, пользователь назначает изменяемым сигналам примечания. Стартует транзакция внесения заявки в БД.

Сначала вносятся данные по заявке.

CREATE PROCEDURE InsertRequest

@Prefix CHAR(2),

@Number BIGINT,

@WriteDate DATETIME,

@ID_Request BIGINT OUT

AS

DECLARE @ID_SPTZAdminLogin INT;

SELECT @ID_SPTZAdminLogin = ID_SPTZAdminLogin

FROM SPTZAdminsLogins

WHERE NameLogin = SUSER_NAME()

IF @ID_SPTZAdminLogin IS NULL BEGIN

INSERT INTO SPTZAdminsLogins (NameLogin) VALUES

(SUSER_NAME())

SET @ID_SPTZAdminLogin = @@IDENTITY

END

IF EXISTS(SELECT ID_Request FROM Requests

WHERE Prefix = @Prefix AND Number = @Number)

BEGIN

raiserror('Заявка с таким номером и префиксом уже существует в базе данных!', 15, 1)

RETURN

END

INSERT INTO Requests (Prefix, Number, WriteDate, ExecDate,

ID_SPTZAdminLogin)

VALUES (@Prefix,@Number, @WriteDate, GETDATE(),

@ID_SPTZAdminLogin)

SET @ID_Request = @@IDENTITY

Эта процедура возвращает приложению, её вызвавшему ID заявки, по которому оно далее может добавлять, редактировать, удалять сигналы.

В целях предотвращения намеренной подмены даты исполнения заявки на стороне клиента, данная процедура делает подзапрос к процедуре GetCurrentDateTime.

CREATE PROCEDURE GetCurrentDateTime @CurrDateTime DATETIME OUT

AS

SET @CurrDateTime = GETDATE()

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

Следующим этапом с использованием InsertTITRSignal, InsertTUTSSignal добавляются сигналы в базу данных, UpdateTITRSignal, UpdateTUTSSignal – обновляются, DeleteSignal – удаляются.

Ниже приведён код некоторых из этих процедур:

REATE PROCEDURE InsertTITRSignal

@NameDataType VARCHAR(20),

@NameSignal VARCHAR(50),

@MEKAdress SMALLINT,

@MaxEnginGrade INT,

@MinEnginGrade INT,

@MaxPhysicGrade INT,

@MinPhysicGrade INT,

@Comment VARCHAR(300) = NULL,

@NameRNU VARCHAR(50),

@NamePLC VARCHAR(50),

@NumberPLC INT,

@ID_Request BIGINT,

@IsTISignal BIT

AS

DECLARE @ID_PLC INT

EXEC @ID_PLC = FindPLCWithInsUpd @NameRNU,

@NamePLC,@NumberPLC

DECLARE @TITRSigCount INT

SELECT @TITRSigCount = COUNT(ID_TITRSignal)

FROM TITRSignals

WHERE ID_PLC = @ID_PLC AND MEKAdress = @MEKAdress AND

IsDeleted = 0

DECLARE @TUTSSigCount INT

SELECT @TUTSSigCount = COUNT(ID_TUTSSignal)

FROM TUTSSignals

WHERE ID_PLC = @ID_PLC AND MEKAdress = @MEKAdress AND

IsDeleted = 0

IF (@TITRSigCount + @TUTSSigCount) > 0 BEGIN

raiserror('Сигнал с Адресом МЭК %d, принадлежащий ПЛК №%d из РНУ %s уже содержится в базе данных! Вставка невозможна.', 16, 1, @MEKAdress, @NumberPLC, @NameRNU)

RETURN

END

DECLARE @ID_DataType INT

EXEC @ID_DataType = FindDataTypeWithInsUpd @NameDataType

INSERT INTO TITRSignals (NameSignal, MEKAdress,

MaxEnginGrade, MinEnginGrade, MaxPhysicGrade,

MinPhysicGrade, Comment, IsDeleted, ID_PLC,

ID_DataType, ID_Request, IsTISignal)

VALUES(@NameSignal,@MEKAdress, @MaxEnginGrade,

@MinEnginGrade, @MaxPhysicGrade,

@MinPhysicGrade, @Comment, 0, @ID_PLC, @ID_DataType,

@ID_Request, @IsTISignal)

CREATE PROCEDURE UpdateTITRSignal

@NameDataType VARCHAR(20),

@NameSignal VARCHAR(50),

@MEKAdress SMALLINT,

@MaxEnginGrade INT,

@MinEnginGrade INT,

@MaxPhysicGrade INT,

@MinPhysicGrade INT,

@Comment VARCHAR(300) = NULL,

@NameRNU VARCHAR(50),

@NamePLC VARCHAR(50),

@NumberPLC INT,

@ID_Request INT,

@IsTISignal BIT

AS

DECLARE @ID_PLC INT

EXEC @ID_PLC = FindPLC @NameRNU, @NumberPLC, 1

IF @ID_PLC = 0 RETURN

DECLARE @ID_ExRequest INT

SELECT @ID_ExRequest = ID_Request

FROM TITRSignals

WHERE MEKAdress = @MEKAdress AND @ID_PLC = ID_PLC AND IsDeleted = 0 AND

IsTISignal = @IsTISignal

IF COUNT(@ID_ExRequest) = 0 BEGIN

raiserror('Обновляемый сигнал с Адресом МЭК %d, принадлежащий ПЛК №%d из РНУ %s не содержится в базе данных', @MEKAdress, @NumberPLC, @NameRNU, 16, 1)

RETURN

END

IF COUNT(@ID_ExRequest) > 1 BEGIN

raiserror('№%d из РНУ %s принадлежит больше одного сигнала с Адресом МЭК %d! Нарушена целостность базы данных', @MEKAdress, @NumberPLC, @NameRNU, 16, 1)

RETURN

END

DECLARE @ExWriteDate SMALLDATETIME

SELECT @ExWriteDate = WriteDate

FROM Requests

WHERE ID_Request = @ID_ExRequest

DECLARE @WriteDate SMALLDATETIME

SELECT @WriteDate = WriteDate

FROM Requests

WHERE ID_Request = @ID_Request

IF DATEDIFF(day, @WriteDate, @ExWriteDate) > 0

BEGIN

raiserror('Характеристики сигнала с Адресом МЭК %d, принадлежащий ПЛК №%d из РНУ %s изменялись по более новой заявке', 16, 1, @MEKAdress, @NumberPLC, @NameRNU)

END

ELSE

BEGIN

DECLARE @ID_DataType INT

EXEC @ID_DataType = FindDataTypeWithInsUpd @NameDataType

UPDATE TITRSignals SET NameSignal = @NameSignal, MEKAdress = @MEKAdress,

MaxEnginGrade = @MaxEnginGrade, MinEnginGrade = MinEnginGrade, MaxPhysicGrade = @MaxPhysicGrade,MinPhysicGrade = @MinPhysicGrade, Comment = @Comment, ID_DataType = @ID_DataType,

ID_Request = @ID_Request

WHERE MEKAdress = @MEKAdress AND @ID_PLC = ID_PLC AND

IsDeleted = 0 AND IsTISignal = @IsTISignal

END

Процедура InsertTITRSignal использует подпрограмму FindPLCWithInsUp, которая возвращает ID ПЛК с заданным номерам, принадлежащий определённому РНУ. Если РНУ или ПЛК не существует, то он создаются. Тоже самое делает и FindDataTypeWithInsUpd, только с типом данных. В этом заключается одно из преимуществ подхода, избранного для автоматизации бизнес-процесса. Все словари заполняются автоматически. Также предусмотрены триггеры очистки словарей от данных, которые не используются в данный момент ни одной записью дочерних отношений.

Для иллюстрации всего вышесказанного приведём код одной из процедур:

CREATE PROCEDURE FindDataTypeWithInsUpd

@NameDataType VARCHAR(20)

AS

BEGIN

DECLARE @ID_DataType INT

SELECT @ID_DataType = ID_DataType

FROM DataTypes

WHERE NameDataType = @NameDataType

IF @ID_DataType IS NULL BEGIN

INSERT INTO DataTypes (NameDataType) VALUES

(@NameDataType)

SET @ID_DataType = @@IDENTITY

END

RETURN @ID_DataType

END

При вводе данных по характеристикам сигналов может возникнуть такая ситуация, что какой-либо сигналов обновляется по заявке, имеющей дату составления более раннюю, чем заявка, по которой редактировался сигнал, уже хранящийся в базе данных. Разумеется, такое изменение не может быть внесено. В таком случае процедура UpdateTITRSignal откатывает всю транзакцию и даёт пользователю возможность исправить ошибку в базе данных SCADA RealFlex, в которую данные неправильные изменения уже были внесены, а затем повторить всё заново. Конечно, такое развитие событий маловероятно, но предусмотреть его всё-таки стоит.

На этом ввод заявки и сопутствующих данных завершается.

Далее рассмотрим, как формируется единственный выходной документ бизнес-процесса «Учёт сигналов телемеханики»: Данные по характеристикам сигналов ПЛК (Приложение 4). В этом участвуют 5 хранимых процедур и вызываются в следующей последовательности:


Пользователь выбирает название РНУ, затем номер ПЛК, ему принадлежащего и в конечном итоге процедуры FetchtTITRSignalsOnPLC и FetchtTUTSSignalsOnPLC возвращают данные по характеристикам затребованных сигналов. В выходной форме сигналы делятся на 4 группы по типу, каждая группа располагается на отдельном листе. Эти хранимые процедуры обеспечивают выборку каждой группы сигналов по отдельности. Таким образом, клиентскому приложению нет необходимости разделять сигналы самостоятельно. Кроме того на каждом листе сигналы сортируются по полю «Адрес МЭК» в возрастающем порядке. Такая форма наиболее удобна для телемехаников.

Почему физическая модель БД включает 4 на первый взгляд по сути одинаковые хранимые процедуры: FetchtTITRSignalsOnPLC, FetchtTUTSSignalsOnPLC, GetTITRSignalsOnPLC, GetTUTSSignalsOnPLC? Отличие первых двух от других заключается в том, что они не предусматривают возможности выборки сигналов только какого-либо одного типа, а особенности организации представления данных в клиентском приложении этого требуют, поэтому были написаны ещё две функции. Вот код одной из них: