АИС “Метроконтроль”: массовое удаление из справочника записей о типах СИДобрый день, уважаемые коллеги. Андрей Высоцкий, мой коллега по нынешнему месту работы, порекомендовал мне открыть рубрику по АИС “Метроконтроль”, но всё как-то повода не было. Сегодня появился.

Возникла необходимость “почистить” справочник СИ, убрать из него те типы СИ, поверку которых мы не осуществляем. А версия 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> Буду благодарен, если подскажете, как обстоят дела с групповым удалением в новых версиях Метроконтроля.

Отзывы » (2)

  1. Здесь можно почитать про создание триггера через PowerShell. Так что если потребуется, смогу написать «patch» на PowerShell.

Опубликовать комментарий

XHTML: Вы можете использовать следующие HTML теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Tags Связь с комментариями статьи:
RSS комментарии
Обратная ссылка