АИС “Метроконтроль”: массовое удаление из справочника записей о типах СИ
Добрый день, уважаемые коллеги. Андрей Высоцкий, мой коллега по нынешнему месту работы, порекомендовал мне открыть рубрику по АИС “Метроконтроль”, но всё как-то повода не было. Сегодня появился.
Возникла необходимость “почистить” справочник СИ, убрать из него те типы СИ, поверку которых мы не осуществляем. А версия 2.3 АИС “Метроконтроль” не позволяет выполнять групповое удаление – только по одной записи из справочника. А записей – больше 25000. О поисках решения речь и пойдёт дальше.
SQL Management Studio поможет нам в решении данного вопроса. После недолгого поиска нашёл таблицу, которая содержит необходимые для меня сведения. И простейший запрос позволяет мне получить из справочника СИ, отнесённые к определённым областям измерений:
SELECT MEASURE_TYPE.MEASURE_TYPE_CODE, MEASURE_TYPE.MEASURE_TYPE_NAME, DEVICE_TYPE.* FROM MEASURE_TYPE INNER JOIN DEVICE_TYPE ON MEASURE_TYPE.MEASURE_TYPE_CODE_ID = DEVICE_TYPE.MEASURE_TYPE_CODE_ID WHERE (MEASURE_TYPE.MEASURE_TYPE_CODE IN ('38', '36'))
Я выбирал 38 и 36 области (ну не осуществляем мы поверку в этих областях). Но с запросом проблем нет, задача стоит – удалить записи. А вот здесь как раз всё не так просто. Дело в том, что на таблицу DEVICE_TYPE
разработчики “повесили” триггер на удаление (точнее – не только на удаление, но на удаление в том числе). Приведу его код:
CREATE TRIGGER [dbo].[DEVICE_TYPE_DELETE] ON [dbo].[DEVICE_TYPE] INSTEAD OF DELETE AS BEGIN SET NOCOUNT ON DECLARE @numberDeleted int DECLARE @deletedId bigint DECLARE @changeId bigint DECLARE @sessionId int DECLARE @DelTime DateTime; SET @DelTime=GetDate(); select @numberDeleted = count(*) from deleted where recstate=4; IF (@numberDeleted>0) BEGIN DELETE DEVICE_TYPE FROM DEVICE_TYPE INNER JOIN DELETED ON DEVICE_TYPE.DT_ID = DELETED.DT_ID AND DELETED.RECSTATE=4 END SELECT @numberDeleted = count(*) FROM DELETED WHERE recstate<>4 AND delete_date is null; IF @numberDeleted=0 RETURN IF @numberDeleted <> 1 BEGIN RAISERROR ('Can delete only 1 record at a time.', 16, 1) RETURN END SELECT @deletedId = DT_ID, @sessionId = SESS_ID FROM DELETED WHERE RECSTATE<>4 AND delete_date is null EXEC setChangeBySessionId @sessionId, @changeId OUTPUT UPDATE DEVICE_TYPE SET RECSTATE = 2, SESS_ID = NULL, DELETE_DATE = @DelTime, DELETION_ID = @changeId WHERE DT_ID = @deletedId UPDATE CALIBR_SCHED_REC SET DELETE_DATE=@DelTime, RECSTATE=2--Удаление графиков поверок для удалённых СИ WHERE DT_ID = @deletedId SET NOCOUNT OFF END
Этот триггер, в общем то, должен помочь нам решить поставленную задачу. Суть его в том, что записи на самом деле не будут удалены, лишь будут заполнены столбцы DELETE_DATE
, DELETION_ID
, и изменён столбец RECSTATE
. Логика такова: для конкретной рабочей станции и конкретного пользователя регистрируются операции через сохранённую процедур setChangeBySessionId
, и далее – с этой операцией связываются изменённые записи, в нашем случае связь через DELETION_ID
. Но код триггера написан таким образом, что он не в состоянии обработать более одной удаляемой записи. И причина не только в условии. Посему первое, что мы должны – изменить триггер так, чтобы обеспечить поддержку группового удаления. Сделаем это:
USE [Ваша база] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER TRIGGER [dbo].[DEVICE_TYPE_DELETE] ON [dbo].[DEVICE_TYPE] INSTEAD OF DELETE AS BEGIN SET NOCOUNT ON DECLARE @numberDeleted int DECLARE @deletedId bigint DECLARE @changeId bigint DECLARE @sessionId int DECLARE @DelTime DateTime; SET @DelTime=GetDate(); DELETE DEVICE_TYPE FROM DEVICE_TYPE INNER JOIN DELETED ON DEVICE_TYPE.DT_ID = DELETED.DT_ID WHERE DELETED.RECSTATE=4 SELECT @numberDeleted = count(*) FROM DELETED WHERE recstate<>4 AND delete_date is null; IF @numberDeleted=0 RETURN SELECT TOP 1 @sessionId = SESS_ID FROM DELETED WHERE RECSTATE<>4 AND delete_date is null EXEC setChangeBySessionId @sessionId, @changeId OUTPUT UPDATE DEVICE_TYPE SET RECSTATE = 2, SESS_ID = NULL, DELETE_DATE = @DelTime, DELETION_ID = @changeId WHERE DT_ID IN (SELECT DT_ID FROM DELETED WHERE RECSTATE<>4 AND delete_date is null) --Удаление графиков поверок для удалённых СИ UPDATE CALIBR_SCHED_REC SET DELETE_DATE=@DelTime, RECSTATE=2 WHERE DT_ID IN (SELECT DT_ID FROM DELETED WHERE RECSTATE<>4 AND delete_date is null) SET NOCOUNT OFF END
В таком виде триггер уже способен корректно обработать и групповое удаление. Теперь нам осталось только выполнить как таковое групповое удаление. Приведу код на примере удаления типов СИ для двух областей измерений – 36 и 38:
DELETE DEVICE_TYPE FROM DEVICE_TYPE INNER JOIN MEASURE_TYPE ON MEASURE_TYPE.MEASURE_TYPE_CODE_ID = DEVICE_TYPE.MEASURE_TYPE_CODE_ID WHERE (MEASURE_TYPE.MEASURE_TYPE_CODE IN ('38', '36'))
После удаления любопытно будет посмотреть на результат – записи то в таблице останутся (Метроконтроль их более показывать не будет, для него они удалены), но уже будут видоизменены:
SELECT MEASURE_TYPE.MEASURE_TYPE_CODE, MEASURE_TYPE.MEASURE_TYPE_NAME, DEVICE_TYPE.* FROM MEASURE_TYPE INNER JOIN DEVICE_TYPE ON MEASURE_TYPE.MEASURE_TYPE_CODE_ID = DEVICE_TYPE.MEASURE_TYPE_CODE_ID WHERE (MEASURE_TYPE.MEASURE_TYPE_CODE IN ('38', '36'))
Естественно, у Вас могут быть иные критерии, но основной задачей этой статьи было решение проблемы с групповым удалением, и задача решена.
P.S> Буду благодарен, если подскажете, как обстоят дела с групповым удалением в новых версиях Метроконтроля.
Отзывы » (1)
RSS комментарии
Обратная ссылка
Здесь можно почитать про создание триггера через PowerShell. Так что если потребуется, смогу написать «patch» на PowerShell.