{"id":1195,"date":"2024-02-20T19:15:14","date_gmt":"2024-02-20T18:15:14","guid":{"rendered":"https:\/\/staging.sql.marcus-belz.de\/?p=1195"},"modified":"2026-05-07T01:06:38","modified_gmt":"2026-05-06T23:06:38","slug":"logging-an-etl-process-with-t-sql","status":"publish","type":"post","link":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en","title":{"rendered":"Design Pattern \/\/ Logging an ETL process with T-SQL"},"content":{"rendered":"\n<p>How can you judge whether an ETL process has been successful? The mere fact that a process was not terminated with an exception does not necessarily mean that the process did what was expected of it. Readable and evaluable logging of an ETL process can help here. It enables a reliable assessment of the success of an ETL process.<\/p>\n\n\n\n<p>This article presents a design pattern for logging an ETL process based on stored procedures that insert and update log records in log tables. The aim is to create a readable and evaluable protocol that provides answers to essential questions about the execution of an ETL process:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>How long does the ETL process take in total?<\/li>\n\n\n\n<li>How long does a stored procedure, SSIS package, or other component take to execute?<\/li>\n\n\n\n<li>How long does it take to execute a specific SQL statement?<\/li>\n\n\n\n<li>How many records were processed by an SQL statement?<\/li>\n<\/ul>\n\n\n\n<p>Of course, we also want to know whether the process as a whole, a procedure or even a specific SQL statement was executed successfully.<\/p>\n\n\n\n<p>The procedure is actually straightforward: At the beginning of each action, a log data record is written and after the action is completed, it is updated with either the status success or failure and, if necessary, other helpful information. That&#8217;s it! But it can still be a little more&#8230;<\/p>\n\n\n\n<!--more-->\n\n\n\n<h1 class=\"wp-block-heading\">Content<\/h1>\n\n\n\n<p>\n<a href=\"#TheResult\">The Result<\/a><br>\n<a href=\"#LetsStart\">Let&#8217;s start&#8230;<\/a><br>\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#ThreeTierLogging\">Three-tier logging<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#ThreeTierLoggingExecution\">[LL].[Execution]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#ThreeTierLoggingComponent\">[LL].[Component]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#ThreeTierLoggingTrace\">[LL].[Trace]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#ThreeTierLoggingSchemaLL\">Schema LL<\/a><br>\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#TableDescription\">Table descriptions, declaration and data model<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#TableDescriptionExecution\">[LL].[Execution]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#TableDescriptionComponent\">[LL].[Component]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#TableDescriptionTrace\">[LL].[Trace]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#TableDescriptionError\">[LL].[Error]<\/a><br>\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#ETL-process-execution-status\">ETL process execution status<\/a><br>\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#Stored-procedures-for-logging\">Stored procedures for logging<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#StoredProcedure-spInsertTrace\">[LL].[spInsertTrace]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#StoredProcedure-spUpdateTrace\">[LL].[spUpdateTrace]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#StoredProcedure-spUpdateTraceSuccess\">[LL].[spUpdateTraceSuccess]<\/a><br>\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#ExceptionHandling\">ExceptionHandling<\/a><br>\n\n<a href=\"#Example\">Example of logging and exception handling in an ETL process<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#Example-spETLProcess\">[T2].[spETLProcess]<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#Example-spDo\u00adSomething_2_2\">[T2].[spDo\u00adSomething_2_2]<\/a><br>\n\n<a href=\"#Summary\">Summary<\/a><br>\n\n<a href=\"#Related-Posts\">Related Posts<\/a><br>\n\n<a href=\"#Download\">Download<\/a><br>\n<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"TheResult\">The result<\/h1>\n\n\n\n<p>Even if the creation of a protocol itself is not or should not be a big deal, there is still a lot to write about. But let&#8217;s start with the result and put the cart before the horse. The process logging presented here is three-tier and uses the following log tables:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>[LL].[Execution]<\/strong><\/li>\n\n\n\n<li><strong>[LL].[Component]<\/strong><\/li>\n\n\n\n<li><strong>[LL].[Trace]<\/strong><\/li>\n<\/ul>\n\n\n\n<p>In these tables, an ETL process and the associated components and work steps are logged with increasing granularity &#8211; read from top to bottom. The ETL process, the components and the individual action are logged with exactly one row.<\/p>\n\n\n\n<p>Of course, the logging of errors is also closely linked to the creation of the logging of the process. The logging approach presented here uses the following table for logging errors:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>[LL].[Error]<\/strong><\/li>\n<\/ul>\n\n\n\n<p>The following images show the result of the three-stage logging of a simple, compact but complete ETL process.<\/p>\n\n\n\n<p>In the <strong>[LL].[Trace]<\/strong> table, each action is recorded, among other things, with the name of the procedure, the target entity that is processed by the procedure, a short description of what was specifically done and other information, such as the number of affected Records and duration of execution are logged.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"195\" src=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png\" alt=\"\" class=\"wp-image-1058\" srcset=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png 1024w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-300x57.png 300w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-768x146.png 768w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1.png 1476w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Tabelle [LL].[Trace]<\/figcaption><\/figure>\n\n\n\n<p>The <strong>[LL].[Component]<\/strong> table logs the calls to procedures and SSIS packages or &#8211; generally speaking &#8211; components. Here too, a short description of the component&#8217;s task, the target entity and the duration of execution are logged.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"93\" src=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1-1024x93.png\" alt=\"\" class=\"wp-image-1059\" srcset=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1-1024x93.png 1024w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1-300x27.png 300w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1-768x70.png 768w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1.png 1334w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Tabelle [LL].[Component]<\/figcaption><\/figure>\n\n\n\n<p>At the top level, each execution of the ETL process is logged in the <strong>[LL].[Execution]<\/strong> table with exactly one row.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"35\" src=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1-1024x35.png\" alt=\"\" class=\"wp-image-1061\" srcset=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1-1024x35.png 1024w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1-300x10.png 300w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1-768x26.png 768w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1.png 1210w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Tabelle [LL].[Execution]<\/figcaption><\/figure>\n\n\n\n<p>All process logging tables contain two columns <strong>[State]<\/strong> and <strong>[Success]<\/strong>, which store the success or failure of the execution of an action, component, or ETL process.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"LetsStart\">Let&#8217;s start\u2026<\/h1>\n\n\n\n<p>After the brief introduction of the result, the following aspects of the procedure need to be clarified:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#ThreeTierLogging\">Three-tier logging<\/a><\/li>\n\n\n\n<li><a href=\"#TableDescritpion\">Table descrition, declaration and datamodel<\/a> <\/li>\n\n\n\n<li><a href=\"#CombinationsOfStateAndSuccess\">Status of the execution of an ETL process<\/a><\/li>\n\n\n\n<li><a href=\"#LoggingProcedures\">Logging stored procedures<\/a><\/li>\n\n\n\n<li><a href=\"#ExceptionHandling\">Exception-Handling<\/a><\/li>\n\n\n\n<li><a href=\"#Example\">Example for logging and exception handling in an ETL process<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ThreeTierLogging\">Three-tier logging<\/h2>\n\n\n\n<p>The procedure involves logging an ETL process in the three tables <strong>[LL].[Execution]<\/strong>, <strong>[LL].[Component]<\/strong> and <strong>[LL].[Trace]<\/strong>. Each of the tables is intended for logging specific artifacts. This section introduces the use of each table, its columns, and the code to create it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingExecution\">[LL].[Execution]<\/h3>\n\n\n\n<p>This table records the execution of an ETL process with exactly one record. An ETL process always has an entry function. This can be a stored procedure, an SSIS package, a Talend job, or a <em>SQL Server Agent<\/em> job. At the beginning of execution of the entry function, a log record is inserted into this table. After all tasks have been successfully processed, this data record is updated with the status <em>success<\/em>, or in the event of an error with the status <em>error<\/em>. This table therefore contains an overview of all executions of the ETL process and provides information such as the status and duration of the execution.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingComponent\">[LL].[Component]<\/h3>\n\n\n\n<p>In this table, the execution of a component is logged with exactly one row. A component can be a stored procedure, an SSIS package, a Talend job. A component is characterized by the fact that it controls and executes one or more data manipulations or other components. As with the table <strong>[LL].[Execution]<\/strong>, a log entry is inserted into this table at the beginning of execution and updated with the status <em>success <\/em>or <em>error <\/em>upon completion. This table therefore contains a list of the components executed for each execution of the ETL process and provides information such as the status and duration of the execution for each component.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingTrace\">[LL].[Trace]<\/h3>\n\n\n\n<p>The name of this table already indicates that the table is intended for a detailed logging of actions of the ETL process. Which actions are logged is a design decision by the developer. However, it is recommended to log at least every INSERT, UPDATE and DELETE statement with its own log entry. In addition to the status fields mentioned above, the table also contains a column that provides the number of affected rows of a data manipulation task, thus giving the developer the opportunity to assess whether the statements did exactly what was expected.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingError\">[LL].[Error]<\/h3>\n\n\n\n<p>Errors that were detected in an ETL process must of course be logged. A distinction must be made between the logging of exceptions and data errors. The structure of thi<\/p>\n\n\n\n<p>s table is designed for the logging of data errors and contains columns in which each data errors can be logged completely, readably and evaluably. This article focuses on logging an ETL process rather than logging data errors. The logging of the process is closely linked to explicit exception handling. A separate section is dedicated to exception handling and exception logging.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingSchemaLL\">Schema LL<\/h3>\n\n\n\n<p>The schema name <strong>LL<\/strong> stands for <em>Logging Layer<\/em>. This schema stores all the log tables and the stored procedures used for logging.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"TableDescription\">Table descriptions, declaration and data model<\/h2>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<p>The following sections describe the process logging tables and the error logging table. Finally, there is a diagram with the data model for these tables.<\/p>\n<\/div><\/div>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"TableDescriptionExecution\">[LL].[Execution]<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionExecutionColumns\">Columns<\/h4>\n\n\n\n<p>The table contains the following columns:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Column<\/th><th class=\"has-text-align-left\" data-align=\"left\">Description<\/th><\/tr><\/thead><tbody><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Id<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[Id]<\/strong> column is declared as <strong>IDENTITY <\/strong>and identifies a log record in this table.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Process<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The logging tables cannot be used by just one ETL process. So that the log data records of different ETL processes can be distinguished from one another, a unique name of the ETL process must be specified in the <strong>[Process]<\/strong> column.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Start<\/strong><br><strong>End<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">These two columns indicate the start time and the end of the execution of an ETL process. When the ETL process starts, the current timestamp is saved in the <strong>[Start]<\/strong> column. The <strong>[End]<\/strong> column is initialized with a <em>NULL <\/em>at startup. The last command of an ETL process must update the state of the log entry (<strong>[State]<\/strong> and <strong>[Success]<\/strong> columns). When updated, the current timestamp is saved in the <strong>[End]<\/strong> column. A <em>NULL <\/em>in the <strong>[End] <\/strong>column indicates either that the process is still running or that it has aborted with an exception. Times are always stored as UTC time.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>DeltaStart<\/strong><br><strong>DeltaEnd<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">These columns determine the time window for a delta load. <strong>[DeltaStart]<\/strong> sets the lower time limit and <strong>[DeltaEnd]<\/strong> sets the upper one. The time window is automatically determined by the stored procedure <strong>[LL].[spInsertExecution]<\/strong>, which inserts the log entry into this table.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>User<\/strong><br><strong>Machine<\/strong><br><strong>Version<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">These columns must indicate the context in which the ETL process is executed. The user specified in the <strong>[User] <\/strong>column is the user under which the process is executed. This is crucial for authorizations to databases, tables, file shares, etc. The user is determined by automatically using the T-SQL function <strong>SUSER_SNAME() <\/strong>when inserting the log entry.<br>The <strong>[Machine] <\/strong>column stores the name of the computer on which the ETL process is running. The name is also determined automatically when the log entry is inserted using the T-SQL function <strong>HOST_NAME()<\/strong>.<br>The <strong>[Version]<\/strong> column takes the version number of the ETL process and may be helpful for troubleshooting after an incorrect deployment of an ETL process.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>State<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[State]<\/strong> column displays the current status of the ETL process. Possible values include <em>processing<\/em>, <em>warning<\/em>, <em>success <\/em>or <em>error<\/em>. Initially the ETL process is started with <strong>[State]<\/strong> = <em>processing<\/em>. If successful, <strong>[State]<\/strong> is updated with <em>warning <\/em>or <em>success<\/em>. In case of an error, <strong>[State]<\/strong> is updated with <em>error<\/em>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Success<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[Success]<\/strong> column indicates whether the ETL process completed successfully with <strong>[State]<\/strong> = <em>warning <\/em>or <em>success<\/em>. Initially the ETL process is started with <strong>[Success]<\/strong> = <em>0<\/em>. If successful, <strong>[Success]<\/strong> is updated with <em>1<\/em>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>CreatedOn<\/strong><br><strong>CreatedBy<\/strong><br><strong>ModifiedOn<\/strong><br><strong>ModifiedBy<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[CreatedOn]<\/strong> and <strong>[ModifiedOn]<\/strong> columns contain a UTC timestamp. Initially, <strong>[CreatedOn]<\/strong> is assigned the current timestamp via a default value and <strong>[ModifiedOn]<\/strong> is assigned a NULL. <strong>[ModifiedOn]<\/strong> is updated with the current timestamp when the status is updated. The same system applies to the fields <strong>[CreatedBy] <\/strong>and <strong>[ModifiedBy]<\/strong>. The user under which the process is executed is stored here.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionExecutionDeclaration\">Declaration<\/h4>\n\n\n\n<p>The table is created using the following statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE TABLE [LL].[Execution] \n(\n    [Id]           bigint         IDENTITY (1, 1) NOT NULL\n   ,[Process]      nvarchar (max)                 NOT NULL\n   ,[Start]        datetime                       NOT NULL\n   ,[End]          datetime                           NULL\n   ,[DeltaStart]   datetime                           NULL\n   ,[DeltaEnd]     datetime                           NULL\n   ,[User]         nvarchar(128)                      NULL\n   ,[Machine]      nvarchar(128)                      NULL\n   ,[Version]      int                                NULL\n   ,[State]        nvarchar(128)                      NULL\n   ,[Success]      bit                                NULL\n   ,[CreatedOn]    datetime\n       CONSTRAINT [DF_LL_Execution_CreatedOn] \n       DEFAULT (GETUTCDATE())                     NOT NULL\n   ,[CreatedBy]    nvarchar(100)\n       CONSTRAINT [DF_LL_Execution_CreatedBy]\n       DEFAULT (SUSER_SNAME())                    NOT NULL\n   ,[ModifiedOn]   datetime                           NULL\n   ,[ModifiedBy]   nvarchar(100)                      NULL\n   ,CONSTRAINT [PK_LL_Execution] \n       PRIMARY KEY CLUSTERED ([Id] ASC)\n);\nGO\n\nCREATE TRIGGER [LL].[TR_LL_Execution_Update]\nON [LL].[Execution]\nFOR UPDATE\nAS\nBEGIN\nSET NOCOUNT ON\n   UPDATE [LL].[Execution]\n      SET\n          [ModifiedOn] = GETUTCDATE()\n         ,[ModifiedBy] = SUSER_SNAME()\n   FROM\n      [LL].[Execution]\n      INNER JOIN inserted\n      ON\n        inserted.[ID] = [LL].[Execution].[ID];\nEND;\nGO<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"TableDescriptionComponent\">[LL].[Component]<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionComponentColumns\">Columns<\/h4>\n\n\n\n<p>The table contains the following columns:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Column<\/th><th class=\"has-text-align-left\" data-align=\"left\">Descritpion<\/th><\/tr><\/thead><tbody><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Id<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[Id]<\/strong> column is declared as <strong>IDENTITY <\/strong>and identifies a log record in this table.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>ExecutionId<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">Using this foreign key on the table <strong>[LL].[Execution]<\/strong>, log entries that are related to a specific execution of the ETL process can be identified.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Source<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The text in this column indicates the type of component that wrote the log record. Values used are, for example, <em>T-SQL<\/em> or <em>SSIS<\/em>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Component<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">This column holds the name of the component that wrote the entry. For procedures, this is the procedure name, for other components, for example, the file name of the component.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Version<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">If a version number is available for the component, it can and should be logged in this column.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Entity<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The name of the target table or &#8211; to put it more generally &#8211; the entity that is processed by the component must be specified in this column. The name can be freely chosen. It is recommended to choose the name systematically in order to facilitate a systematic evaluation of the protocol.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Step<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">A short description of the component&#8217;s task must be provided in the column <strong>[Step]<\/strong>. This description should also follow a strict system to enable easy evaluation of the protocol.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>FileId<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[FileId]<\/strong> column is used for the processing of files by the component. It is not important for describing the procedure presented here.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Description<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">An additional description of the component&#8217;s task can be inserted in this column.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>State<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[State]<\/strong> column displays the current status of the component&#8217;s execution. Possible values include <em>processing<\/em>, <em>warning<\/em>, <em>success<\/em> or <em>error<\/em>. Initially the component is started with <strong>[State]<\/strong> equal to <em>processing<\/em>. If successful, <strong>[State]<\/strong> is updated with <em>warning <\/em>or <em>success<\/em>. In case of an error, <strong>[State]<\/strong> is updated with <em>error<\/em>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Success<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The column <strong>[Success]<\/strong> indicates whether the component ended successfully with <strong>[State]<\/strong> equal to <em>warning <\/em>or <em>success<\/em>. Initially the component is started with <strong>[Success]<\/strong> equal to <em>0<\/em>. If successful, <strong>[Success]<\/strong> is updated with <em>1<\/em>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>CreatedOn<\/strong><br><strong>CreatedBy<\/strong><br><strong>ModifiedOn<\/strong><br><strong>ModifiedBy<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">See table <strong>[LL].[Execution]<\/strong>.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionComponentDeclaration\">Declaration<\/h4>\n\n\n\n<p>The table is created using the following statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE TABLE [LL].[Component] \n(\n    [Id]           bigint         IDENTITY (1, 1) NOT NULL\n   ,[ExecutionId]  bigint                         NOT NULL\n   ,[Source]       nvarchar (5)                   NOT NULL\n   ,[Component]    nvarchar (128)                 NOT NULL\n   ,[Version]      int                                NULL\n   ,[Entity]       nvarchar (128)                 NOT NULL\n   ,[Step]         nvarchar (MAX)                 NOT NULL\n   ,[Description]  nvarchar (MAX)                     NULL\n   ,[FileId]       bigint                             NULL\n   ,[State]        nvarchar (128)                     NULL\n   ,[Success]      bit                                NULL\n   ,[CreatedOn]    datetime\n       CONSTRAINT [DF_LL_Execution_CreatedOn] \n       DEFAULT (GETUTCDATE())                     NOT NULL\n   ,[CreatedBy]    nvarchar (100) \n       CONSTRAINT [DF_LL_Execution_CreatedBy] \n       DEFAULT (SUSER_SNAME())                    NOT NULL\n   ,[ModifiedOn]   datetime                           NULL\n   ,[ModifiedBy]   nvarchar (100)                     NULL\n   ,CONSTRAINT [PK_LL_Component] \n       PRIMARY KEY CLUSTERED ([Id] ASC),\n   ,CONSTRAINT [FK_LL_Component_ExecutionId] \n       FOREIGN KEY ([ExecutionId]) \n       REFERENCES [LL].[Execution] ([Id])\n);\nGO\n\nCREATE TRIGGER [LL].[TR_LL_Component_Update]\nON [LL].[Component]\nFOR UPDATE\nAS\nBEGIN\nSET NOCOUNT ON\n\n   UPDATE [LL].[Component]\n      SET\n          [ModifiedOn] = GETUTCDATE()\n         ,[ModifiedBy] = SUSER_SNAME()\n   FROM\n      [LL].[Component]\n      INNER JOIN inserted\n      ON\n        inserted.[ID] = [LL].[Component].[ID];\nEND;\nGO<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"TableDescriptionTrace\">[LL].[Trace]<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionTraceColumns\">Columns<\/h4>\n\n\n\n<p>The table contains the following columns:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Column<\/th><th class=\"has-text-align-left\" data-align=\"left\">Description<\/th><\/tr><\/thead><tbody><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Id<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[Id]<\/strong> column is declared as <strong>IDENTITY <\/strong>and identifies a log record in this table.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>ExecutionId<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">Using this foreign key to table <strong>[LL].[Execution]<\/strong>, log entries that are related to a specific execution of the ETL process can be identified.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>ComponentId<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">Using this foreign key to table <strong>[LL].[Component]<\/strong>, log entries that are related to a specific execution of a component can be identified.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Source<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The text in this column indicates the type of component that wrote the log record. Values used are, for example, <em>T-SQL<\/em> or <em>SSIS<\/em>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Component<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">This column holds the name of the component that wrote the entry. For procedures, this is the procedure name, for other components, for example, the file name of the component.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Task<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The stored procedures can also be used for logging in an SSIS package or other type of component. This column should store the name of the task in the component this log entry is related to.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Entity<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The name of the target table or &#8211; to put it more generally &#8211; the entity that is processed by the component must be specified in this column. The name can be freely chosen. It is recommended to choose the name systematically in order to facilitate a systematic evaluation of the protocol.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Step<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">A short description of the component&#8217;s task must be provided in the column <strong>[Step]<\/strong>. This description should also follow a strict system to enable easy evaluation of the protocol.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Description<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">An additional description of the component&#8217;s task can be inserted in this column.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>FileId<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">Column <strong>[FileId]<\/strong> is used for the processing of files by the component. It is not important for the description of the procedure presented here.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Action<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">In this column, the action carried out must be sepcified with a keyword. Frequently used texts include <em>insert<\/em>, <em>update<\/em>, <em>delete<\/em>, <em>copy<\/em>, etc. The same applies here: a strict system in the use of keywords makes it easier to evaluate the protocol.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>AffectedRows<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">If the action carried out inserts, updates or deletes data, the number of affected rows must be saved here. The number of affected rows can be queried, for example, using the T-SQL system function <strong>@@ROWCOUNT<\/strong>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>State<\/strong><br><strong>Success<\/strong><br><strong>CreatedOn<\/strong><br><strong>CreatedBy<\/strong><br><strong>ModifiedOn<\/strong><br><strong>ModifiedBy<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">See table <strong>[LL].[Execution]<\/strong>.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionTraceDeclaration\">Declaration<\/h4>\n\n\n\n<p>The table is created using the following statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE TABLE [LL].[Trace] \n(\n    [Id]           bigint         IDENTITY (1, 1) NOT NULL\n   ,[ExecutionId]  bigint                         NOT NULL\n   ,[ComponentId]  bigint                         NOT NULL\n   ,[Source]       nvarchar(5)                    NOT NULL\n   ,[Component]    nvarchar(128)                  NOT NULL\n   ,[Task]         nvarchar(128)                      NULL\n   ,[Entity]       nvarchar(128)                      NULL\n   ,[Step]         nvarchar(MAX)                  NOT NULL\n   ,[Description]  nvarchar(MAX)                      NULL\n   ,[FileId]       bigint                             NULL\n   ,[Action]       nvarchar(100)                      NULL\n   ,[AffectedRows] int                                NULL\n   ,[State]        nvarchar(100)                  NOT NULL\n   ,[Success]      bit                            NOT NULL\n   ,[CreatedOn]    datetime\n       CONSTRAINT [DF_LL_Trace_CreatedOn]\n       DEFAULT (GETUTCDATE())                     NOT NULL\n   ,[CreatedBy]    nvarchar(100)\n       CONSTRAINT [DF_LL_Trace_CreatedBy]\n       DEFAULT (SUSER_SNAME())                    NOT NULL\n   ,[ModifiedOn]   datetime                           NULL\n   ,[ModifiedBy]   nvarchar(128)                      NULL\n   ,CONSTRAINT [PK_LL_Trace] \n       PRIMARY KEY CLUSTERED ([Id] ASC)\n   ,CONSTRAINT [FK_LL_Trace_ComponentId]\n       FOREIGN KEY ([ComponentId])\n       REFERENCES [LL].[Component] ([Id])\n   ,CONSTRAINT [FK_LL_Trace_ExecutionId]\n       FOREIGN KEY ([ExecutionId])\n       REFERENCES [LL].[Execution] ([Id])\n);\nGO\n\nCREATE TRIGGER [LL].[TR_LL_Trace_Update]\nON [LL].[Trace]\nFOR UPDATE\nAS\nBEGIN\nSET NOCOUNT ON\n\n   UPDATE [LL].[Trace]\n      SET\n          [ModifiedOn] = GETUTCDATE()\n         ,[ModifiedBy] = SUSER_SNAME()\n   FROM\n      [LL].[Trace]\n      INNER JOIN inserted\n      ON\n        inserted.[Id] = [LL].[Trace].[Id];\nEND;\nGO<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"TableDescriptionError\">[LL].[Error]<\/h3>\n\n\n\n<p>As mentioned above, the structure of this table is designed for logging data errors, which is outside the scope of this article. However, the table is also used for logging exceptions. The description of the columns only takes into account those columns that are required for logging an exception.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionErrorColumns\">Columns<\/h4>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Column<\/th><th class=\"has-text-align-left\" data-align=\"left\">Description<\/th><\/tr><\/thead><tbody><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Id<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[Id]<\/strong> column is declared as <strong>IDENTITY <\/strong>and identifies a log record in this table.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>ExecutionId<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">Using this foreign key to table <strong>[LL].[Execution]<\/strong>, log entries that are related to a specific execution of the ETL process can be identified.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>ComponentId<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">Using this foreign key to table <strong>[LL].[Component]<\/strong>, log entries that are related to a specific execution of a component can be identified. However, the foreign key is not implemented. This is to allow logging entries in this table in absence of a log entry in table <strong>[LL].[Component]<\/strong>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>TraceId<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">Using this foreign key to table <strong>[LL].[Trace]<\/strong>, log entries that are related to a specific execution of a component can be identified. However, the foreign key is not implemented. This is to allow logging entries in this table in absence of a log entry in table <strong>[LL].[Trace]<\/strong>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>ErrorType<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The severity of the error is marked in this column. Possible values in this column are: <strong>E<\/strong> = <em>Error<\/em>, <strong>W<\/strong> = <em>Warning<\/em> and <strong>I<\/strong> = <em>Information<\/em>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Source<\/strong><br><strong>Component<\/strong><br><strong>Task<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">F\u00fcr diese Spalten gelten die gleichen Ausf\u00fchrung wie bei der Tabelle <strong>[LL].[Trace]<\/strong>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Step<br>SchemaName<br>TableName<br>FileId<br>ID1Value<br>ID1ColumnName<br>ID2Value<br>ID2ColumnName<br>ID3Value<br>ID3ColumnName<br>ErrorValue<br>ErrorColumnName<br>FileName<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">These columns are not relevant for logging an exception.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Description<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The error message is to be saved in this column. In case of an exception thrown in a stored procedure, the error message can be queried using the T-SQL BuiltIn function <strong>ERROR_MESSAGE<\/strong>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Number<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">This column is used to be saved the error number. In case of an exception thrown in a stored procedure, the error number can be queried using the T-SQL BuiltIn function <strong>ERROR_NUMBER<\/strong>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>Line<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">In case of an exception thrown in a stored procedure, the line wihtin the script or stored procedure where the exception was thrown can be queried using the T-SQL BuiltIn function <strong>ERROR_LINE<\/strong>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>State<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The status code of the exception can be queried using the T-SQL BuiltIn function <strong>ERROR_STATE<\/strong> and should be written to this column..<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>CreatedOn<\/strong><br><strong>CreatedBy<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The <strong>[CreatedOn]<\/strong> column contains a UTC timestamp. Initially, <strong>[CreatedOn]<\/strong> is assigned the current timestamp via a default value. The <strong>[CreatedBy]<\/strong> column stores the user under which the error was logged.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionErrorDeclaration\">Declaration<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE TABLE [LL].[Error]\n(\n    [Id]              bigint        IDENTITY (1, 1) NOT NULL\n   ,[ExecutionId]     bigint                        NOT NULL\n   ,[ComponentId]     bigint                            NULL\n   ,[TraceId]         bigint                            NULL\n   ,[ErrorType]       char (1)                      NOT NULL\n   ,[Source]          nvarchar(5)                   NOT NULL\n   ,[Component]       nvarchar(128)                 NOT NULL\n   ,[TaskName]        nvarchar(128)                     NULL\n   ,[Entity]          nvarchar(128)                     NULL\n   ,[Step]            nvarchar(max)                     NULL\n   ,[SchemaName]      nvarchar(128)                     NULL\n   ,[TableName]       nvarchar(128)                     NULL\n   ,[FileId]          bigint                            NULL\n   ,[ID1Value]        nvarchar(max)                     NULL\n   ,[ID1ColumnName]   nvarchar(128)                     NULL\n   ,[ID2Value]        nvarchar(max)                     NULL\n   ,[ID2ColumnName]   nvarchar(128)                     NULL\n   ,[ID3Value]        nvarchar(max)                     NULL\n   ,[ID3ColumnName]   nvarchar(128)                     NULL\n   ,[ErrorValue]      nvarchar(max)                     NULL\n   ,[ErrorColumnName] nvarchar(128)                     NULL\n   ,[FileName]        nvarchar(128)                     NULL\n   ,[Description]     nvarchar(max)                     NULL\n   ,[Number]          int                               NULL\n   ,[Line]            int                               NULL\n   ,[State]           nvarchar(max)                     NULL\n   ,[CreatedOn]       datetime\n       CONSTRAINT [DF_LL_Error_CreatedOn] \n       DEFAULT (GETUTCDATE() )                      NOT NULL\n   ,[CreatedBy]       nvarchar(100) \n       CONSTRAINT [DF_LL_Error_CreatedBy] \n       DEFAULT (SUSER_SNAME())                      NOT NULL\n   ,CONSTRAINT [PK_LL_Error] \n       PRIMARY KEY CLUSTERED ([Id] ASC)\n   ,CONSTRAINT [FK_LL_Error_ExecutionId] \n       FOREIGN KEY ([ExecutionId]) \n       REFERENCES [LL].[Execution] ([Id])\n);#\nGO<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"TableDescriptionDataModel\">Data model<\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"901\" height=\"542\" src=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030105.data-model.png\" alt=\"\" class=\"wp-image-1111\" srcset=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030105.data-model.png 901w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030105.data-model-300x180.png 300w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030105.data-model-768x462.png 768w\" sizes=\"auto, (max-width: 901px) 100vw, 901px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ETL-process-execution-status\">ETL process execution status<\/h2>\n\n\n\n<p>All process logging tables have two columns <strong>[State]<\/strong> and <strong>[Success]<\/strong>, which store the current status of the ETL process, the execution of a component or a concrete action &#8211; for example an <em>INSERT<\/em>, <em>UPDTAE<\/em> or <em>DELETE<\/em>.<br>The current status is stated in the <strong>[State]<\/strong> column with either <em>processing<\/em>, <em>warning <\/em>or <em>error<\/em>. The success is stated with <strong>[Success]<\/strong> = <em>1<\/em>. The current status of the process can only be determined by combining both status values. The following combinations of status values are permitted:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">State<\/th><th class=\"has-text-align-center\" data-align=\"center\">Success<\/th><th class=\"has-text-align-left\" data-align=\"left\">Description<\/th><\/tr><\/thead><tbody><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>processing<\/strong><strong><\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>0<\/strong><strong><\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The process is currently running <br>&#8211; or &#8211; <br>The process terminated with an exception, without updating this column.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>warning<\/strong><strong><\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>0<\/strong><strong><\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The process is currently running and a warning has been logged in the error table <strong>[LL].[Error]<\/strong>.<br>or &#8211;<br>The process terminated with an exception, without updating this column.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>warning<\/strong><strong><\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>1<\/strong><strong><\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The process was executed &#8222;successfully&#8220;. However, a warning was logged in the error table <strong>[LL].[Error]<\/strong>.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>success<\/strong><strong><\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>1<\/strong><strong><\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The process was executed successfully.<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>error<\/strong><strong><\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>0<\/strong><strong><\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">The process has thrown an exception that caused the process to be ended. The exception was catched and logged in table <strong>[LL].[Error]<\/strong>.<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Combination of status values in <strong>[State]<\/strong> and <strong>[Success]<\/strong><\/figcaption><\/figure>\n\n\n\n<p>Other combinations of status values are not permitted. The procedures used for logging will throw an exception if an invalid combination is passed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Stored-procedures-for-logging\">Stored procedures for logging<\/h2>\n\n\n\n<p>The following procedures (among others) are available for inserting log entries into the above tables:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Table<\/th><th class=\"has-text-align-left\" data-align=\"left\">Stored Procedure<\/th><\/tr><\/thead><tbody><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>[LL].[Execution]<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">[LL].[spInsertExecution]<br>[LL].[spUpdateExecution]<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>[LL].[Component]<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">[LL].[spUpdateComponent]<br>[LL].[spUpdateComponent]<br>[LL].[spUpdateComponentSuccess]<br>[LL].[spUpdateComponentWarning]<br>[LL].[spUpdateComponentError]<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>[LL].[Trace]<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">[LL].[spInsertTrace]<br>[LL].[spUpdateTrace]<br>[LL].[spUpdateTraceSuccess]<br>[LL].[spUpdateTraceWarning]<br>[LL].[spUpdateTraceError]<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\"><strong>[LL].[Error]<\/strong><\/td><td class=\"has-text-align-left\" data-align=\"left\">[LL].[spInsertError]<br>[LL].[spInsertErrorException]<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Stored procedures for logging<\/figcaption><\/figure>\n\n\n\n<p>Essentially, these procedures perform an INSERT or UPDATE on the log tables. The values to be logged are passed to the procedures as parameters. The procedures check the parameters passed and raise an exception in the case of invalid parameters.<\/p>\n\n\n\n<p>The following three code examples show the procedures <strong>[LL].[spInsertTrace]<\/strong>, <strong>[LL].[spUpdateTrace]<\/strong> and <strong>[LL].[spUpdateTraceSuccess]<\/strong>. The remaining procedures are developed in the same fassion. The code for all procedures can be downloaded via this <a href=\"https:\/\/staging.sql.marcus-belz.de\/?download=1147&amp;tmstv=1708206617\">link<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"StoredProcedure-spInsertTrace\">[LL].[spInsertTrace]<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">-- --------------------------------------------------------------------------------\n-- Parameters\n--    @p_executionId          AS int\n--       Execution Id of the current execution\n--    @p_componentId          AS int\n--       Each procedure call gets a unique id that allows identifying all messages\n--       that will be written by the procedure call\n--    @p_traceId              AS int OUT\n--       Returns the Id of the new row in [LL].[Trace]\n--    @p_source               AS nvarchar(5)\n--       Type of the calling source system (SSIS, T-SQL, ...)\n--    @p_component            AS nvarchar(128)\n--       Name of the calling SSIS-Package\n--    @p_task                 AS nvarchar(128) = NULL\n--       SSIS-Task name the log entry refers to.\n--    @p_entity               AS nvarchar(128) = NULL\n--       Entity name the log entry refers to.\n--    @p_step                 AS nvarchar(max)\n--       Description of the task in the calling object that will be logged\n--    @p_description          AS nvarchar(max) = NULL\n--       Additional description of the task in the calling object that will be\n--       logged\n--    @p_fileId               AS int = NULL\n--       Foreign Key to [LL].[FileList].[Id]\n--    @p_action               AS nvarchar(max) = NULL\n--       Specifiy any action that will be logged by this procedure call like\n--       Insert, Delete, Update, ...\n--    @p_affectedRows         AS nvarchar(max) = NULL\n--       Specifiy the number of rows\/objects that were inserted, deleted, updated, ...\n--    @p_state                AS nvarchar(100)\n--       State of the current task (processing, success, error, warning)\n--    @p_success              AS bit\n--       Specifies whether the calling procedure succeded\n--       0 = processing, warning, error\n--       1 = success\n-- --------------------------------------------------------------------------------\nCREATE PROCEDURE [LL].[spInsertTrace]\n    @p_executionId           AS int\n   ,@p_componentId           AS int\n   ,@p_traceId               AS int OUT\n   ,@p_source                AS nvarchar(5)\n   ,@p_component             AS nvarchar(128)\n   ,@p_task                  AS nvarchar(128)\n   ,@p_entity                AS nvarchar(128)\n   ,@p_step                  AS nvarchar(max)\n   ,@p_description           AS nvarchar(max)\n   ,@p_fileId                AS bigint        = NULL\n   ,@p_action                AS nvarchar(100) = NULL\n   ,@p_affectedRows          AS int\n   ,@p_state                 AS nvarchar(100)\n   ,@p_success               AS bit\nAS\nBEGIN\n   SET NOCOUNT ON;\n\n   -- --------------------------------------------------------------------------------\n   -- Declare variables\n   -- --------------------------------------------------------------------------------\n   DECLARE @component        AS nvarchar(128);\n   DECLARE @table            AS table([Id] int);\n   DECLARE @message          AS nvarchar(max);\n\n   -- --------------------------------------------------------------------------------\n   -- Initialize variables\n   -- --------------------------------------------------------------------------------\n   SET @component = OBJECT_SCHEMA_NAME(@@PROCID) + N'.' + OBJECT_NAME(@@PROCID);\n\n   -- --------------------------------------------------------------------------------\n   -- Workload\n   -- --------------------------------------------------------------------------------\n   BEGIN TRY\n      -- --------------------------------------------------------------------------------\n      -- Check parameters\n      -- --------------------------------------------------------------------------------\n      BEGIN\n         -- --------------------------------------------------------------------------------\n         -- Check @p_executionId\n         -- --------------------------------------------------------------------------------\n         IF (@p_executionId IS NULL)\n            BEGIN\n               EXEC [dbo].[spRaiseError] N'The parameter ''p_ExecutionId'' is NULL.', @component;\n               RETURN 0;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check @p_componentId\n         -- --------------------------------------------------------------------------------\n         IF (@p_componentId IS NULL)\n            BEGIN\n               EXEC [dbo].[spRaiseError] N'The parameter ''p_ComponentId'' is NULL.', @component;\n               RETURN 0;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check @p_source\n         -- --------------------------------------------------------------------------------\n         IF ([dbo].[fnIsNullOrEmpty](@p_source, 1) <> 0 )\n            BEGIN\n               EXEC [dbo].[spRaiseError] N'The parameter ''p_source'' is either NULL or an empty string.', @component;\n               RETURN 1;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check @p_component\n         -- --------------------------------------------------------------------------------\n         IF ([dbo].[fnIsNullOrEmpty](@p_component, 1) <> 0 )\n            BEGIN\n               EXEC [dbo].[spRaiseError] N'The parameter ''p_component'' is either NULL or an empty string.', @component;\n               RETURN 1;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check @p_step\n         -- --------------------------------------------------------------------------------\n         IF ([dbo].[fnIsNullOrEmpty](@p_step, 1) <> 0)\n            BEGIN\n               EXEC [dbo].[spRaiseError] N'The parameter ''p_step'' is either NULL or an empty string.', @component;\n               RETURN 1;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check @p_state\n         -- --------------------------------------------------------------------------------\n         IF ([dbo].[fnIsNullOrEmpty](@p_state, 1) <> 0)\n            BEGIN\n               EXEC [dbo].[spRaiseError] N'The parameter ''p_state'' is either NULL or an empty string', @component;\n               RETURN 1;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check @p_success\n         -- --------------------------------------------------------------------------------\n         IF @p_success IS NULL\n            BEGIN\n               EXEC [dbo].[spRaiseError] N'The parameter ''p_success'' is either NULL.', @component;\n               RETURN 1;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check combination of @p_success and @p_state\n         -- --------------------------------------------------------------------------------\n         IF (@p_success = 0 AND @p_state IN ('success')) OR (@p_success = 1 AND @p_state IN ('processing', 'error'))\n            BEGIN\n               SET @message = CONCAT('Invalid state ''', @p_state, ''' for p_success = ''', CAST(@p_success AS nvarchar(100)),'''.');\n               EXEC [dbo].[spRaiseError] @message, @component;\n               RETURN 1;\n            END;\n      END;\n\n      -- --------------------------------------------------------------------------------\n      -- Insert trace into [LL].[Trace]\n      -- --------------------------------------------------------------------------------\n      INSERT INTO [LL].[Trace]\n      (\n          [ExecutionId]\n         ,[ComponentId]\n         ,[Source]\n         ,[Component]\n         ,[Task]\n         ,[Entity]\n         ,[Step]\n         ,[Description]\n         ,[FileId]\n         ,[Action]\n         ,[AffectedRows]\n         ,[State]\n         ,[Success]\n      )\n      OUTPUT Inserted.Id INTO @table\n      VALUES\n      (\n          @p_executionId\n         ,@p_componentId\n         ,@p_source\n         ,@p_component\n         ,@p_task\n         ,@p_entity\n         ,@p_step\n         ,CASE WHEN @p_description IS NULL OR DATALENGTH(@p_description) = 0  THEN NULL ELSE @p_description END\n         ,@p_fileId\n         ,@p_action\n         ,@p_affectedRows\n         ,@p_state\n         ,@p_success\n      );\n\n      SELECT @p_traceId = [Id] FROM @table;\n\n      RETURN 0;\n   END TRY\n   BEGIN CATCH\n      THROW;\n   END CATCH;\nEND;\n-- [LL].[spInsertTrace]\n\n-- DECLARE @ExecutionId  AS int;\n-- DECLARE @ComponentId  AS int;\n-- DECLARE @traceId      AS int;\n-- DECLARE @source       AS nvarchar(5);\n-- DECLARE @component    AS nvarchar(128);\n-- DECLARE @entity       AS nvarchar(128);\n-- DECLARE @step         AS nvarchar(max);\n-- DECLARE @description  AS nvarchar(max);\n-- DECLARE @fileId       AS bigint\n-- DECLARE @action       AS nvarchar(100) = NULL\n-- DECLARE @affectedRows AS int\n-- DECLARE @state        AS nvarchar(100);\n-- DECLARE @success      AS bit;\n--\n-- SET @ExecutionId  = 1;\n-- SET @ComponentId  = 1;\n-- SET @source       = 'T-SQL';\n-- SET @component    = 'test script';\n-- SET @entity       = '[LL].[spInsertTrace]';\n-- SET @step         = '[LL].[spInsertTrace]';\n-- SET @description  = 'none';\n-- SET @fileId       = 456;\n-- SET @action       = 'Insert';\n-- SET @affectedRows = 55;\n-- SET @state        = 'processing';\n-- SET @success      = 0;\n--\n-- EXEC [LL].[spInsertTrace]\n--     @p_executionId  = @ExecutionId\n--    ,@p_componentId  = @ComponentId\n--    ,@p_traceId      = @traceId OUTPUT\n--    ,@p_source       = @source\n--    ,@p_component    = @component\n--    ,@p_entity       = @entity\n--    ,@p_step         = @step\n--    ,@p_description  = @description\n--    ,@p_fileId       = @fileId\n--    ,@p_action       = @action\n--    ,@p_affectedRows = @affectedRows\n--    ,@p_state        = @state\n--    ,@p_success      = @success;\n--\n-- SELECT @traceId;\n-- SELECT * FROM [LL].[Trace] WHERE [Id] = @traceId;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"StoredProcedure-spUpdateTrace\">[LL].[spUpdateTrace]<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">-- --------------------------------------------------------------------------------\n-- Parameters :\n--    @p_traceId              AS int\n--       ID of the row in [LL].[Trace], that is to be updated.\n--   @p_description           AS nvarchar(max)\n--       Additional description of the task in the calling object that will be logged\n--    @p_action               AS nvarchar(max) = NULL\n--       Specifiy any action that will be logged by this procedure call like Insert, Delete, Update, ...\n--    @p_affectedRows         AS nvarchar(max) = NULL\n--       Specifiy the number of rows\/objects that were inserted, deleted, updated, ...\n--    @p_state                AS nvarchar(100)\n--       State of the current task (processing, success, error, warning)\n--    @p_success              AS bit\n--       Specifies the success state of the execution\n--       0 = @p_state &gt; processing, warning, error\n--       1 = @p_state &gt; success, warning\n-- --------------------------------------------------------------------------------\nALTER PROCEDURE [LL].[spUpdateTrace]\n    @p_traceId               AS int\n   ,@p_description           AS nvarchar(max)\n   ,@p_action                AS nvarchar(100) = NULL\n   ,@p_affectedRows          AS int\n   ,@p_state                 AS nvarchar(100)\n   ,@p_success               AS bit\nAS\nBEGIN\n   SET NOCOUNT ON;\n\n   -- --------------------------------------------------------------------------------\n   -- Declare variables\n   -- --------------------------------------------------------------------------------\n   DECLARE @component        AS nvarchar(128);\n   DECLARE @tempuid          AS int;\n   DECLARE @message          AS nvarchar(max);\n\n   -- --------------------------------------------------------------------------------\n   -- Initialize variables\n   -- --------------------------------------------------------------------------------\n   SET @component = OBJECT_SCHEMA_NAME(@@PROCID) + N'.' + OBJECT_NAME(@@PROCID);\n\n   -- --------------------------------------------------------------------------------\n   -- Workload\n   -- --------------------------------------------------------------------------------\n   BEGIN TRY\n      -- --------------------------------------------------------------------------------\n      -- Check parameters\n      -- --------------------------------------------------------------------------------\n      BEGIN\n         -- --------------------------------------------------------------------------------\n         -- Check @p_traceId\n         -- --------------------------------------------------------------------------------\n         IF (@p_traceId IS NULL)\n            BEGIN\n               EXEC [dbo].[spRaiseError] N'The parameter ''p_traceid'' is NULL.', @component;\n               RETURN 1;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check @p_success\n         -- --------------------------------------------------------------------------------\n         IF (@p_success IS NULL)\n            BEGIN\n               SET @message = 'The parameter ''p_success'' is NULL.';\n               EXEC [dbo].[spRaiseError] @message, @component;\n               RETURN 1;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check combination of @p_success and @p_state\n         -- --------------------------------------------------------------------------------\n         IF (@p_success = 0 AND @p_state IN (N'success')) OR (@p_success = 1 AND @p_state IN (N'processing', N'error'))\n            BEGIN\n               SET @message = CONCAT(N'Invalid state ''', @p_state, N''' for p_success = ''', CAST(@p_success AS nvarchar(100)),'''.');\n               EXEC [dbo].[spRaiseError] @message, @component;\n               RETURN 1;\n            END;\n         -- --------------------------------------------------------------------------------\n         -- Check whether an trace log does exist in [LL].[Trace] with\n         -- [ID] = @p_traceId\n         -- --------------------------------------------------------------------------------\n         SELECT\n             @tempuid = [Id]\n         FROM\n            [LL].[Trace]\n         WHERE\n            [Id] = @p_traceId;\n\n         IF (@tempuid IS NULL)\n            BEGIN\n               SET @message = N'A record with [ID] = ''' + CAST(@p_traceId AS nvarchar(max)) + N''' could not be found.';\n               EXEC [dbo].[spRaiseError] @message, @component;\n               RETURN 1;\n            END;\n      END;\n\n      -- --------------------------------------------------------------------------------\n      -- Update trace log in [LL].[Trace]\n      -- --------------------------------------------------------------------------------\n      UPDATE [LL].[Trace]\n         SET\n             [Description]  = CASE WHEN (@p_description IS NULL OR DATALENGTH(@p_description) = 0) AND ([Description] IS NULL OR DATALENGTH([Description]) = 0) THEN NULL ELSE @p_description END\n            ,[Action]       = @p_action\n            ,[AffectedRows] = @p_affectedRows\n            ,[State]        = @p_state\n            ,[Success]      = @p_success\n      WHERE\n         [Id] = @p_traceId;\n\n      RETURN 0;\n   END TRY\n   BEGIN CATCH\n      THROW;\n   END CATCH;\nEND;\n-- [dbo].[spUpdateTrace]\n\n-- EXEC [LL].[spUpdateTrace] 1, N'process successfully finished', N'Insert', 123, N'success', 1;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"StoredProcedure-spUpdateTraceSuccess\">[LL].[spUpdateTraceSuccess]<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">-- --------------------------------------------------------------------------------\n-- Parameters :\n--    @p_traceId              AS int\n--       ID of the row in [LL].[Trace], that is to be updated.\n--    @p_description           AS nvarchar(max)\n--       Additional description of the task in the calling object that will be logged\n--    @p_action               AS nvarchar(max) = NULL\n--       Specifiy any action that will be logged by this procedure call like Insert, Delete, Update, ...\n--    @p_affectedRows         AS nvarchar(max) = NULL\n--       Specifiy the number of rows\/objects that were inserted, deleted, updated, ...\n-- --------------------------------------------------------------------------------\nALTER PROCEDURE [LL].[spUpdateTraceSuccess]\n    @p_traceId               AS int\n   ,@p_description           AS nvarchar(max)\n   ,@p_action                AS nvarchar(100) = NULL\n   ,@p_affectedRows          AS int\nAS\nBEGIN\n   SET NOCOUNT ON;\n\n   EXEC [LL].[spUpdateTrace]\n       @p_traceId\n      ,@p_description\n      ,@p_action\n      ,@p_affectedRows\n      ,'success'\n      ,1;\nEND;\n-- [LL].[spUpdateTraceSuccess]\n\n-- EXEC [LL].[spUpdateTraceSuccess] 1, 'description', 'Insert', 11;<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ExceptionHandling\">Exception Handling<\/h2>\n\n\n\n<p>To ensure that an ETL process terminates in an orderly manner and is not terminated without appropriate logging, explicit exception handling is required. In this case, <em>orderly <\/em>means that the process catches a thrown exception and updates the related log entries in the tables <strong>[LL].[Execution]<\/strong>, <strong>[LL].[Component]<\/strong> and <strong>[LL].[Trace]<\/strong> &#8211; if applicable \u2013 with <strong>[Status]<\/strong> = <em>error<\/em> and <strong>[Success]<\/strong> = <em>0<\/em> and the exception is logged in the table <strong>[LL].[Error]<\/strong>. The following diagram shows the basic procedure of exception handling:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"682\" height=\"501\" src=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030203.exceptionhandling.png\" alt=\"\" class=\"wp-image-1124\" srcset=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030203.exceptionhandling.png 682w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030203.exceptionhandling-300x220.png 300w\" sizes=\"auto, (max-width: 682px) 100vw, 682px\" \/><figcaption class=\"wp-element-caption\">Exception-Handling<\/figcaption><\/figure>\n\n\n\n<p>Exception handling is required at least at the top level of the execution of an ETL process, which is logged in the <strong>[LL].[Execution]<\/strong> table.<\/p>\n\n\n\n<p>The following code example shows an exception handling including logging in the tables <strong>[LL].[Execution]<\/strong> and <strong>[LL].[Error]<\/strong> according to the diagram above:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- Execution logging variables\nDECLARE @executionId    AS int;\nDECLARE @processName    AS varchar(max);\nDECLARE @version        AS int;\n\n-- Error logging variables\nDECLARE @componentId    AS int;\nDECLARE @traceId        AS int;\nDECLARE @source         AS nvarchar(5);\nDECLARE @component      AS nvarchar(128);\nDECLARE @task           AS nvarchar(128);\nDECLARE @entity         AS nvarchar(128);\nDECLARE @step           AS nvarchar(128);\nDECLARE @state          AS nvarchar(128);\nDECLARE @success        AS bit;\n\n-- Exception variables\nDECLARE @error_message AS nvarchar(max);\nDECLARE @error_number  AS int;\nDECLARE @error_line    AS int;\nDECLARE @error_state   AS nvarchar(max);\n\nBEGIN TRY\n    -- Initialize execution logging variables\n    SET @processName = 'Name of ETL-Process';\n    SET @version     = 123;\n\n    -- Initialize error variables\n    SET @componentId = NULL;\n    SET @traceId     = NULL;\n    SET @source      = 'sql';\n    SET @component   = 'Procedure Name';\n    SET @task        = NULL;\n    SET @entity      = 'Any Entity';\n    SET @step        = 'Do something';\n\n    EXEC [LL].[spInsertExecution] @executionId OUTPUT, @processName, @version;\n\n   -- Do something\n   RAISERROR('Any Exception', 15, 1);\n\n   SET @state        = 'success';\n   SET @success      = 1;\n   EXEC [LL].[spUpdateExecution] @executionId, @state, @success;\n\nEND TRY\nBEGIN CATCH\n   SET @error_message = ERROR_MESSAGE();\n   SET @error_number  = ERROR_NUMBER();\n   SET @error_line    = ERROR_LINE();\n   SET @error_state   = ERROR_STATE();\n\n   SET @state         = 'error';\n   SET @success       = 0;\n\n   IF @executionId IS NOT NULL\n      BEGIN\n         EXEC [LL].[spInsertErrorException] @executionId, @componentId, @traceId, @source, @component, @task, @entity, @step, @error_number, @error_message, @error_line, @error_state;\n         EXEC [LL].[spUpdateExecution] @executionId, @state, @success;\n      END;\n   THROW;\nEND CATCH<\/pre>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"Example\">Example of logging and exception handling in an ETL process<\/h1>\n\n\n\n<p>After these explanations, the following diagram shows the exception handling of a simple, compact but complete ETL process:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"611\" height=\"911\" src=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030302.process-log.png\" alt=\"\" class=\"wp-image-1130\" srcset=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030302.process-log.png 611w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030302.process-log-201x300.png 201w\" sizes=\"auto, (max-width: 611px) 100vw, 611px\" \/><figcaption class=\"wp-element-caption\">Beispiel f\u00fcr das Exception-Handling und Protokollierung eines Beispiel-ETL-Prozesses<\/figcaption><\/figure>\n\n\n\n<p>This example shows logging an ETL process developed exclusively with and consisting of 5 stored procedures. The entry procedure <strong>[T2].[spETLProcess]<\/strong> calls the two procedures <strong>[T2].[spDoSomething_1] <\/strong>and <strong>[T2].[spDoSomething_2]<\/strong>. The first simulates and logs an <em>INSERT<\/em>, <em>UPDATE <\/em>and <em>DELETE <\/em>statement, while the second procedure executes two additional procedures <strong>[T2].[spDoSomething_1_1]<\/strong> and <strong>[T2].[spDoSomething_1_2]<\/strong>. These procedures also simulate and log an <em>INSERT<\/em>, <em>UPDATE <\/em>and <em>DELETE <\/em>statement. During the execution of the <em>DELETE <\/em>statement in the second procedure, an exception is thrown, which leads to an orderly termination of the ETL process with <strong>[State]<\/strong> = <em>error<\/em> and <strong>[Success]<\/strong> = <em>0<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"281\" height=\"551\" src=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.etl-process.png\" alt=\"\" class=\"wp-image-1136\" srcset=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.etl-process.png 281w, https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.etl-process-153x300.png 153w\" sizes=\"auto, (max-width: 281px) 100vw, 281px\" \/><figcaption class=\"wp-element-caption\">Prozedur-Aufrufe des Beispiel-ETL-Prozesses<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>The example code for creating a database with the required stored procedures for logging and the ETL process procedures mentioned in the diagram from the T2 schema can be downloaded from this <a href=\"https:\/\/staging.sql.marcus-belz.de\/?download=1147&amp;tmstv=1708206617\">link<\/a>.<\/p>\n\n\n\n<p>Showing all procedures would lead to repetition. Therefore, only the entry procedure <strong>[T2].[spETLProcess] <\/strong>and the procedure <strong>[T2].[spDoSomething_2_2]<\/strong> &nbsp;are listed here.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Example-spETLProcess\">[T2].[spETLProcess]<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE PROCEDURE [T2].[spETLProcess]\nAS\nBEGIN\n   SET NOCOUNT ON;   \n\n   -- --------------------------------------------------------------------------------\n   -- Declare variables\n   -- --------------------------------------------------------------------------------\n   -- Error Variables\n   DECLARE @error_message    AS nvarchar(max);\n   DECLARE @error_number     AS int;\n   DECLARE @error_line       AS int;\n   DECLARE @error_state      AS nvarchar(max);\n\n   -- Logging Variables\n   DECLARE @component        AS nvarchar(128);\n   DECLARE @task             AS nvarchar(128);\n   DECLARE @schema           AS nvarchar(128);\n   DECLARE @table            AS nvarchar(128);\n\n   DECLARE @source           AS nvarchar(5);\n   DECLARE @step             AS nvarchar(max);\n   DECLARE @entity           AS nvarchar(max);\n   DECLARE @message          AS nvarchar(max);\n\n   DECLARE @traceId          AS int; \n   DECLARE @componentId      AS int;\n   DECLARE @executionId      AS int;\n\n   DECLARE @description      AS nvarchar(max);\n   DECLARE @affectedrows     AS int;\n   DECLARE @action           AS varchar(100);\n   DECLARE @state            AS varchar(100);\n   DECLARE @success          AS int;\n\n   -- --------------------------------------------------------------------------------\n   -- Initialize variables\n   -- --------------------------------------------------------------------------------\n   -- Logging\n   SET @message          = NULL;\n   SET @description      = NULL;\n   SET @affectedrows     = 0;\n\n   SET @component        = OBJECT_SCHEMA_NAME(@@PROCID) + N'.' + OBJECT_NAME(@@PROCID);\n   SET @source           = N'T-SQL';\n   SET @entity           = N'[<Multiple Schemas>].[<Multiple Tables>]';\n\n   -- --------------------------------------------------------------------------------\n   -- Workload\n   -- --------------------------------------------------------------------------------\n   BEGIN TRY\n      -- --------------------------------------------------------------------------------\n      -- Check parameters\n      -- --------------------------------------------------------------------------------\n      EXEC [LL].[spInsertExecution] @executionId OUTPUT, N'ETL process', 123;\n\n      -- --------------------------------------------------------------------------------\n      -- Insert component log\n      -- --------------------------------------------------------------------------------\n      SET @step        = N'Orchestrate ETL process';\n      SET @description = '';\n      EXEC [LL].[spInsertComponent] @executionId, @componentId OUTPUT, @source, @component, NULL, @entity, @step, @description;\n      \n      -- --------------------------------------------------------------------------------\n      -- Execute Procedure [T2].[spDoSomething_1]\n      -- --------------------------------------------------------------------------------\n      SET @task        = NULL;\n      SET @step        = N'Execute [T2].[spDoSomething_1]';\n      SET @action      = 'execute';\n      SET @description = NULL; \n      SET @state       = 'processing';\n      SET @success     = 0;\n      EXEC [LL].[spInsertTrace] @executionId, @componentId, @traceId OUTPUT, @source, @component, @task, @entity, @step, @description, NULL, @action, NULL, @state, @success;\n\n      EXEC [T2].[spDoSomething_1] @executionId;\n\n      EXEC [LL].[spUpdateTraceSuccess] @traceId, @description, @action, @@ROWCOUNT;\n\n      -- --------------------------------------------------------------------------------\n      -- Execute Procedure [T2].[spDoSomething_2]\n      -- --------------------------------------------------------------------------------\n      SET @task        = NULL;\n      SET @step        = N'Execute [T2].[spDoSomething_2]';\n      SET @action      = 'execute';\n      SET @description = NULL; \n      SET @state       = 'processing';\n      SET @success     = 0;\n      EXEC [LL].[spInsertTrace] @executionId, @componentId, @traceId OUTPUT, @source, @component, @task, @entity, @step, @description, NULL, @action, NULL, @state, @success;\n\n      EXEC [T2].[spDoSomething_2] @executionId;\n\n      EXEC [LL].[spUpdateTraceSuccess] @traceId, @description, @action, @@ROWCOUNT;\n\n      -- --------------------------------------------------------------------------------\n      -- Execute another procedure \n      -- --------------------------------------------------------------------------------\n      -- ...\n\n      -- --------------------------------------------------------------------------------\n      -- Update component log \n      -- --------------------------------------------------------------------------------\n      EXEC [LL].[spUpdateComponentSuccess] @componentId, @description;\n\n      -- --------------------------------------------------------------------------------\n      -- Update execution log \n      -- --------------------------------------------------------------------------------\n      SET @state       = 'success';\n      SET @success     = 1;\n      EXEC [LL].[spUpdateExecution] @executionId, @state, @success;\n\n   END TRY\n   BEGIN CATCH\n      SET @error_message = ERROR_MESSAGE();\n      SET @error_number  = ERROR_NUMBER();\n      SET @error_line    = ERROR_LINE();\n      SET @error_state   = ERROR_STATE();\n\n      IF @executionId IS NOT NULL\n         BEGIN\n            EXEC [LL].[spInsertErrorException] @executionId, @componentId, @traceId, @source, @component, NULL, NULL, @step, @error_number, @error_message, @error_line, @error_state;\n\n            IF @traceId IS NOT NULL     EXEC [LL].[spUpdateTraceError] @traceId, @description;\n            IF @componentId IS NOT NULL EXEC [LL].[spUpdateComponentError] @componentId, @description;\n\n            SET @state       = 'error';\n            SET @success     = 0;\n            EXEC [LL].[spUpdateExecution] @executionId, @state, @success;\n         END;\n   END CATCH; \nEND;<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Example-spDo\u00adSomething_2_2\">[T2].[spDo\u00adSomething_2_2]<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE PROCEDURE [T2].[spDoSomething_2_2]\n(   \n    @p_executionId           AS int\n)\nAS\nBEGIN\n   SET NOCOUNT ON;   \n\n   -- --------------------------------------------------------------------------------\n   -- Declare variables\n   -- --------------------------------------------------------------------------------\n   -- Error Variables\n   DECLARE @error_message    AS nvarchar(max);\n   DECLARE @error_number     AS int;\n   DECLARE @error_line       AS int;\n   DECLARE @error_state      AS nvarchar(max);\n\n   -- Logging Variables\n   DECLARE @component        AS nvarchar(128);\n   DECLARE @task             AS nvarchar(128);\n   DECLARE @schema           AS nvarchar(128);\n   DECLARE @table            AS nvarchar(128);\n\n   DECLARE @source           AS nvarchar(5);\n   DECLARE @step             AS nvarchar(max);\n   DECLARE @entity           AS nvarchar(max);\n   DECLARE @message          AS nvarchar(max);\n\n   DECLARE @traceId          AS int; \n   DECLARE @componentId      AS int;\n\n   DECLARE @description      AS nvarchar(max);\n   DECLARE @affectedrows     AS int;\n   DECLARE @action           AS varchar(100);\n   DECLARE @state            AS varchar(100);\n   DECLARE @success          AS int;\n\n   -- --------------------------------------------------------------------------------\n   -- Initialize variables\n   -- --------------------------------------------------------------------------------\n   -- Logging\n   SET @message          = NULL;\n   SET @description      = NULL;\n   SET @affectedrows     = 0;\n\n   SET @component        = OBJECT_SCHEMA_NAME(@@PROCID) + N'.' + OBJECT_NAME(@@PROCID);\n   SET @source           = N'T-SQL';\n   SET @entity           = N'[<SchemaName>].[<TableName>]';\n\n   -- --------------------------------------------------------------------------------\n   -- Workload\n   -- --------------------------------------------------------------------------------\n   BEGIN TRY\n      -- --------------------------------------------------------------------------------\n      -- Check parameters\n      -- --------------------------------------------------------------------------------\n      BEGIN\n         IF (@p_executionId IS NULL)\n            BEGIN\n               SET @message = N'The parameter ''p_executionId'' is NULL.';\n               EXEC [dbo].[spRaiseError] @message,  @component;\n               RETURN -1;\n            END;\n      END;\n\n      -- --------------------------------------------------------------------------------\n      -- Insert component log\n      -- --------------------------------------------------------------------------------\n      SET @step        = N'Do something';\n      SET @description = '';\n      EXEC [LL].[spInsertComponent] @p_executionId, @componentId OUTPUT, @source, @component, NULL, @entity, @step, @description;\n      \n      -- --------------------------------------------------------------------------------\n      -- Insert data\n      -- --------------------------------------------------------------------------------\n      SET @task        = NULL;\n      SET @step        = N'Insert data';\n      SET @action      = 'insert';\n      SET @description = NULL; \n      SET @state       = 'processing';\n      SET @success     = 0;\n      EXEC [LL].[spInsertTrace] @p_executionId, @componentId, @traceId OUTPUT, @source, @component, @task, @entity, @step, @description, NULL, @action, NULL, @state, @success;\n\n      -- Insert here a SQL Statement that inserts data into a table\n\n      EXEC [LL].[spUpdateTraceSuccess] @traceId, @description, @action, @@ROWCOUNT;\n   \n      -- --------------------------------------------------------------------------------\n      -- Update data\n      -- --------------------------------------------------------------------------------\n      SET @task        = NULL;\n      SET @step        = N'Update data';\n      SET @action      = 'update';\n      SET @description = NULL; \n      SET @state       = 'processing';\n      SET @success     = 0;\n      EXEC [LL].[spInsertTrace] @p_executionId, @componentId, @traceId OUTPUT, @source, @component, @task, @entity, @step, @description, NULL, @action, NULL, @state, @success;\n\n      -- Insert here a SQL Statement that updates data a table\n\n      EXEC [LL].[spUpdateTraceSuccess] @traceId, @description, @action, @@ROWCOUNT;\n\n      -- --------------------------------------------------------------------------------\n      -- Delete data      \n      -- --------------------------------------------------------------------------------\n      SET @task        = NULL;\n      SET @step        = N'Delete data';\n      SET @action      = 'delete';\n      SET @description = NULL; \n      SET @state       = 'processing';\n      SET @success     = 0;\n      EXEC [LL].[spInsertTrace] @p_executionId, @componentId, @traceId OUTPUT, @source, @component, @task, @entity, @step, @description, NULL, @action, NULL, @state, @success;\n\n      -- Insert here a SQL Statement that deletes data from a table\n      RAISERROR('Exception in [T2].[spDoSomething_2_2]', 15, 1);\n      \n      EXEC [LL].[spUpdateTraceSuccess] @traceId, @description, @action, @@ROWCOUNT;\n\n      -- --------------------------------------------------------------------------------\n      -- Update component log \n      -- --------------------------------------------------------------------------------\n      EXEC [LL].[spUpdateComponentSuccess] @componentId, @description;\n\n   END TRY\n   BEGIN CATCH\n      SET @error_message = ERROR_MESSAGE();\n      SET @error_number  = ERROR_NUMBER();\n      SET @error_line    = ERROR_LINE();\n      SET @error_state   = ERROR_STATE();\n\n      -- Write in Logging\n      IF @p_executionId IS NOT NULL\n         BEGIN\n            EXEC [LL].[spInsertErrorException] @p_executionId, @componentId, @traceId, @source, @component, NULL, NULL, @step, @error_number, @error_message, @error_line, @error_state;\n\n            IF @traceId IS NOT NULL     EXEC [LL].[spUpdateTraceError] @traceId, @description;\n            IF @componentId IS NOT NULL EXEC [LL].[spUpdateComponentError] @componentId, @description;\n         END;\n      THROW;\n   END CATCH; \nEND;<\/pre>\n\n\n\n<p>The following script contains the commands for executing the ETL process. In order to obtain a compact process log, the date in the log tables is deleted beforehand. The final SELECT statement produces the result as shown at the beginning.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- --------------------------------------------------------------------------------\n-- 01: Delete data from logging tables\n-- --------------------------------------------------------------------------------\nTRUNCATE TABLE [LL].[Error]\nTRUNCATE TABLE [LL].[Trace]\nDELETE FROM [LL].[Component]\nDELETE FROM [LL].[Execution]\nDBCC CHECKIDENT (N'[LL].[Component]', RESEED, 0);\nDBCC CHECKIDENT (N'[LL].[Execution]', RESEED, 0);\n\n-- --------------------------------------------------------------------------------\n-- 02: Execute ETL Process\n-- --------------------------------------------------------------------------------\nEXEC [T2].[spETLProcess];\n\n-- --------------------------------------------------------------------------------\n-- 03: Query logging tables\n-- --------------------------------------------------------------------------------\nSELECT * FROM [LL].[Execution];\nSELECT * FROM [LL].[Component];\nSELECT * FROM [LL].[Trace];<\/pre>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button has-custom-width wp-block-button__width-25 has-custom-font-size is-style-fill has-small-font-size\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/staging.sql.marcus-belz.de\/?download=1147&amp;tmstv=1708206617\">download sample code<\/a><\/div>\n<\/div>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"Summary\">Summary<\/h1>\n\n\n\n<p>ETL processes are data-driven processes. If data is delivered that is not expected, then there is a high probability that either not all data or even incorrect data will be written to the target system. What is only mentioned casually in this article is that at the lowest level of logging, the number of affected data records is or can be logged. Knowing the number of records expected and processed is a good indication of the success or failure of an ETL process.<\/p>\n\n\n\n<p>This approach therefore supports the development of robust ETL processes, which also ensure an assessment of data quality.<\/p>\n\n\n\n<p>What is a must in software development is often neglected when developing ETL processes: explicit exception handling. The exception handling presented here initially ensures that a process is terminated in an orderly manner in the event of an error. But when is there an error? And does an error really always have to lead to the process being aborted? In conjunction with knowledge of the expected and actual number of records processed, real error handling can be implemented.<\/p>\n\n\n\n<p>The approach presented here is, so to speak, an invitation to delve more into the data and the expected result. The protocol and in particular the knowledge of the data support the developer during the development of the ETL process in being able to assess the correctness of the development.<\/p>\n\n\n\n<p>The procedures presented merely provide a toolbox for logging. When used correctly, it produces a readable and interpretable log that allows assessing the correctness of the execution of the ETL process and the data processed.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"Related-Posts\">Related Posts<\/h1>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/staging.sql.marcus-belz.de\/?p=1046\">Dieser Artikel in Deutsch<\/a><\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"Download\">Download<\/h1>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button has-custom-width wp-block-button__width-25 has-custom-font-size is-style-fill has-small-font-size\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/staging.sql.marcus-belz.de\/?download=1147&amp;tmstv=1708206617\">download sample code<\/a><\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\"> <\/h2>\n","protected":false},"excerpt":{"rendered":"<p>How can you judge whether an ETL process has been successful? The mere fact that a process was not terminated with an exception does not necessarily mean that the process did what was expected of it. Readable and evaluable logging of an ETL process can help here. It enables a reliable assessment of the success &#8230; <a title=\"Design Pattern \/\/ Logging an ETL process with T-SQL\" class=\"read-more\" href=\"https:\/\/staging.sql.marcus-belz.de\/?p=1195&#038;lang=en\" aria-label=\"Mehr Informationen \u00fcber Design Pattern \/\/ Logging an ETL process with T-SQL\">Weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[106,108],"tags":[122,114,120,124,126,128,130,132,134],"class_list":["post-1195","post","type-post","status-publish","format-standard","hentry","category-all-languages-en","category-english-en","tag-data-integration-en","tag-design-pattern-en","tag-etl-process-en","tag-exception-handling-en","tag-logging-en","tag-logging-an-etl-process-en","tag-sql-en","tag-stored-procedures-en","tag-t-sql-en"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Design Pattern \/\/ Logging an ETL process with T-SQL - Just another SQL blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Design Pattern \/\/ Logging an ETL process with T-SQL - Just another SQL blog\" \/>\n<meta property=\"og:description\" content=\"How can you judge whether an ETL process has been successful? The mere fact that a process was not terminated with an exception does not necessarily mean that the process did what was expected of it. Readable and evaluable logging of an ETL process can help here. It enables a reliable assessment of the success ... Weiterlesen\" \/>\n<meta property=\"og:url\" content=\"https:\/\/staging.sql.marcus-belz.de\/?p=1195&amp;lang=en\" \/>\n<meta property=\"og:site_name\" content=\"Just another SQL blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-02-20T18:15:14+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-06T23:06:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png\" \/>\n<meta name=\"author\" content=\"marcus\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Geschrieben von\" \/>\n\t<meta name=\"twitter:data1\" content=\"marcus\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"36\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en\"},\"author\":{\"name\":\"marcus\",\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/#\\\/schema\\\/person\\\/98ab042e47d7286f64530ee18f20f675\"},\"headline\":\"Design Pattern \\\/\\\/ Logging an ETL process with T-SQL\",\"datePublished\":\"2024-02-20T18:15:14+00:00\",\"dateModified\":\"2026-05-06T23:06:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en\"},\"wordCount\":3959,\"image\":{\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/0304.example.trace_-1-1024x195.png\",\"keywords\":[\"Data Integration\",\"Design Pattern\",\"ETL-Process\",\"Exception-Handling\",\"Logging\",\"Logging an ETL-Process\",\"SQL\",\"Stored Procedures\",\"T-SQL\"],\"articleSection\":[\"All Languages\",\"English\"],\"inLanguage\":\"de\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en\",\"url\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en\",\"name\":\"Design Pattern \\\/\\\/ Logging an ETL process with T-SQL - Just another SQL blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/0304.example.trace_-1-1024x195.png\",\"datePublished\":\"2024-02-20T18:15:14+00:00\",\"dateModified\":\"2026-05-06T23:06:38+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/#\\\/schema\\\/person\\\/98ab042e47d7286f64530ee18f20f675\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en#primaryimage\",\"url\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/0304.example.trace_-1.png\",\"contentUrl\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/0304.example.trace_-1.png\",\"width\":1476,\"height\":281},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?p=1195&lang=en#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Design Pattern \\\/\\\/ Logging an ETL process with T-SQL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/#website\",\"url\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/\",\"name\":\"Just another SQL blog\",\"description\":\"Marcus Belz \u00b7 SQL Server \u00b7 ETL \u00b7 Datenqualit\u00e4t\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/#\\\/schema\\\/person\\\/98ab042e47d7286f64530ee18f20f675\",\"name\":\"marcus\",\"url\":\"https:\\\/\\\/staging.sql.marcus-belz.de\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Design Pattern \/\/ Logging an ETL process with T-SQL - Just another SQL blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en","og_locale":"de_DE","og_type":"article","og_title":"Design Pattern \/\/ Logging an ETL process with T-SQL - Just another SQL blog","og_description":"How can you judge whether an ETL process has been successful? The mere fact that a process was not terminated with an exception does not necessarily mean that the process did what was expected of it. Readable and evaluable logging of an ETL process can help here. It enables a reliable assessment of the success ... Weiterlesen","og_url":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en","og_site_name":"Just another SQL blog","article_published_time":"2024-02-20T18:15:14+00:00","article_modified_time":"2026-05-06T23:06:38+00:00","og_image":[{"url":"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png","type":"","width":"","height":""}],"author":"marcus","twitter_card":"summary_large_image","twitter_misc":{"Geschrieben von":"marcus","Gesch\u00e4tzte Lesezeit":"36\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en#article","isPartOf":{"@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en"},"author":{"name":"marcus","@id":"https:\/\/staging.sql.marcus-belz.de\/#\/schema\/person\/98ab042e47d7286f64530ee18f20f675"},"headline":"Design Pattern \/\/ Logging an ETL process with T-SQL","datePublished":"2024-02-20T18:15:14+00:00","dateModified":"2026-05-06T23:06:38+00:00","mainEntityOfPage":{"@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en"},"wordCount":3959,"image":{"@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en#primaryimage"},"thumbnailUrl":"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png","keywords":["Data Integration","Design Pattern","ETL-Process","Exception-Handling","Logging","Logging an ETL-Process","SQL","Stored Procedures","T-SQL"],"articleSection":["All Languages","English"],"inLanguage":"de"},{"@type":"WebPage","@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en","url":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en","name":"Design Pattern \/\/ Logging an ETL process with T-SQL - Just another SQL blog","isPartOf":{"@id":"https:\/\/staging.sql.marcus-belz.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en#primaryimage"},"image":{"@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en#primaryimage"},"thumbnailUrl":"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png","datePublished":"2024-02-20T18:15:14+00:00","dateModified":"2026-05-06T23:06:38+00:00","author":{"@id":"https:\/\/staging.sql.marcus-belz.de\/#\/schema\/person\/98ab042e47d7286f64530ee18f20f675"},"breadcrumb":{"@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en#primaryimage","url":"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1.png","contentUrl":"https:\/\/staging.sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1.png","width":1476,"height":281},{"@type":"BreadcrumbList","@id":"https:\/\/staging.sql.marcus-belz.de\/?p=1195&lang=en#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/staging.sql.marcus-belz.de\/"},{"@type":"ListItem","position":2,"name":"Design Pattern \/\/ Logging an ETL process with T-SQL"}]},{"@type":"WebSite","@id":"https:\/\/staging.sql.marcus-belz.de\/#website","url":"https:\/\/staging.sql.marcus-belz.de\/","name":"Just another SQL blog","description":"Marcus Belz \u00b7 SQL Server \u00b7 ETL \u00b7 Datenqualit\u00e4t","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/staging.sql.marcus-belz.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/staging.sql.marcus-belz.de\/#\/schema\/person\/98ab042e47d7286f64530ee18f20f675","name":"marcus","url":"https:\/\/staging.sql.marcus-belz.de\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/posts\/1195","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1195"}],"version-history":[{"count":10,"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/posts\/1195\/revisions"}],"predecessor-version":[{"id":1473,"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/posts\/1195\/revisions\/1473"}],"wp:attachment":[{"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/staging.sql.marcus-belz.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}