Используя курсор, как обработать ошибку в SQL - PullRequest
0 голосов
/ 28 января 2019

У меня есть несколько баз данных, в которых я ищу определенный столбец под названием Страны.Если столбец существует, тогда я проверяю пробелы в столбце.Если я зациклюсь на курсоре, БД, в которой нет столбца Страны, выдаст ошибку.Как я могу обработать эту ошибку?

Обеспокоенность: блок catch не обрабатывается, пожалуйста, помогите мне решить проблему.

Запрос, как показано ниже,

CREATE PROCEDURE [dbo].[USP_SMSGeneric_CountrySpace] @DB VARCHAR(100)                                        
As                                        
BEGIN                                        

SET NOCOUNT ON                                    

DECLARE @StudyID  varchar(max)                                    
DECLARE @Databasename VARCHAR(max)                                    
DECLARE @QUERY NVARCHAR(MAX)                                  
DECLARE @Protocol varchar(max)                                    
DECLARE @Servername varchar(max)                                     
DECLARE @script VARCHAR(Max)        
DECLARE @script1 VARCHAR(Max)                                    
DECLARE @initscript NVARCHAR(Max)       
DECLARE @Countries VARCHAR(Max)         
DECLARE @Countryrelease VARCHAR(Max) 

IF OBJECT_ID('TEMPDB..#OBJMISSING') IS NOT NULL DROP TABLE  #OBJMISSING       


CREATE TABLE #OBJMISSING (ERRID INT IDENTITY(1,1),ERRNUM BIGINT,ERRMSG VARCHAR(MAX),DBNAME VARCHAR(MAX))                                        


SET @initscript='
    DECLARE csrStudy CURSOR FOR                                    
    SELECT  ProtocolName, DBName, studyid,DBServer AS Servername from SMSAPP.dbo.studymaster  WITH (NOLOCK)                                   
      WHERE ClientName LIKE ''%NOVARTIS%'' AND studystatus IN (1,2) AND DBServer  IN (''SQL002'' ,''SQL004'',''SQL005'')                                         
    '
EXEC sp_executesql @initscript                                 

OPEN csrStudy                                  
FETCH NEXT FROM csrStudy INTO @Protocol,@Databasename,@StudyID,@ServerName                                    

WHILE @@FETCH_STATUS = 0                                      
BEGIN                                      
    SET @DB = @Servername+'.'+@Databasename        

    SET @script = '

    DECLARE @StrValue VARCHAR(max)

    BEGIN TRY     
        IF EXISTS (         
            SELECT DISTINCT 1 FROM  '+@DB+'.sys.columns c JOIN '+@DB+'.sys.Tables t ON c.Object_ID=t.Object_ID
            WHERE c.Name = ''Countries’'' AND t.name =''tblMaterials'')      
        BEGIN
            SELECT  @StrValue = ISNULL(@StrValue + '','', '''') + Countries’ FROM (
            SELECT DISTINCT (LEN(Countries’ + '','') - LEN(REPLACE(Countries’, '' '', '''') + '',''))CNT,Countries  
            FROM  '+@DB+'.dbo.tblMaterials WITH (NOLOCK) )A WHERE CNT>0
        END
    END TRY

    BEGIN CATCH          
        INSERT INTO #OBJMISSING VALUES 
        (ERROR_NUMBER(),ERROR_MESSAGE(),''+@Databasename+'')     
    END CATCH     

    IF @StrValue IS NOT NULL   -- If any Duplicate values found, then raise an alert           
    BEGIN           
        SELECT '+@StudyID+' As StudyID,
        ''Countries field value Should not have space''   AS Actual ,          
        ''Countries field value exists with space for String :'' + @StrValue AS Discrepancy INTO #tempOutput       

Я получаю следующую ошибку:

Поставщик OLE DB "SQLNCLI10" для связанного сервера "SQL001" не содержит таблицу "" RAW. "Dbo". "TblMaterials" ".таблица либо не существует, либо текущий пользователь не имеет разрешений для этой таблицы

1 Ответ

0 голосов
/ 28 января 2019

Вам нужно TRY CATCH вне динамического SQL.

Отображаемое сообщение об ошибке: разбор раз, еще до того, как оно выполнится (для этого оператора EXEC).В этот момент механизм проверяет, существуют ли таблицы и объекты, и если нет, то возвращается ошибка.Выполнение никогда не начинается, поэтому оно никогда не попадет в раздел CATCH.Вот почему TRY CATCH должен находиться за пределами динамического SQL, потому что весь динамический SQL будет отклонен после синтаксического анализа.


Полученное сообщение об ошибке исходит из запроса, подобного следующему:

EXEC('SELECT * FROM [SomeLinkedServer].DatabaseName.SchemaName.NonExistingTable')

Сообщение 7314, уровень 16, состояние 1, строка 1 Поставщик OLE DB "SQLNCLI11" для связанного сервера "SomeLinkedServer" не содержит таблицу "" DatabaseName "." SchemaName "."NonExistingTable"».Таблица либо не существует, либо текущий пользователь не имеет разрешений для этой таблицы.

Если вы можете обернуть это в TRY CATCH, поток управления перейдет к улову, так как серьезностьошибки достаточно высоки:

BEGIN TRY

    EXEC('SELECT * FROM [SomeLinkedServer].DatabaseName.SchemaName.NonExistingTable')

END TRY

BEGIN CATCH

    SELECT 'This is the catch section'

END CATCH

![enter image description here

Обратите внимание на разницу по сравнению со следующим примером без динамического SQL:

BEGIN TRY

    SELECT 1 FROM [SomeLinkedServer].DatabaseName.SchemaName.NonExistingTable

END TRY

BEGIN CATCH

    SELECT 1

END CATCH

Сообщение 208, Уровень 16, Состояние 1, Строка 3 Неверное имя объекта 'DatabaseName.SchemaName.NonExistingTable'.

Это происходит потому, что весь пакет отклоняется после анализа, поэтомуон не может перейти на CATCH, так как он никогда не начинал выполнение.Когда вы используете динамический SQL, анализ, компиляция и выполнение динамической части происходит в точке EXEC (и именно поэтому она является динамической), задерживая выдачу ошибки, чтобы ее можно было перехватить.


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

DECLARE @Variable ...

DECLARE MyCursor CURSOR FOR ...

FETCH NEXT FROM MyCursor INTO @Variable

WHILE @@FETCH_STATUS = 0
BEGIN

    BEGIN TRY

        DECLARE @DynamicSQL VARCHAR(MAX) = ... -- The DynamicSQL may have another TRY CATCH inside

        EXEC(@DynamicSQL)

    END TRY

    BEGIN CATCH

        -- Do your catch operation here, you can leave this section empty if you want (not recommended)

    END CATCH

    FETCH NEXT FROM MyCursor INTO @Variable

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