Альтернатива TSQL для курсора, чтобы зациклить данные триггера - PullRequest
0 голосов
/ 09 ноября 2018

В ответах на этот случай

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

ОБНОВЛЕНИЕ:

Ниже приведен TSQL для создания этого триггера обновления.

CREATE TRIGGER [dbo].[trAfterUpdateInfoDoc]
ON [dbo].[InfoDocs]
AFTER UPDATE
AS
BEGIN
    DECLARE @infodoctemplateid INT;
    DECLARE @infodocid INT;
    DECLARE @requireccount FLOAT(2);
    DECLARE @filledcount FLOAT(2);
    DECLARE @pcnt FLOAT(2);

    DECLARE c CURSOR FOR
         SELECT id 
         FROM InfoDocs ifd 
         WHERE exists (SELECT 1 FROM Inserted AS i WHERE i.id = ifd.id)

    OPEN c

    FETCH NEXT FROM c INTO @infodocid

    WHILE @@Fetch_Status = 0 
    BEGIN
        SELECT @infodoctemplateid = InfoDocTemplateId 
        FROM InfoDocs 
        WHERE id = @infodocid;

        SELECT @requireccount = COUNT(*) 
        FROM InfoDocTemplateFields 
        WHERE InfoDocTemplateId = @infodoctemplateid 
          AND IsRequired = 1;

        IF (@requireccount = 0)
        BEGIN
            set @pcnt = 100;
        END
        ELSE
        BEGIN
            select @filledcount = count(*) from InfoDocFields 
            where InfoDocId = @infodocid 
            and InfoDocTemplateFieldId in (select id from InfoDocTemplateFields where InfoDocTemplateId = @infodoctemplateid and IsRequired = 1)
            and (BooleanValue is not null or (StringValue is not null and StringValue <> '') or IntValue is not null or DateValue is not null)

            set @pcnt = @filledcount / @requireccount * 100.0;
        END
        update InfoDocs set PercentageCompleted = @pcnt Where id = @infodocid;

        Fetch next From c into @infodocid
    End
Close c
Deallocate c
END

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

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

CREATE TRIGGER [dbo].[trAfterUpdateInfoDoc]
ON [dbo].[InfoDocs]
AFTER UPDATE
AS
BEGIN
    WITH CTE1 AS
    (
        SELECT  ifd.Id, 
                SUM(CASE WHEN IsRequired = 1 THEN 1 ELSE 0 END) As RequiredCount,
                (
                    select count(*) 
                    from InfoDocFields 
                    where InfoDocFields.InfoDocId = ifd.Id,
                    and InfoDocTemplateFieldId in (
                        select id 
                        from InfoDocTemplateFields 
                        where InfoDocTemplateId = idtf.InfoDocTemplateId 
                        and IsRequired = 1
                    )
                    and 
                        InfoDocFields.BooleanValue is not null 
                        or (InfoDocFields.StringValue is not null and InfoDocFields.StringValue <> '') 
                        or InfoDocFields.IntValue is not null 
                        or InfoDocFields.DateValue is not null

                ) As Filledcount
        FROM InfoDocs ifd 
        JOIN InfoDocTemplateFields idtf
            ON ifd.InfoDocTemplateId = idtf.InfoDocTemplateId
        WHERE exists (SELECT 1 FROM Inserted AS i WHERE i.id = ifd.id)
        GROUP BY ifd.Id, idtf.InfoDocTemplateId
    ), CTE2 AS
    (
        SELECT  ifd.Id, 
                CASE WHEN RequiredCount = 0 THEN 
                    100
                ELSE
                    Filledcount / RequiredCount * 100.0
                END As Completed
        FROM CTE1
    )

    UPDATE docs 
    SET PercentageCompleted = Completed 
    FROM InfoDocs docs
    JOIN cte2 
        ON docs.id = cte2.Id

END
0 голосов
/ 09 ноября 2018

Вы можете избавиться от курсора, выполнив обновление с помощью соединения.

* 1003 Е.Г. *

UPDATE t1
SET Col2 = t2.Col2,
Col3 = t2.Col3
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.Col1 = t2.Col1
WHERE t1.Col1 IN (21, 31)

Это даст вам максимально возможную производительность. И код будет более компактным и простым для понимания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...