cómo repensar la misma excepción en sql server


Quiero repensar la misma excepción en sql server que se ha producido en mi bloque try. Puedo lanzar el mismo mensaje pero quiero lanzar el mismo error.

BEGIN TRANSACTION
    BEGIN TRY
            INSERT INTO Tags.tblDomain 
            (DomainName, SubDomainId, DomainCode, Description)
            VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
            COMMIT TRANSACTION
    END TRY

    BEGIN CATCH
            declare @severity int; 
            declare @state int;

            select @severity=error_severity(), @state=error_state();

            RAISERROR(@@Error,@ErrorSeverity,@state);
            ROLLBACK TRANSACTION
    END CATCH

RAISERROR(@@Error, @ErrorSeverity, @state);

Esta línea mostrará error, pero quiero funcionalidad algo así. Esto plantea error con el número de error 50000, pero quiero que se lance el número de erron que estoy pasando @@error,

Quiero capturar este error no en frontend

Es decir,

catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}

Quiero esto funcionalidad. que no se puede lograr usando raiseerror. No quiero dar un mensaje de error personalizado en el back-end.

RAISEERROR debe devolver el error mencionado a continuación cuando paso errorNo para ser lanzado en catch

Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,

Línea 14 Violación de la restricción de CLAVE ÚNICA 'UK_DomainCode'. No se puede insertar duplicar clave en el objeto 'Etiquetas.tblDomain'. La declaración ha sido terminada.

EDITAR:

¿Cuál puede ser el inconveniente de no usar try catch block si quiero que la excepción se maneje en el frontend considerando que el procedimiento almacenado contiene múltiples consultas que deben ejecutarse

Author: Shantanu Gupta, 2010-03-20

10 answers

Aquí hay un ejemplo de código limpio completamente funcional para revertir una serie de instrucciones si se produce un error y reportar el mensaje de error.

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
 90
Author: Ben Gripka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-09 15:55:53

SQL 2012 introduce la sentencia throw:

Http://msdn.microsoft.com/en-us/library/ee677615.aspx

Si la instrucción THROW se especifica sin parámetros, debe aparecer dentro de un bloque de CAPTURA. Esto hace que la excepción atrapada se eleve.

BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH
 101
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-26 00:43:43

Repensando dentro del bloque CATCH (código anterior a SQL2012, use la instrucción THROW para SQL2012 y posteriores):

DECLARE
    @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
    @ErrorNumber int = ERROR_NUMBER(),
    @ErrorSeverity int = ERROR_SEVERITY(),
    @ErrorState int = ERROR_STATE(),
    @ErrorLine int = ERROR_LINE(),
    @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
 5
Author: nzeemin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-13 13:39:12

Creo que sus opciones son:

  • No atrape el error (deje que burbujee)
  • Levante una personalizada

En algún momento, SQL probablemente introducirá un comando reraise, o la capacidad de detectar solo ciertos errores. Pero por ahora, utilice una solución alternativa. Disculpe....

 4
Author: Rob Farley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-20 00:11:41

No se puede: solo el motor puede lanzar errores de menos de 50000. Todo lo que puede hacer es lanzar una excepción que se parece a...

Ver mi respuesta aquí, por favor,

El interrogador aquí utilizó transacciones del lado del cliente para hacer lo que quería, lo que creo que es un poco tonto...

 1
Author: gbn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:30

Ok, esta es una solución...:-)

DECLARE @Error_Number INT
BEGIN TRANSACTION 
    BEGIN TRY
    INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') 
    /* Column 'Name' has unique constraint on it*/
    END TRY
    BEGIN CATCH

            SELECT ERROR_NUMBER()
            --RAISERROR (@ErrorMessage,@Severity,@State)
            ROLLBACK TRAN
    END CATCH

Si observa el bloque catch, no está elevando el error, sino devolviendo el número de error real (y también revertiría la transacción). Ahora en su código. NET, en lugar de capturar la exception, si usa ExecuteScalar (), obtiene el número de error real que desea y muestra el número apropiado.

int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
    MessageBox.Show("Some message");
}

Espero que esto ayude,

EDITAR: - Solo una nota, si desea obtener el número de registros afectados y tratando de utilizar ExecuteNonQuery, la solución anterior puede no funcionar para usted. De lo contrario, creo que se adaptaría a lo que necesitas. Házmelo saber.

 0
Author: Ashish Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-20 05:52:32

La forma de detener la ejecución en un procedimiento almacenado después de que se haya producido un error y devolver el error al programa que llama es seguir cada instrucción que pueda generar un error con este código:

If @@ERROR > 0
Return

Me sorprendió descubrir que la ejecución en un procedimiento almacenado puede continuar después de un error, sin darme cuenta de esto puede conducir a algunos errores difíciles de rastrear.

Este tipo de manejo de errores parallels (pre. net) Visual Basic 6. Esperando el comando de lanzamiento en SQL Server 2012.

 0
Author: Chuck Bevitt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-20 16:58:05

Dado que aún no se ha movido a 2012, una forma de implementar el burbujeo del código de error original es usar la parte de mensaje de texto de la excepción que está (re)lanzando desde el bloque catch. Recuerde que puede contener alguna estructura, por ejemplo, texto XML para que su código de llamada lo analice en su bloque catch.

 0
Author: Yuri Makassiouk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-25 15:58:57

También puede crear un procedimiento almacenado wrapper para esos escenarios cuando desee que la instrucción SQL se ejecute dentro de la transacción y alimente el error a su código.

CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
    @SQL nvarchar(max)
)
AS

SET NOCOUNT ON

BEGIN TRY
    BEGIN TRANSACTION
        EXEC(@SQL)
    COMMIT TRANSACTION
END TRY

BEGIN CATCH
    DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
    SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
    ROLLBACK TRANSACTION
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH

GO

-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'
 0
Author: Sergey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-02 05:44:14

Desde el punto de vista del diseño, ¿cuál es el punto de lanzar excepciones con números de error originales y mensajes personalizados? Hasta cierto punto rompe el contrato de interfaz entre las aplicaciones y la base de datos. Si desea detectar errores originales y manejarlos en código superior, no los maneje en la base de datos. Luego, cuando atrapa una excepción, puede cambiar el mensaje presentado al usuario a cualquier cosa que desee. Yo no lo haría sin embargo, porque hace que su código de base de datos hmm ' no correcto. Como otros dijeron, debería definir un conjunto de sus propios códigos de error (por encima de 50000) y lanzarlos en su lugar. A continuación, puede hanle problemas de integridad ('No se permiten valores duplicados') por separado de los posibles problemas de negocio - 'Código postal no es válido', 'No se encontraron filas que coincidan con los criterios' y así sucesivamente.

 -3
Author: Piotr Rodak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-20 13:41:10