SQL Server - можно ли заменить эти курсоры чем-то другим? - PullRequest
0 голосов
/ 20 января 2019

Во-первых, вот несколько таблиц и данных для теста:

CREATE TABLE [dbo].[MyOrders]
(
    [ID] [int] NOT NULL,
    [ref_type] [nchar](1) NOT NULL,
    [ref_num] [nvarchar](15) NULL,
    [req_cert] [nvarchar](255) NULL,
 CONSTRAINT [PK_MyOrders] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[MyJobs]
(
    [job_id] [nvarchar](15) NOT NULL,
    [job_message] [nvarchar](255) NULL,
 CONSTRAINT [PK_MyJobs] PRIMARY KEY CLUSTERED 
(
    [job_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[MyTypes]
(
    [type] [nvarchar](255) NOT NULL,
    [value] [nvarchar](255) NOT NULL
) ON [PRIMARY]
GO

INSERT INTO [dbo].[MyOrders] ([ID], [ref_type], [ref_num], [req_cert])
VALUES (1, 'J', 'Job0001', 'Cert1')
GO

INSERT INTO [dbo].[MyJobs] ([job_id], [job_message])
VALUES ('Job0001', 'Accepted')
GO

INSERT INTO [dbo].[MyTypes] ([type], [value])
VALUES ('MyCerts', 'Cert1'),
       ('MyCerts', 'Cert2')
GO

Таблица MyOrders содержит мои заказы, которые могут ссылаться на работу в таблице MyJobs. MyOrder может указывать req_cert, который затем будет отображаться в поле job_message. req_cert будет иметь значения из таблицы MyTypes, где type == 'MyCert'

Я пытаюсь создать триггер, который при обновлении таблицы req_cert или ref_num таблицы MyOrders выполняет следующие действия:

  1. Обновлено ли одно из этих 2 полей?

  2. Это ref_type == J и ref_num is not null?

  3. Выберите существующий job_message и проверьте, нет ли значения в таблице MyTypes.

  4. Если есть, заменить его значением от req_cert

  5. Если нет, добавьте req_cert

Я написал этот триггер для этого, но я не знаю, лучший ли это способ:

ALTER TRIGGER [dbo].[UpdateCert] 
ON [dbo].[MyOrders]
FOR UPDATE
AS
    SET NOCOUNT ON

    IF (NOT UPDATE ([req_cert])
        AND NOT UPDATE ([ref_num]))
       RETURN

    DECLARE @ID NVARCHAR(50)
    DECLARE @Certificate NVARCHAR(255)
    DECLARE @OldValue NVARCHAR(255)
    DECLARE @Found TINYINT
    DECLARE @JobMessage NVARCHAR(2000)

    DECLARE InsertCursor CURSOR FAST_FORWARD FOR
        SELECT ref_num, req_cert
        FROM Inserted

    OPEN InsertCursor

    FETCH NEXT FROM InsertCursor INTO @ID, @Certificate

    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF (NOT EXISTS (SELECT ref_num
                        FROM MyOrders
                        WHERE ref_type = 'J'
                          AND ref_num = @ID))
        BEGIN
            FETCH NEXT FROM InsertCursor INTO @ID, @Certificate
            CONTINUE
        END

        SELECT @JobMessage = job_message
        FROM MyJobs
        WHERE job_id = @ID

        DECLARE CertCursor CURSOR FAST_FORWARD FOR
             SELECT [Value]
             FROM MyTypes
             WHERE [Type] = 'MyCerts'

        OPEN CertCursor

        FETCH NEXT FROM CertCursor INTO @OldValue

        WHILE @@FETCH_STATUS = 0
        BEGIN
            IF (@JobMessage LIKE '%' + @OldValue + '%')
            BEGIN
                SET @Found = 1
                BREAK
            END

            FETCH NEXT FROM CertCursor INTO @OldValue
        END

        CLOSE CertCursor
        DEALLOCATE CertCursor

        IF (@Found = 1)
        BEGIN
            SELECT @JobMessage = REPLACE(@JobMessage, @OldValue, '')
        END

        UPDATE MyJobs WITH (ROWLOCK)
        SET job_message = ISNULL(@Certificate, '') + ISNULL(@JobMessage, '')
        WHERE MyJobs.job_id = @ID

        FETCH NEXT FROM InsertCursor INTO @ID, @Certificate
    END

    CLOSE InsertCursor
    DEALLOCATE InsertCursor

УСКОРЕННЫЕ РЕЗУЛЬТАТЫ (при условии данных сверху):

UPDATE MyOrders
SET req_cert = 'Cert1'
WHERE ID = 1

job_message должно быть Cert1 Accepted

UPDATE MyOrders
    SET req_cert = 'Cert2'
    WHERE ID = 1

job message должно быть Cert2 Accepted

UPDATE MyOrders
SET ref_num = null
WHERE ID = 1
GO
UPDATE MyOrders
SET  req_cert = 'Cert1'
WHERE ID = 1
GO
UPDATE MyOrders
SET ref_num = 'Job0001'
WHERE ID = 1

job message должно быть Cert1 Accepted

...