ProgrammingBackend Developer

How to implement effective error handling and logging in SQL at the level of stored procedures to detect and analyze failures during business logic execution?

Pass interviews with Hintsage AI assistant

Answer.

Error handling and logging in SQL have gained particular popularity with the development of complex business processes when it became important not just to stop execution on error but to record the fact of failure and, if possible, continue working. Initially, SQL did not have advanced try-catch mechanisms, and each DBMS offered its own mechanisms.

History of the issue:

Early versions of SQL standards did not have built-in operators to catch errors in procedures. Later, vendors began to implement constructs such as TRY...CATCH in Microsoft SQL Server or HANDLER in MySQL, allowing for more flexible control over the workflow directly at the database level.

Problem:

Errors can occur due to incorrect data as well as system reasons. If a stored procedure does not implement capturing and logging errors, debugging and maintenance become extremely difficult. Furthermore, it is necessary to distinguish between critical errors and handled ones to avoid interrupting business operations where it is not required.

Solution:

In modern systems, it is advisable to implement constructs for collecting and logging errors. It is necessary to create separate log tables, use TRY...CATCH (SQL Server) or DECLARE ... HANDLER (MySQL), and store detailed information about exceptions in order to later analyze the causes of failures.

Code example (SQL Server):

CREATE PROCEDURE dbo.UpdateCustomer @CustomerID INT, @NewName NVARCHAR(100) AS BEGIN BEGIN TRY UPDATE Customers SET Name = @NewName WHERE CustomerID = @CustomerID; END TRY BEGIN CATCH INSERT INTO ErrorLog (ErrorMessage, ErrorSeverity, ErrorTime) VALUES (ERROR_MESSAGE(), ERROR_SEVERITY(), GETDATE()); THROW; END CATCH END;

Key features:

  • Using TRY...CATCH allows isolating potentially dangerous code.
  • Inserting errors into a log table with maximum detail.
  • Throw/Error raising for proper procedure completion and passing information to the calling layer.

Tricky questions.

Can all types of errors be caught inside a TRY...CATCH block (or through a handler)?

No, not all errors, for example, severe server failures, can be caught. Attention errors or connection failures are beyond transaction processing.

What will happen to uncommitted changes in the procedure in case of an error if a transaction is not used?

Changes will be partially committed, some updates will enter the database, and some may be lost. To avoid inconsistency, it is recommended to always use transactions.

BEGIN TRY BEGIN TRANSACTION; --...code COMMIT; END TRY BEGIN CATCH ROLLBACK; END CATCH

Can INSERT EXEC be used directly from within the CATCH block to log an error from another context?

Not always: INSERT EXEC is prohibited in certain contexts (for example, if there is already an active transaction), which may cause second-level errors. It is better to collect error details locally and then log them with a single INSERT.

Typical errors and anti-patterns

  • Lack of error logging.
  • Ignoring TRANSACTION, which leads to data breaks.
  • Logging only texts, without error codes and time/user code.

Real-life example

Negative case

A client implemented logic only through RAISERROR without logging, so errors were not saved or analyzed.

Pros:

  • Less code.

Cons:

  • There is no way to understand the causes of failures; analyzing problems in production is impossible.

Positive case

Using TRY...CATCH plus an ErrorLog table, recording time, error code, user, text, and trace.

Pros:

  • Easy error analytics.
  • Quick problem localization.
  • Transparency for business analysts.

Cons:

  • Requires maintaining logs, sometimes cleaning them for optimization.