Как удалить временную таблицу в блоке try catch с помощью транзакции SQL

Здравствуйте, у меня есть следующий запрос с транзакцией в блоке try catch, и я откатываю транзакцию в блоке catch в случае сбоя. Проблема в том, что я создаю временную таблицу и не знаю, как с ней справиться с транзакцией. Итак, как я могу безопасно избавиться от временной таблицы в этой ситуации? Я пытался добавить его в блок catch, но не уверен, что это хорошая практика.

ALTER PROCEDURE GetDataForNewListaAbastecimento
    @UAP NVARCHAR(20),
    @ColaboradorId INT
AS
BEGIN

    DECLARE @TransactionName nvarchar(20) = 'GetDataForNewListaAbastecimento'
    DECLARE @Status INT
    DECLARE @CurrentWeekDay INT
    SET DATEFIRST 1
    SET @CurrentWeekDay = DATEPART (WEEKDAY, GETDATE()) - 1

    CREATE TABLE #tempTable
    (
        Id INT PRIMARY KEY,
        Referencia NVARCHAR(15),
        UAP NVARCHAR(20),
        ConsumoWeek01 FLOAT,
        ConsumoWeek02 FLOAT,
        Stock INT,
        QtdPecasPorCaixa INT    
        UNIQUE (Id)
    )


    BEGIN TRY
    BEGIN TRAN @TransactionName  

        DECLARE @SQL NVARCHAR(MAX)
        SELECT @SQL = 'INSERT INTO #tempTable
        SELECT
            Id,
            Referencia,     
            UAP,
            ConsumoWeek01 AS ConsumoWeek01, 
            ConsumoWeek02, 
            CASE 
                WHEN Stock IS NULL THEN 0
            ELSE    
                Stock
            END AS Stock,
            QtdPecasPorCaixa
        FROM OPENQUERY(MACPAC, 
        ''WITH maxFornecedorByDate AS
         (
            SELECT
                YDA3REP.A3ARCD,
                YDA3REP.A3D5CD,
                ROW_NUMBER() OVER ( PARTITION BY YDA3REP.A3D5CD ORDER BY YDA3REP.A3A3DT DESC) AS Number
            FROM
                AUTO.YSACHAPOR.YDA3REP YDA3REP
         )  

        SELECT 
            ROW_NUMBER() OVER(ORDER BY A.RH6001 ASC) AS Id,
            A.RH6001 as Referencia, 
            A.RH6002 as UAP, 
            A.RH6030 as ConsumoWeek01, 
            A.RH6031 as ConsumoWeek02,
            IC130M.LLBLT1 as Stock,
            M.AUQCON AS QtdPecasPorCaixa
        FROM AUTO.D805DATPOR.TRP060H AS A
        LEFT JOIN AUTO.D805DATPOR.IC130M IC130M 
        ON A.RH6001 = IC130M.LLPPN AND
             IC130M.LLSTLC =
                 CASE A.RH6002
                      WHEN ''''UAP1'''' THEN ''''M1''''
                      WHEN ''''UAP2'''' THEN ''''M2''''
                      WHEN ''''UAP3'''' THEN ''''M3''''
                      WHEN ''''UAP4'''' THEN ''''M4''''
                      WHEN ''''UAP5'''' THEN ''''M5''''
                      WHEN ''''UAP6'''' THEN ''''M6''''
                      WHEN ''''UAPP'''' THEN ''''PROTOS''''
                      WHEN ''''EXT'''' THEN ''''EXTR''''
                    END
        LEFT JOIN 
        (
            SELECT 
                YDAUREP.AUD5CD,
                YDAUREP.AUQCON
            FROM maxFornecedorByDate F
            join AUTO.YSACHAPOR.YDAUREP YDAUREP
            ON F.A3ARCD = YDAUREP.AUARCD
            AND F.A3D5CD = YDAUREP.AUD5CD
            WHERE F.Number = 1 AND YDAUREP.AUD5CD LIKE ''''M%''''
            AND YDAUREP.AUD5CD NOT LIKE ''''%P%''''
            AND YDAUREP.AUA0NB > 1 
            AND YDAUREP.AUG6ST= ''''O''''
        ) M 
        ON M.AUD5CD = A.RH6001      
        WHERE A.RH6001 Not Like ''''FS%''''
        AND A.RH6030 <> 0
        AND A.RH6002 = ''''' + @UAP + ''''' '')'        
        EXEC sp_executesql @SQL

        INSERT INTO hListasAbastecimento (UAP,DataCriacao,ColaboradorId) VALUES (@UAP,GETDATE(),@ColaboradorId)

        INSERT INTO 
            hReferenciasAbastecimento 
            (
                Referencia,
                QtdAbastecimento,
                QtdCaixas,
                QtdPecasPorCaixa,
                ListaAbastecimentoId
            )   
        SELECT 
            C.Id,
            C.Referencia,
            ( T.ConsumoWeek01 / ( ( P.NumDias - @CurrentWeekDay ) * P.NumPAB )) * P.AlcanceAbastecimento AS QtdAbastecimento,
            T.QtdPecasPorCaixa,
            CASE
                WHEN ((T.ConsumoWeek01 / ( ( P.NumDias - @CurrentWeekDay ) * P.NumPAB )) * P.AlcanceAbastecimento) / NULLIF(T.QtdPecasPorCaixa,0) IS NULL THEN NULL
            ELSE
                CAST( CEILING(((T.ConsumoWeek01 / ( ( P.NumDias - @CurrentWeekDay ) * P.NumPAB )) * P.AlcanceAbastecimento) / T.QtdPecasPorCaixa )  AS INT)
            END AS QtdCaixas,
            SCOPE_IDENTITY()
        FROM 
            #tempTable T
        INNER JOIN hParametros P
        ON P.Referencia = T.Referencia 
        AND P.UAP = @UAP
        INNER JOIN hConsumos C
        ON C.Referencia = P.Referencia  
        AND C.UAP = @UAP
        WHERE T.Stock < ( T.ConsumoWeek01 / ( ( P.NumDias - @CurrentWeekDay ) * P.NumPAB )) * P.QtdMin
        ORDER BY QtdAbastecimento DESC

        COMMIT TRANSACTION @TransactionName 

        DROP TABLE #tempTable

        -- Success, Lista de abastecimento foi criada sem errors --
        SELECT @Status = 200
        RETURN @Status

    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
        ROLLBACK TRAN @TransactionName
        DROP TABLE #tempTable
        SELECT
            ERROR_NUMBER() AS ErrorNumber,
            ERROR_STATE() AS ErrorState,
            ERROR_SEVERITY() AS ErrorSeverity,
            ERROR_PROCEDURE() AS ErrorProcedure,
            ERROR_LINE() AS ErrorLine,
            ERROR_MESSAGE() AS ErrorMessage;

            -- Erro, Nao foi possivel criar lista de abastecimento, verificar dynamic query -- 
            SELECT @Status = 400
        RETURN @Status

    END CATCH

END

РЕДАКТИРОВАТЬ

Я вызываю SP из приложения Asp .NET Core с Entity Framework Core

  await _context.Database
        .ExecuteSqlCommandAsync("EXEC @Status = GetDataForNewListaAbastecimento @UAP, @ColaboradorId", @params);

Почему вы используете sp_executesql для запуска этого нединамического запроса и почему вы вводите в него значение? Этот запрос не должен выполняться как «динамический» оператор, и он должен быть параметризован должен; в противном случае он открыт для инъекции (даже nvarchar(20) может подвергнуться инъекции).

Larnu 28.05.2019 12:44

Временная таблица будет сохраняться только на время соединения, которое ее создало. Предполагая, что вы открываете соединение для запуска SP (например, из приложения), SQL Server в любом случае будет корректно DROP временную таблицу. Как вы выполняете СП?

Larnu 28.05.2019 12:45

О, я вижу, я вызываю это, используя структуру сущности в основном приложении asp .net. Кроме того, я должен выполнить sp_executeSql, потому что это единственный способ передать параметры из SQL на связанный с db 2 сервер, если только я что-то не упустил, но так делают мои коллеги.

Jackal 28.05.2019 12:58

Ааа, это OPENQUERY (довольно трудно понять, когда буквальное жало); в этом случае, да, "инъекция" - единственный способ, однако я все же предлагаю сделать его безопасным. QUOTENAME отлично подходит для этого. Я не могу проверить, но я думаю, что вы хотите AND A.RH6002 = ''''' + @UAP + ''''' '' на AND A.RH6002 = N' + QUOTENAME(QUOTENAME(@UAP,N''''),N'''') + N' (обратите внимание, я также добавил N, так как @UAP — это nvarchar, и он вводился как varchar)

Larnu 28.05.2019 13:04

Я пробовал это, но дает неправильный синтаксис рядом с ключевым словом @UAP, «AND A.RH6002 = N» + QUOTENAME(QUOTENAME(@UAP,N''''),N'''') + N' '')' EXEC sp_executesql @SQL´

Jackal 28.05.2019 13:13

Как я уже сказал, я не мог проверить, @Jackal, но я предлагаю использовать QUOTENAME. Использование PRINT или SELECT для проверки значения @SQL поможет. Почему QUOTENAME важно

Larnu 28.05.2019 13:29

хорошо, то, что вы написали, дает мне печать AND A.RH6002 = N'''UAP1''' '), я попытался удалить 2 кавычки из каждой, и результат AND A.RH6002 = N[[UAP1]]] ')

Jackal 28.05.2019 13:32

Бларг, вот почему динамический динамический SQL - это боль XD. Попробуйте N'N''' + QUOTENAME(QUOTENAME(@UAP,N''''),N'''') + N''''; Это должно охватывать основы сейчас.

Larnu 28.05.2019 13:39

вот то, что я пробовал, выглядит ближе к решению И A.RH6002 = N' + QUOTENAME(@UAP,N'''') + N' '')' это pritns AND A.RH6002 = N'UAP1' '), кажется, что единственная проблема сейчас - это начальная N ', я не уверен, что она делает, или она неправильно читает?

Jackal 28.05.2019 13:43

так что я читал, что это что-то о nvarchar, @UAP уже является NVARCHAR кстати

Jackal 28.05.2019 13:46

Это означает, что буквальная строка — это nvarchar @Jackal. Вы не передаете @UAP в OPENQUERY, вы инъекция это значение. 'UAP1' не является nvarchar (N'UAP1'` является), поэтому, если вы вводите nvarchar, вам нужно убедиться, что вы делаете строковый литерал, который вы вводите, объявлен как один. Обратите внимание, что здесь происходит, если вы опускаете N, например: дб <> рабочий пример. Несмотря на то, что в значении @SQL все символы отображаются правильно, при его выполнении они совершенно другие.

Larnu 28.05.2019 13:53

это сработало И A.RH6002 = ''' + QUOTENAME(@UAP,N'''') + ''''')', но не уверен, требуется ли иметь N'''' до и после каждого знака плюс ? Поскольку 1-й N всегда появляется в запросе как текст

Jackal 28.05.2019 13:59

Если ваш параметр (@UAP) будет иметь символ Юникода, то вышеописанное не будет работать так, как вы ожидаете. И если у него никогда не будет символа Юникода, тогда вы должны объявить @UAP как varchar, а не как nvarchar (во избежание путаницы).

Larnu 28.05.2019 14:04

Ах, я вижу, как это работает И A.RH6002 = N''' + QUOTENAME(@UAP,N'''') + N''' '')', да, это может быть юникод, так что это окончательный результат, Спасибо!

Jackal 28.05.2019 15:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
14
1 026
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

попробуйте добавить это:

ЕСЛИ OBJECT_ID('tempdb..#Results') НЕ NULL DROP TABLE #Results

(Замените имя своей временной таблицы #Result)

Другие вопросы по теме