{"id":1046,"date":"2024-02-17T21:21:48","date_gmt":"2024-02-17T20:21:48","guid":{"rendered":"https:\/\/sql.marcus-belz.de\/?p=1046"},"modified":"2024-02-24T10:40:25","modified_gmt":"2024-02-24T09:40:25","slug":"protokollierung-eines-etl-prozesses","status":"publish","type":"post","link":"https:\/\/sql.marcus-belz.de\/?p=1046","title":{"rendered":"Design Pattern \/\/ Protokollierung eines ETL-Prozesses mit SQL"},"content":{"rendered":"\n<p>Wie kann man beurteilen, ob ein ETL-Prozess erfolgreich gewesen ist? Alleine der Umstand, dass ein Prozess nicht mit einer Exception abgebrochen wurde, bedeutet nicht zwangsl\u00e4ufig, dass der Prozess auch das gemacht hat, was man von ihm erwartet hat. Eine les- und auswertbare Protokollierung eines ETL-Prozesses kann hier helfen. Sie erm\u00f6glicht eine sichere Beurteilung des Erfolgs eines ETL-Prozesses.<\/p>\n\n\n\n<p>Dieser Artikel stellt eine Vorgehensweise f\u00fcr die Protokollierung eines ETL-Prozesses auf der Basis von gespeicherten Prozeduren vor, die Protokolldatens\u00e4tze in Protokolltabellen einf\u00fcgen und aktualisieren. Ziel ist es, ein les- und auswertbares Protokoll zu erstellen, das Antworten auf wesentliche Fragen zu der Ausf\u00fchrung eines ETL-Prozesses bereit h\u00e4lt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Wie lange dauert der ETL-Prozess insgesamt?<\/li>\n\n\n\n<li>Wie lange dauert die Ausf\u00fchrung einer gespeicherten Prozedur, eines SSIS-Paketes oder einer anderen Komponente?<\/li>\n\n\n\n<li>Wie lange dauert die Ausf\u00fchrung eines konkreten SQL-Statements?<\/li>\n\n\n\n<li>Wie viele Datens\u00e4tze wurden durch ein SQL-Statement bearbeitet?<\/li>\n<\/ul>\n\n\n\n<p>Nat\u00fcrlich wollen wir auch wissen,  ob der Prozess als Ganzes, eine Prozedur oder auch ein konkretes SQL-Statement erfolgreich ausgef\u00fchrt wurden.<\/p>\n\n\n\n<p>Die Vorgehensweise ist eigentlich gerade heraus: Zu Beginn jeder Aktion wird ein Protokolldatensatz geschrieben und nach der Beendigung der Aktion wird dieser entweder mit dem Status Erfolg oder Misserfolg und gegebenenfalls auch noch anderen hilfreichen Informationen aktualisiert. That&#8217;s it! Ein bisschen mehr darf es dann aber doch noch sein&#8230; <\/p>\n\n\n\n<!--more-->\n\n\n\n<h1 class=\"wp-block-heading\">Inhalt<\/h1>\n\n\n\n<p>\n<a href=\"#TheResult\">Das Ergebnis<\/a><br>\n<a href=\"#LetsStart\">Und nun die Herleitung&#8230;<\/a><br>\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#ThreeTierLogging\">Dreistufige Protokollierung<\/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\">Der Schemaname LL<\/a><br>\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#TableDescription\">Tabellenbeschreibung, Deklaration und Datenmodell<\/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\">Status der Ausf\u00fchrung des ETL-Prozesses<\/a><br>\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#Stored-procedures-for-logging\">Prozeduren f\u00fcr die Protokollierung<\/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\">Exception Handling<\/a><br>\n\n<a href=\"#Example\">Beispiel f\u00fcr die Protokollierung und das Exception-Handling in einem ETL-Prozess<\/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\">Fazit<\/a><br>\n\n<a href=\"#Related-Posts\">Verwandte Artikel<\/a><br>\n<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"TheResult\">Das Ergebnis<\/h1>\n\n\n\n<p>Auch wenn die Erstellung eines Protokolls an sich keine gro\u00dfe Sache ist bzw. sein sollte, gibt es doch einiges dazu zu schreiben. Fangen wir aber mit dem Ergebnis an und z\u00e4umen das Pferd von hinten auf. Die hier vorgestellte Prozessprotokollierung  ist dreistufig und verwendet die folgenden Protokoll-Tabellen:<\/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 diesen Tabellen werden ein ETL-Prozess und die damit verbundenen Komponenten und Arbeitsschritte mit wachsender Granularit\u00e4t &#8211; von oben nach unten gelesen &#8211; protokolliert. Der ETL-Prozess, die Komponenten und die einzelnen Arbeitsschritte werden mit genau einem Datensatz protokolliert. <\/p>\n\n\n\n<p>Eng mit der Erstellung der Protokollierung des Prozesses verbunden ist nat\u00fcrlich auch die Protokollierung von Fehlern. Die hier vorgestellte Vorgehensweise f\u00fcr die Protokollierung verwendet die folgenden Tabelle f\u00fcr die Protokollierung von Fehlern:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>[LL].[Error]<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Die folgenden Abbildungen zeigen das Ergebnis der dreistufigen Protokollierung eines einfachen, kompakten, aber vollst\u00e4ndigen ETL-Prozesses.<\/p>\n\n\n\n<p>In der Tabelle <strong>[LL].[Trace]<\/strong> wird jede Aktion unter anderem mit dem Namen der Prozedur, der Zielentit\u00e4t, die von der Prozedur bearbeitet wird, einer kurzen Beschreibung, was konkret gemacht wurde  und anderen Informationen, wie zum Beispiel die Anzahl der betroffenen Datens\u00e4tze und die Dauer der Ausf\u00fchrung protokolliert. <\/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:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png\" alt=\"\" class=\"wp-image-1058\" style=\"width:580px;height:110px\" srcset=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png 1024w, https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-300x57.png 300w, https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-768x146.png 768w, https:\/\/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>In der Tabelle <strong>[LL].[Component]<\/strong> werden die Aufrufe von Prozeduren und SSIS-Paketen oder &#8211; allgemein ausgedr\u00fcckt &#8211; Komponenten protokolliert. Auch hier wird eine kurze Beschreibung der Aufgabe der Komponente, die Zielentit\u00e4t und die Dauer der Ausf\u00fchrung protokolliert.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"93\" src=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1-1024x93.png\" alt=\"\" class=\"wp-image-1059\" srcset=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1-1024x93.png 1024w, https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1-300x27.png 300w, https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.component-1-768x70.png 768w, https:\/\/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>Auf der obersten Ebene wird jede Ausf\u00fchrung des ETL-Prozesses in der Tabelle <strong>[LL].[Execution]<\/strong> mit genau einem Datensatz protokolliert.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"35\" src=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1-1024x35.png\" alt=\"\" class=\"wp-image-1061\" srcset=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1-1024x35.png 1024w, https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1-300x10.png 300w, https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.execution-1-768x26.png 768w, https:\/\/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>Alle Tabellen f\u00fcr die Prozessprotokollierung enthalten zwei Spalten <strong>[State]<\/strong> und <strong>[Success]<\/strong>, in denen der Erfolg oder Misserfolg der Ausf\u00fchrung einer Aktion, einer Komponente oder des ETL-Prozesses gespeichert wird.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"LetsStart\">Und nun die Herleitung&#8230;<\/h1>\n\n\n\n<p>Nach der kurzen Einf\u00fchrung des Ergebnisses sind die folgenden Aspekte der Vorgehensweise zu kl\u00e4ren:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#ThreeTierLogging\">Dreistufige Protokollierung<\/a><\/li>\n\n\n\n<li><a href=\"#TableDescritpion\">Tabellenbeschreibung, Deklaration und Datenmodell<\/a> <\/li>\n\n\n\n<li><a href=\"#CombinationsOfStateAndSuccess\">Status der Ausf\u00fchrung des ETL-Prozesses<\/a><\/li>\n\n\n\n<li><a href=\"#LoggingProcedures\">Prozeduren f\u00fcr die Protokollierung<\/a><\/li>\n\n\n\n<li><a href=\"#ExceptionHandling\">Exception-Handling<\/a><\/li>\n\n\n\n<li><a href=\"#Example\">Beispiel f\u00fcr die Protokollierung und das Exception-Handling in einem ETL-Prozess<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ThreeTierLogging\">Dreistufige Protokollierung<\/h2>\n\n\n\n<p>Die Vorgehensweise sieht die Protokollierung eines ETL-Prozesses in den drei Tabellen <strong>[LL].[Execution]<\/strong>, <strong>[LL].[Component]<\/strong> und <strong>[LL].[Trace]<\/strong> vor. Jede der Tabellen ist f\u00fcr die Protokollierung von bestimmten Artefakten vorgesehen. Dieser Abschnitt stellt die Verwendung der jeweiligen Tabellen, ihre Spalten und den Code f\u00fcr ihre Erstellung vor.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingExecution\">[LL].[Execution]<\/h3>\n\n\n\n<p>In dieser Tabelle wird die Ausf\u00fchrung eines ETL-Prozesses mit genau einem Datensatz protokolliert. Ein ETL-Prozess hat immer eine Einstiegsfunktion. Das kann eine gespeicherte Prozedur, ein SSIS-Paket, ein Talend-Job oder aus ein <em>SQL Server Agent<\/em> Job sein. Zu Beginn der Ausf\u00fchrung der Einstiegsfunktion wird ein Protokolldatensatz in diese Tabelle eingef\u00fcgt. Nach erfolgreicher Verarbeitung aller Aufgaben wird dieser Datensatz mit dem Status <em>success <\/em>aktualisiert, im Fehlerfall mit dem Status <em>error<\/em>. Damit enth\u00e4lt diese Tabelle eine \u00dcbersicht \u00fcber alle Ausf\u00fchrungen des ETL-Prozesses und stellt Informationen wie zum Beispiel den Status und die Dauer der Ausf\u00fchrung bereit. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingComponent\">[LL].[Component]<\/h3>\n\n\n\n<p>In dieser Tabelle wird die Ausf\u00fchrung einer Komponente mit genau einem Datensatz protokolliert. Eine Komponente kann eine gespeicherte Prozedur, ein SSIS-Paket, ein Talendjob sein. Eine Komponente zeichnet sich dadurch aus, dass sie eine oder mehrere Datenmanipulationen steuert und ausf\u00fchrt. Wie schon bei der Tabelle <strong>[LL].[Execution]<\/strong> wird zu Beginn der Ausf\u00fchrung ein Protokolldatensatz in diese Tabelle eingef\u00fcgt und nach Beendigung mit dem Status <em>success <\/em>oder dem Status <em>error<\/em> aktualisiert. Damit enth\u00e4lt diese Tabelle je Ausf\u00fchrung des ETL-Prozesses eine Liste der ausgef\u00fchrten Komponenten und stellt Informationen wie den Status und die Dauer der Ausf\u00fchrung bereit.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingTrace\">[LL].[Trace]<\/h3>\n\n\n\n<p>Die Bezeichnung dieser Tabelle enth\u00e4lt schon den Hinweis, dass die Tabelle f\u00fcr die detailliertes Protokollierung der Aktionen des ETL-Prozesses vorgesehen ist, eben einen Trace erstellt. Welche Aktionen protokolliert werden ist eine Design-Entscheidung des Entwicklers. Es empfiehlt sich aber mindestens jedes INSERT- UPDATE und DELETE-Statement mit einem eigenen Protokolldatensatz zu protokollieren. Die Tabelle sieht neben den bereits oben erw\u00e4hnten Status-Feldern auch  die Speicherung der Anzahl der betroffenen Datens\u00e4tze vor und gibt damit dem Entwickler die M\u00f6glichkeit zu beurteilen, ob die Statements genau das gemacht haben, was erwartet wurde.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingError\">[LL].[Error]<\/h3>\n\n\n\n<p>Fehler, die in einem ETL-Prozess erkannt wurden, sind nat\u00fcrlich zu protokollieren. Zu unterscheiden ist die Protokollierung von Exceptions und  Datenfehlern. Die Struktur dieser Tabelle ist auf die Protokollierung von Datenfehlern ausgelegt und enth\u00e4lt Spalten, in denen jeder Datenfehler vollst\u00e4ndig, les- und auswertbar protokolliert werden kann. Dieser Artikel legt den Fokus auf die Protokollierung eines ETL-Prozesses und nicht die Protokollierung von Datenfehlern. Die Protokollierung des Prozesses ist eng verbunden nicht einem expliziten Exception-Handling. Dem Exception-Handling und der Protokollierung von Exceptions ist ein separater Abschnitt gewidmet.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"ThreeTierLoggingSchemaLL\">Der Schemaname LL<\/h3>\n\n\n\n<p>Der Schemaname <strong>LL <\/strong>steht f\u00fcr <em>Logging Layer<\/em>. In diesem Schema sind alle Protokolltabellen und die gespeicherten Prozeduren, die f\u00fcr die Protokollierung verwendet werden, gespeichert.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"TableDescription\">Tabellenbeschreibung, Deklaration und Datenmodell<\/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>Die folgenden Abschnitte beschreiben die Tabellen f\u00fcr die Protokollierung des Prozesses sowie die Tabelle f\u00fcr die Protokollierung von Fehlern. Abschlie\u00dfend findet sich ein Diagramm mit dem Datenmodell zu diesen Tabellen.<\/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\">Spalten<\/h4>\n\n\n\n<p>Die Tabelle enth\u00e4lt die folgenden Spalten:<\/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\">Spalte<\/th><th class=\"has-text-align-left\" data-align=\"left\">Beschreibung<\/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\">Die Spalte <strong>[Id]<\/strong> ist als <strong>IDENTITY <\/strong>deklariert und identifiziert einen Protokolldatensatz in dieser Tabelle.<\/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\">Die Tabellen f\u00fcr die Protokollierung k\u00f6nnen nicht nur von einem einzigen ETL-Prozess verwendet werden. Damit die Protokolldatens\u00e4tze verschiedener ETL-Prozesse voneinander unterschieden werden k\u00f6nnen, ist in der Spalte <strong>[Process]<\/strong> ein eindeutiger Name des ETL-Prozesses zu anzugeben.<\/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\">Diese beiden Spalten geben den Startzeitpunkt und das Ende der Ausf\u00fchrung eines ETL-Prozesses an. Beim Start des ETL-Prozesses wird in der Spalte <strong>[Start]<\/strong> der aktuelle Zeitstempel gespeichert. Die Spalte <strong>[End]<\/strong> wird beim Start mit einem <em>NULL <\/em>initialisiert. Der letzte Befehl eines ETL-Prozesses muss eine Aktualisierung der Datensatzes mit dem Status vornehmen (Spalten <strong>[State]<\/strong> und <strong>[Success]<\/strong>). Bei der Aktualisierung wird der aktuelle Zeitstempel in der Spalte <strong>[End]<\/strong> gespeichert. Ein <em>NULL <\/em>in der Spalte <strong>[End]<\/strong> zeigt entweder an, dass der Prozess noch ausgef\u00fchrt wird, oder dieser mit einer Exception abgebrochen ist. <br>Zeitangaben werden immer als UTC-Zeit gespeichert.<\/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\">Diese Spalten legen das Zeitfenster f\u00fcr einen Delta-Load fest. <strong>[DeltaStart]<\/strong> legt die untere Zeitgrenze fest und <strong>[DeltaEnd]<\/strong> die obere. Das Zeitfenster wird von der Prozedurgespeicherten Prozedur <strong>[LL].[spInsertExecution]<\/strong>, die den Protokolldatensatz in diese Tabelle einf\u00fcgt, automatisch ermittelt.<\/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\">In diesen Spalten ist der Kontext anzugeben, in dem der ETL-Prozess ausgef\u00fchrt wird. Der Benutzer, der in Spalte <strong>[User]<\/strong> angegeben ist, ist der Benutzer, unter dem der Prozess ausgef\u00fchrt wird. Dieser ist ma\u00dfgeblich f\u00fcr Berechtigungen an Datenbanken, Tabellen, File-Shares etc. Der Benutzer wird beim Einf\u00fcgen des Protokolldatensatzes \u00fcber die T-SQL Funktion <strong>SUSER_SNAME()<\/strong> als Default-Wert ermittelt.<br><br>In der Spalte <strong>[Machine]<\/strong> wird der Name des Computers gespeichert, auf dem der ETL-Prozess ausgef\u00fchrt wird. Der Name wird beim Einf\u00fcgen des Protokolldatensatzes \u00fcber die T-SQL Funktion <strong>HOST_NAME() <\/strong>ebenfalls als Default-Wert ermittelt.<br>Die Spalte <strong>[Version]<\/strong> nimmt die Versionsnummer des ETL-Prozesses und ist gegebenenfalls bei der Fehlersuche nach einem fehlerhaften Deployment eines ETL-Prozesses hilfreich.<\/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\">Die Spalte <strong>[State]<\/strong> zeigt den aktuellen Status des ETL-Prozesses an. M\u00f6gliche Werte sin <em>processing<\/em>, <em>warning<\/em>, <em>success<\/em> oder <em>error<\/em>. Initial wird der ETL-Prozess mit <strong>[State]<\/strong> gleich <em>processing<\/em> gestartet. Im Erfolgsfall wird <strong>[State]<\/strong> mit <em>warning<\/em> oder <em>success<\/em> aktualisiert. Im Fehlerfall wird <strong>[State]<\/strong> mit <em>error<\/em> aktualisiert.<\/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\">Die Spalte <strong>[Success] <\/strong>gibt an, ob der ETL-Prozess erfolgreich mit <strong>[State]<\/strong> gleich <em>warning<\/em> oder <em>success<\/em> beendet wurde. Initial wird der ETL-Prozess mit <strong>[Success]<\/strong> gleich <em>0<\/em> gestartet. Im Erfolgsfall wird <strong>[Success]<\/strong> mit <em>1<\/em> aktualisiert.<\/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\">Die Spalten <strong>[CreatedOn] <\/strong>und <strong>[ModifiedOn]<\/strong> enthalten einen UTC-Zeitstempel. Initial wird <strong>[CreatedOn]<\/strong> mit dem aktuellen Zeitstempel \u00fcber einen Default-Wert belegt und <strong>[ModifiedOn]<\/strong> mit einem <em>NULL<\/em>. <strong>[ModifiedOn] <\/strong>wird bei der Aktualisierung des Status mit dem dann geltenden Zeitstempel aktualisiert. Die gleiche Systematik gilt f\u00fcr die Felder <strong>[CreatedBy]<\/strong> und <strong>[ModifiedBy].<\/strong> Hier wird der Benutzer gespeichert, unter dem der Prozess ausgef\u00fchrt wird.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionExecutionDeclaration\">Deklaration<\/h4>\n\n\n\n<p>Die Tabelle wird \u00fcber die folgende Anweisung erstellt:<\/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\">Spalten<\/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\">Spalte<\/th><th class=\"has-text-align-left\" data-align=\"left\">Beschreibung<\/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\">Die Spalte <strong>[Id]<\/strong> ist als <strong>IDENTITY <\/strong>deklariert und identifiziert einen Protokolldatensatz in dieser Tabelle.<\/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\">\u00dcber diesen Fremdschl\u00fcssel auf die Tabelle <strong>[LL].[Execution]<\/strong> k\u00f6nnen die Protokolldatens\u00e4tze genau einer Ausf\u00fchrung des ETL-Prozesses zugeordnet werden.<\/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\">Der Text in dieser Spalt gibt an, von welchem Typ die Komponente ist, die den Protokolldatensatz geschrieben hat. Verwendete Werte sind zum Beispiel <em>T-SQL<\/em> oder <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\">In dieser Spalte wird der Name der Komponente, die den Protokolldatensatz geschrieben hat, festgehalten. Bei Prozeduren ist dieses der Prozedurname, bei anderen Komponenten zum Beispiel der Dateiname der Komponente.<\/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\">Sofern zu der Komponente eine Versionsnummer verf\u00fcgbar ist, kann und sollte diese in dieser Spalte ausgegeben werden.<\/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\">In dieser Spalte ist der Name der Zieltabelle, oder &#8211; allgemeiner formuliert &#8211; Entit\u00e4t anzugeben, die durch die Komponente bearbeitet wird. Der Name ist frei w\u00e4hlbar. Es empfiehlt sich, den Namen systematisch zu w\u00e4hlen, um eine systematische Auswertung des Protokolls zu erleichtern.<\/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\">In der Spalte <strong>[Step]<\/strong> ist eine kurze Beschreibung der Aufgabe der Komponente anzugeben. Auch diese Beschreibung sollte einer strengen Systematik folgen, um eine leichte Auswertung des Protokolls zu erm\u00f6glichen.<\/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\">Die Spalte [FileId] ist f\u00fcr die Verarbeitung von Dateien durch die Komponente vorgesehen. F\u00fcr die Beschreibung der hier vorgestellten Vorgehensweise ist sie nicht von Bedeutung.<\/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\">In dieser Spalte kann eine weitergehende Beschreibung der Aufgabe der Komponente eingef\u00fcgt werden.<\/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\">Die Spalte <strong>[State]<\/strong> zeigt den aktuellen Status der Ausf\u00fchrung der Komponente an. M\u00f6gliche Werte sin <em>processing<\/em>, <em>warning<\/em>, <em>success<\/em> oder <em>error<\/em>. Initial wird die Komponente mit <strong>[State]<\/strong> gleich <em>processing<\/em> gestartet. Im Erfolgsfall wird <strong>[State]<\/strong> mit <em>warning<\/em> oder <em>success<\/em> aktualisiert. Im Fehlerfall wird <strong>[State]<\/strong> mit <em>error<\/em> aktualisiert.<\/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\">Die Spalte <strong>[Success] <\/strong>gibt an, ob die Komponente erfolgreich mit <strong>[State]<\/strong> gleich <em>warning<\/em> oder <em>success<\/em> beendet wurde. Initial wird der Komponente mit <strong>[Success]<\/strong> gleich <em>0<\/em> gestartet. Im Erfolgsfall wird <strong>[Success]<\/strong> mit <em>1<\/em> aktualisiert.<\/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\">Die Spalten <strong>[CreatedOn] <\/strong>und <strong>[ModifiedOn]<\/strong> enthalten einen UTC-Zeitstempel. Initial wird <strong>[CreatedOn]<\/strong> mit dem aktuellen Zeitstempel \u00fcber einen Default-Wert belegt und <strong>[ModifiedOn]<\/strong> mit einem <em>NULL<\/em>. <strong>[ModifiedOn] <\/strong>wird bei der Aktualisierung des Status mit dem dann geltenden Zeitstempel aktualisiert. Die gleiche Systematik gilt f\u00fcr die Felder <strong>[CreatedBy]<\/strong> und <strong>[ModifiedBy].<\/strong> Hier wird der Benutzer gespeichert, unter dem der Prozess ausgef\u00fchrt wird.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionComponentDeclaration\">Deklaration<\/h4>\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\">Spalten<\/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\">Spalte<\/th><th class=\"has-text-align-left\" data-align=\"left\">Beschreibung<\/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\">Die Spalte <strong>[Id]<\/strong> ist als <strong>IDENTITY <\/strong>deklariert und identifiziert einen Protokolldatensatz in dieser Tabelle.<\/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\">\u00dcber diesen Fremdschl\u00fcssel auf die Tabelle <strong>[LL].[Execution]<\/strong> k\u00f6nnen die Protokolldatens\u00e4tze genau einer Ausf\u00fchrung des ETL-Prozesses zugeordnet werden.<\/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\">\u00dcber diesen Fremdschl\u00fcssel auf die Tabelle <strong>[LL].[Component]<\/strong> k\u00f6nnen die Protokolldatens\u00e4tze genau einer Ausf\u00fchrung einer Komponente zugeordnet werden.<\/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\">Der Text in dieser Spalt gibt an, von welchem Typ die Komponente ist, die den Protokolldatensatz geschrieben hat. Verwendete Werte sind zum Beispiel <em>T-SQL<\/em> oder <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\">In dieser Spalte wird der Name der Komponente, die den Protokolldatensatz geschrieben hat, festgehalten. Bei Prozeduren ist dieses der Prozedurname, bei anderen Komponenten zum Beispiel der Dateiname der Komponente.<\/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\">Werden die gespeicherten Prozeduren f\u00fcr die Protokollierung in einem SSIS-Paket oder einer anderen Komponentenart verwendet, ist in dieser Spalte der Name der folgenden Task, die die Aufgabe durchf\u00fchrt zu speichern.<\/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\">In dieser Spalte ist der Name der Zieltabelle, oder &#8211; allgemeiner formuliert &#8211; Entit\u00e4t anzugeben, die durch die Komponente bearbeitet wird. Der Name ist frei w\u00e4hlbar. Es empfiehlt sich, den Namen systematisch zu w\u00e4hlen, um eine systematische Auswertung des Protokolls zu erleichtern.<\/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\">In der Spalte <strong>[Step]<\/strong> ist eine kurze Beschreibung der Aufgabe der Komponente anzugeben. Auch diese Beschreibung sollte einer strengen Systematik folgen, um eine leichte Auswertung des Protokolls zu erm\u00f6glichen.<\/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\">In dieser Spalte kann eine weitergehende Beschreibung der Aufgabe der Komponente eingef\u00fcgt werden.<\/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\">Die Spalte [FileId] ist f\u00fcr die Verarbeitung von Dateien durch die Komponente vorgesehen. F\u00fcr die Beschreibung der hier vorgestellten Vorgehensweise ist sie nicht von Bedeutung.<\/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 dieser Spalte ist die ausgef\u00fchrte Aktion mit einem Schlagwort zu benennen. H\u00e4ufig verwendete Texte sind zum Beispiel <em>insert<\/em>, <em>update<\/em>, <em>delete<\/em>, <em>copy<\/em>, \u2026 Auch hier gilt: Eine strenge Systematik bei der Verwendung der Schlagworte erleichtert die Auswertung des Protokolls.<\/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\">Sofern die ausgef\u00fchrte Aktion Datens\u00e4tze einf\u00fcgt, aktualisiert oder l\u00f6scht, ist hier die Anzahl der betroffenen Datens\u00e4tze zu speichern. Die Anzahl der betroffenen Datens\u00e4tze kann zum Beispiel \u00fcber die T-SQL-Systemfunktion <strong>@@ROWCOUNT<\/strong> abgefragt werden.<\/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\">Die Spalte <strong>[State]<\/strong> zeigt den aktuellen Status der Aktion an. M\u00f6gliche Werte sind <em>processing<\/em>, <em>warning<\/em>, <em>success<\/em> oder <em>error<\/em>. Initial wird die Aktion mit <strong>[State]<\/strong> gleich <em>processing<\/em> gestartet. Im Erfolgsfall wird <strong>[State]<\/strong> mit <em>warning<\/em> oder <em>success<\/em> aktualisiert. Im Fehlerfall wird <strong>[State]<\/strong> mit <em>error<\/em> aktualisiert.<\/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\">Die Spalte <strong>[Success] <\/strong>gibt an, ob die Aktion erfolgreich mit <strong>[State]<\/strong> gleich <em>warning<\/em> oder <em>success<\/em> beendet wurde. Initial wird die Aktion mit <strong>[Success]<\/strong> gleich <em>0<\/em> gestartet. Im Erfolgsfall wird <strong>[Success]<\/strong> mit <em>1<\/em> aktualisiert.<\/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\">Die Spalten <strong>[CreatedOn] <\/strong>und <strong>[ModifiedOn]<\/strong> enthalten einen UTC-Zeitstempel. Initial wird <strong>[CreatedOn]<\/strong> mit dem aktuellen Zeitstempel \u00fcber einen Default-Wert belegt und <strong>[ModifiedOn]<\/strong> mit einem <em>NULL<\/em>. <strong>[ModifiedOn] <\/strong>wird bei der Aktualisierung des Status mit dem dann geltenden Zeitstempel aktualisiert. Die gleiche Systematik gilt f\u00fcr die Felder <strong>[CreatedBy]<\/strong> und <strong>[ModifiedBy].<\/strong> Hier wird der Benutzer gespeichert, unter dem die Aktion ausgef\u00fchrt wird.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionTraceDeclaration\">Deklaration<\/h4>\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>Wie oben bereits erw\u00e4hnt, ist die Struktur dieser Tabelle auf die Protokollierung von Datenfehlern ausgelegt, die nicht Gegenstand dieses Artikels ist. Die Tabelle wird jedoch auch f\u00fcr die Protokollierung von Exceptions verwendet. Die Beschreibung der Spalten ber\u00fccksichtigt nur jene Spalten, die f\u00fcr die Protokollierung einer Exception erforderlich sind.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionErrorColumns\">Spalten<\/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\">Spalte<\/th><th class=\"has-text-align-left\" data-align=\"left\">Beschreibung<\/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\">Die Spalte <strong>[Id]<\/strong> ist als <strong>IDENTITY <\/strong>deklariert und identifiziert einen Protokolldatensatz in dieser Tabelle.<\/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\">\u00dcber diesen Fremdschl\u00fcssel auf die Tabelle <strong>[LL].[Execution]<\/strong> k\u00f6nnen protokollierte Fehler genau einer Ausf\u00fchrung des ETL-Prozesses zugeordnet werden.<\/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\">\u00dcber diesen Fremdschl\u00fcssel auf die Tabelle <strong>[LL].[Component]<\/strong> k\u00f6nnen protokollierte Fehler genau einer Ausf\u00fchrung einer Komponente zugeordnet werden. Der Fremdschl\u00fcssel ist jedoch nicht als Constraint implementiert, um auch die Protokollierung eines Fehlers in Abwesenheit eines Protokolldatensatzes in der Tabelle <strong>[LL].[Component]<\/strong> zu erm\u00f6glichen.<\/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\">\u00dcber diesen Fremdschl\u00fcssel auf die Tabelle <strong>[LL].[Trace]<\/strong> k\u00f6nnen protokollierte Fehler genau einer Aktion zugeordnet werden. Der Fremdschl\u00fcssel ist jedoch nicht als Constraint implementiert, um auch die Protokollierung eines Fehlers in Abwesenheit eines Protokolldatensatzes in der Tabelle <strong>[LL].[Trace]<\/strong> zu erm\u00f6glichen.<\/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\">\u00dcber die Spalte [ErrorType] wird der Schweregrad des Fehlers markiert. M\u00f6gliche Werte in dieser Spalte sind:  <strong>E<\/strong> = <em>Error<\/em>, <strong>W<\/strong> = <em>Warning <\/em>und <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\">Diese Spalten sind f\u00fcr die Protokollierung einer Exception nicht relevant.<\/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\">In dieser Spalte ist die Fehlermeldung zu speichern. Im Falle einer Exception, die in einer gespeicherten Prozedur ausgel\u00f6st wurde, kann die Fehlermeldung \u00fcber die T-SQL BuiltIn-Funktion <strong>ERROR_MESSAGE<\/strong> abgefragt werden.<\/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\">In dieser Spalte ist die Fehlernummer zu speichern. Im Falle einer Exception, die in einer gespeicherten Prozedur ausgel\u00f6st wurde, kann die Fehlernummer \u00fcber die T-SQL BuiltIn-Funktion <strong>ERROR_NUMBER <\/strong>abgefragt werden.<\/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 dieser Spalte ist die Zeile, in der die Exception ausgel\u00f6st wurde, zu speichern. Im Falle einer Exception, die in einer gespeicherten Prozedur ausgel\u00f6st wurde, kann die Zeile \u00fcber die T-SQL BuiltIn-Funktion <strong>ERROR_LINE<\/strong> abgefragt werden.<\/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\">In dieser Spalte ist ein Status-Code zu speichern. Im Falle einer Exception, die in einer gespeicherten Prozedur ausgel\u00f6st wurde, kann der Status-Code der Exception \u00fcber die T-SQL BuiltIn-Funktion <strong>ERROR_STATE<\/strong> abgefragt werden.<\/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\">Die Spalte <strong>[CreatedOn] <\/strong>enth\u00e4lt einen UTC-Zeitstempel. Initial wird <strong>[CreatedOn]<\/strong> mit dem aktuellen Zeitstempel \u00fcber einen Default-Wert belegt. In der Spalte <strong>[CreatedBy]<\/strong> wird der Benutzer gespeichert, unter dem Fehler protokolliert wurde.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"TableDescriptionErrorDeclaration\">Deklaration<\/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\">Datemodell<\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"901\" height=\"542\" src=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030105.data-model.png\" alt=\"\" class=\"wp-image-1111\" srcset=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030105.data-model.png 901w, https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030105.data-model-300x180.png 300w, https:\/\/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<h1 class=\"wp-block-heading\" id=\"ETL-process-execution-status\">Status der Ausf\u00fchrung des ETL-Prozesses<\/h1>\n\n\n\n<p>Alle Tabellen f\u00fcr die Prozessprotokollierung verf\u00fcgen \u00fcber zwei Spalten <strong>[State]<\/strong> und <strong>[Success]<\/strong>, in denen der aktuelle Status des ETL-Prozesses, der Ausf\u00fchrung einer Komponente oder einer konkreten Aktion &#8211; zum Beispiel ein INSERT, UPDTA oder DELETE &#8211; gespeichert wird.<br>Der aktuelle Status wird in der Spalte <strong>[State]<\/strong> mit den Texten <em>processing<\/em>, <em>warning <\/em>und <em>error <\/em>festgehalten. Der Erfolg wird mit <strong>[Success]<\/strong> = <em>1<\/em> gespeichert. Erst durch die Kombination von beiden Status-Werten kann der aktuelle Status des Prozesses ermittelt werden. Folgende Kombinationen von Statuswerten sind zul\u00e4ssig:<\/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\">Bedeutung<\/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\">Der Prozess wird aktuell ausgef\u00fchrt &#8211; oder &#8211; Der Prozess ist hart abgebrochen und die Statusfelder konnten nicht mehr aktualisiert werden.<\/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\">Der Prozess wird aktuell ausgef\u00fchrt und es wurde eine Warnung in der Fehlertabelle <strong>[LL].[Error]<\/strong> protokolliert.<br>&#8211; oder &#8211;<br>Der Prozess ist hart abgebrochen und die Statusfelder konnten nicht mehr aktualisiert werden.<\/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\">Der Prozess wurde erfolgreich ausgef\u00fchrt. Es wurde jedoch eine Warnung in der Fehlertabelle <strong>[LL].[Error]<\/strong> protokolliert.<\/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\">Der Prozess wurde erfolgreich ausgef\u00fchrt.<\/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\">Der Prozess wurde mit einem Fehler beendet. Der Fehler wurde in der Fehlertabelle <strong>[LL].[Error]<\/strong> protokolliert.<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Statuswerte der Spalten [State] und [Success]<\/figcaption><\/figure>\n\n\n\n<p>Andere Kombinationen von Statuswerten sind nicht zul\u00e4ssig. Die Prozeduren, die f\u00fcr die Prozessprotokollierung verwendet werden, l\u00f6sen im Falle einer ung\u00fcltigen \u00fcbergebenen Kombination eine Exception aus.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"Stored-procedures-for-logging\">Prozeduren f\u00fcr die Protokollierung<\/h1>\n\n\n\n<p>F\u00fcr das Einf\u00fcgen von Protokolldatens\u00e4tzen in die oben genannten Tabellen stehen (unter anderem) die folgenden Prozeduren zur Verf\u00fcgung:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Tabelle<\/th><th class=\"has-text-align-left\" data-align=\"left\">Prozedur<\/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\">Prozeduren f\u00fcr die Prozessprotokollierung<\/figcaption><\/figure>\n\n\n\n<p>Im Wesentlichen f\u00fchren diese Prozeduren ein INSERT oder UPDATE auf den Protokolltabellen aus. Die zu protokollierenden Werte werden als Parameter an die Prozeduren \u00fcbergeben. Die Prozeduren pr\u00fcfen die \u00fcbergebenen Parameter und l\u00f6sen im Fall von ung\u00fcltigen Parametern eine Exception aus.<\/p>\n\n\n\n<p>Die folgenden drei Code-Beispiele zeigen die Prozeduren <strong>[LL].[spInsertTrace]<\/strong>, <strong>[LL].[spUpdateTrace]<\/strong> und <strong>[LL].[spUpdateTraceSuccess]<\/strong>. Die \u00fcbrigen Prozeduren sind analog entwickelt. Der Code zu allen Prozeduren kann \u00fcber diesen <a href=\"https:\/\/sql.marcus-belz.de\/?download=1147&amp;tmstv=1708206617\">Link<\/a> heruntergeladen werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"StoredProcedure-spInsertTrace\">[LL].[spInsertTrace]<\/h2>\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<h2 class=\"wp-block-heading\" id=\"StoredProcedure-spUpdateTrace\">[LL].[spUpdateTrace]<\/h2>\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<h2 class=\"wp-block-heading\" id=\"StoredProcedure-spUpdateTraceSuccess\">[LL].[spUpdateTraceSuccess]<\/h2>\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<h1 class=\"wp-block-heading\" id=\"ExceptionHandling\">Exception Handling<\/h1>\n\n\n\n<p>Um sicherzustellen, dass ein ETL-Prozess <em>geordnet <\/em>beendet und nicht ohne entsprechende Protokollierung hart abgebrochen wird, ist ein explizites Exception-Handling erforderlich. <em>Geordnet<\/em> bedeutet in diesem Fall, dass der Prozess eine ausgel\u00f6ste Exception abf\u00e4ngt, ein UPDATE auf den jeweiligen Protokolldatensatz in den Tabellen <strong>[LL].[Execution]<\/strong>, <strong>[LL].[Component]<\/strong> und <strong>[LL].[Trace]<\/strong> \u2013 sofern jeweils anwendbar \u2013 mit <strong>[Status]<\/strong> = <em>error<\/em> und <strong>[Success]<\/strong> = <em>0<\/em> durchf\u00fchrt und die Exception in der Tabelle <strong>[LL].[Error]<\/strong> protokolliert. Das folgende Diagramm zeigt die grundlegende Systematik des Exception-Handlings:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"682\" height=\"501\" src=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030203.exceptionhandling.png\" alt=\"\" class=\"wp-image-1124\" srcset=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030203.exceptionhandling.png 682w, https:\/\/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>Erst nach erfolgter Protokollierung kann der Prozess die Exception an den Aufrufer weiterreichen, so dass der aufrufende Prozess hart abgebrochen w\u00fcrde. Eine Weitergabe der Exception an den Aufrufer ist jedoch nicht erforderlich, wenn der Fehler protokoliert und die relevanten Protokolldatens\u00e4tze mit <strong>[Status]<\/strong> = <em>error<\/em> und <strong>[Success]<\/strong> = <em>0<\/em> aktualisiert wurden.<\/p>\n\n\n\n<p>Das Exception-Handling ist mindestens auf der obersten Ebene der Ausf\u00fchrung eines ETL-Prozesses, der in der Tabelle [LL].[Execution] protokolliert wird, erforderlich. <\/p>\n\n\n\n<p>Das nachfolgende Code-Beispiel zeigt ein Exception-Handling inklusive der Protokollierung in den Tabellen <strong>[LL].[Execution] <\/strong>und <strong>[LL].[Error]<\/strong> entsprechend des obigen Diagramms:<\/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\">Beispiel f\u00fcr die Protokollierung und das Exception-Handling in einem ETL-Prozess<\/h1>\n\n\n\n<p>Nach diesen Erl\u00e4uterungen zu den Grundz\u00fcgen des Exception-Handlings  zeigt das folgende Diagramm das Exception-Handling eines einfachen, kompakten aber vollst\u00e4ndigen ETL-Prozesses:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"611\" height=\"911\" src=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030302.process-log.png\" alt=\"\" class=\"wp-image-1130\" srcset=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/030302.process-log.png 611w, https:\/\/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>Dieses Beispiel zeigt die Protokollierung eines ETL-Prozesses der ausschlie\u00df\u00adlich \u00fcber gespeicherten Prozeduren entwickelt wurde und aus 5 ge\u00adspeicher\u00adten Prozeduren besteht. Die Einstiegs\u00adproze\u00addur <strong>[T2].[spETLProcess]<\/strong> ruft die beiden Prozeduren <strong>[T2].[spDoSomething_1]<\/strong> und <strong>[T2].[spDoSomething_2]<\/strong> auf. Die erste simuliert und protokolliert jeweils ein INSERT-, UPDATE- und DELETE-Statement, w\u00e4hrend die zweite Prozedur zwei weitere Prozeduren <strong>[T2].[spDoSomething_1_1]<\/strong> und <strong>[T2].[spDoSomething_1_2] <\/strong>ausf\u00fchrt. Diese Prozeduren simulieren und protokollieren ebenfalls jeweils ein INSERT-, UPDATE- und DELETE-Statement. W\u00e4hrend der Ausf\u00fchrung des DELETE-Statements in der zweiten Prozedur, wird eine Exception ausgel\u00f6st, die zu einer geordneten Beendigung des ETL-Prozesses f\u00fchrt.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"281\" height=\"551\" src=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.etl-process.png\" alt=\"\" class=\"wp-image-1136\" srcset=\"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.etl-process.png 281w, https:\/\/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>Der Beispiel-Code f\u00fcr die Erstellung einer Datenbank mit den ben\u00f6tigten gespeicherten Prozeduren f\u00fcr die Protokollierung und die in dem Diagramm genannten Prozeduren des ETL-Prozesses aus dem Schema <strong>T2<\/strong> kann \u00fcber diesen <a href=\"https:\/\/sql.marcus-belz.de\/?download=1147&amp;tmstv=1708206617\">Link <\/a>heruntergeladen werden.<\/p>\n\n\n\n<p>Da die Abbildung aller Prozeduren zu Wiederholungen f\u00fchren w\u00fcrde, werden hier nur die Einstiegsprozedur <strong>[T2].[spETLProcess]<\/strong> und die Prozedur <strong>[T2].[spDo\u00adSomething_2_2] <\/strong>&nbsp;abgebildet.<\/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>Das folgende Skript enth\u00e4lt die Anweisung f\u00fcr die Ausf\u00fchrung des ETL-Prozesses. Um ein kompaktes Prozessprotokoll zu erhalten, werden vorher die Protokolltabellen geleert. Die abschlie\u00dfenden SELECT-Statement produzieren das eingangs gezeigte Ergebnis.<\/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<h2 class=\"wp-block-heading\" id=\"Summary\">Fazit<\/h2>\n\n\n\n<p>ETL-Prozesse sind Daten getriebene Prozesse. Werden Daten geliefert, die nicht erwartet werden, dann ist die Wahrscheinlichkeit hoch, dass in dem Zielsystem entweder nicht alle Daten oder sogar falsche Daten in das Zielsystem geschrieben werden. Was in diesem Artikel nur beil\u00e4ufig erw\u00e4hnt wird ist, dass auf der untersten Ebene der Protokollierung auch die Anzahl der betroffenen Datens\u00e4tze protokolliert wird, bzw. protokolliert werden kann. Die Kenntnis der Anzahl der erwarteten und verarbeiteten Datens\u00e4tze ist ein gutes Indiz f\u00fcr den Erfolg oder Nicht-Erfolg eines ETL-Prozesses.<\/p>\n\n\n\n<p>Damit unterst\u00fctzt diese Vorgehensweise die Entwicklung von robusten ETL-Prozessen, die eine Beurteilung auch der Datenqualit\u00e4t sicherstellt.<\/p>\n\n\n\n<p>Was in der Software-Entwicklung ein Muss ist, wird bei der Entwicklung von ETL-Prozessen gerne vernachl\u00e4ssigt: ein explizites Exception-Handling. Das vorgestellte Exception-Handling stellt hier zun\u00e4chst sicher, dass ein Prozess im Fehlerfall <em>geordnet <\/em>beendet wird. Wann aber liegt ein Fehler vor? Und muss ein Fehler tats\u00e4chlich immer zum Abbruch des Prozesses f\u00fchren? In Verbindung mit der Kenntnis \u00fcber die erwartete und tats\u00e4chlich verarbeitete Anzahl Datens\u00e4tze kann eine echte Behandlung von Fehlern implementiert werden.<\/p>\n\n\n\n<p>Die hier vorgestellte Vorgehensweise ist quasi eine Einladung sich mehr mit den Daten und dem erwarteten Ergebnis zu befassen. Das Protokoll und insbesondere die Kenntnis \u00fcber die verarbeiteten Datens\u00e4tze unterst\u00fctzen bereits w\u00e4hrend der Entwicklung des ETL-Prozesses den Entwickler, die Richtigkeit der Entwicklung beurteilen zu k\u00f6nnen. <\/p>\n\n\n\n<p>Die vorgestellten Prozeduren stellen lediglich einen Werkzeugkasten f\u00fcr die Protokollierung bereit. Bei richtiger Anwendung produziert es ein les- und auswertbares Protokoll, das die Beurteilung der Korrektheit der Ausf\u00fchrung des ETL-Prozesses und der verarbeiteten Daten erm\u00f6glicht.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"Related-Posts\">Verwandte Artikel<\/h1>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/sql.marcus-belz.de\/?p=1195\">This article in English<\/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:\/\/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>Wie kann man beurteilen, ob ein ETL-Prozess erfolgreich gewesen ist? Alleine der Umstand, dass ein Prozess nicht mit einer Exception abgebrochen wurde, bedeutet nicht zwangsl\u00e4ufig, dass der Prozess auch das gemacht hat, was man von ihm erwartet hat. Eine les- <a href=\"https:\/\/sql.marcus-belz.de\/?p=1046\" class=\"read-more\">Read More &#8230;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,5],"tags":[46,39,31,27,28,30,38,32,10],"class_list":["post-1046","post","type-post","status-publish","format-standard","hentry","category-all-languages","category-german","tag-data-integration","tag-design-pattern","tag-etl-process","tag-exception-handling","tag-logging","tag-logging-an-etl-process","tag-sql","tag-stored-procedures","tag-t-sql"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Design Pattern \/\/ Protokollierung eines ETL-Prozesses mit 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:\/\/sql.marcus-belz.de\/?p=1046\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Design Pattern \/\/ Protokollierung eines ETL-Prozesses mit SQL - Just another SQL blog\" \/>\n<meta property=\"og:description\" content=\"Wie kann man beurteilen, ob ein ETL-Prozess erfolgreich gewesen ist? Alleine der Umstand, dass ein Prozess nicht mit einer Exception abgebrochen wurde, bedeutet nicht zwangsl\u00e4ufig, dass der Prozess auch das gemacht hat, was man von ihm erwartet hat. Eine les- Read More ...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/sql.marcus-belz.de\/?p=1046\" \/>\n<meta property=\"og:site_name\" content=\"Just another SQL blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-02-17T20:21:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-24T09:40:25+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/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=\"37\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046\"},\"author\":{\"name\":\"marcus\",\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/#\\\/schema\\\/person\\\/7b46a383907dc48ca44fae32ceb24744\"},\"headline\":\"Design Pattern \\\/\\\/ Protokollierung eines ETL-Prozesses mit SQL\",\"datePublished\":\"2024-02-17T20:21:48+00:00\",\"dateModified\":\"2024-02-24T09:40:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046\"},\"wordCount\":4183,\"image\":{\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/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\",\"German\"],\"inLanguage\":\"de\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046\",\"url\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046\",\"name\":\"Design Pattern \\\/\\\/ Protokollierung eines ETL-Prozesses mit SQL - Just another SQL blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/sql.marcus-belz.de\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/0304.example.trace_-1-1024x195.png\",\"datePublished\":\"2024-02-17T20:21:48+00:00\",\"dateModified\":\"2024-02-24T09:40:25+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/#\\\/schema\\\/person\\\/7b46a383907dc48ca44fae32ceb24744\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046#primaryimage\",\"url\":\"https:\\\/\\\/sql.marcus-belz.de\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/0304.example.trace_-1.png\",\"contentUrl\":\"https:\\\/\\\/sql.marcus-belz.de\\\/wp-content\\\/uploads\\\/2024\\\/02\\\/0304.example.trace_-1.png\",\"width\":1476,\"height\":281},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?p=1046#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/sql.marcus-belz.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Design Pattern \\\/\\\/ Protokollierung eines ETL-Prozesses mit SQL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/#website\",\"url\":\"https:\\\/\\\/sql.marcus-belz.de\\\/\",\"name\":\"Just another SQL blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/sql.marcus-belz.de\\\/#\\\/schema\\\/person\\\/7b46a383907dc48ca44fae32ceb24744\",\"name\":\"marcus\",\"url\":\"https:\\\/\\\/sql.marcus-belz.de\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Design Pattern \/\/ Protokollierung eines ETL-Prozesses mit 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:\/\/sql.marcus-belz.de\/?p=1046","og_locale":"de_DE","og_type":"article","og_title":"Design Pattern \/\/ Protokollierung eines ETL-Prozesses mit SQL - Just another SQL blog","og_description":"Wie kann man beurteilen, ob ein ETL-Prozess erfolgreich gewesen ist? Alleine der Umstand, dass ein Prozess nicht mit einer Exception abgebrochen wurde, bedeutet nicht zwangsl\u00e4ufig, dass der Prozess auch das gemacht hat, was man von ihm erwartet hat. Eine les- Read More ...","og_url":"https:\/\/sql.marcus-belz.de\/?p=1046","og_site_name":"Just another SQL blog","article_published_time":"2024-02-17T20:21:48+00:00","article_modified_time":"2024-02-24T09:40:25+00:00","og_image":[{"url":"https:\/\/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":"37\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/sql.marcus-belz.de\/?p=1046#article","isPartOf":{"@id":"https:\/\/sql.marcus-belz.de\/?p=1046"},"author":{"name":"marcus","@id":"https:\/\/sql.marcus-belz.de\/#\/schema\/person\/7b46a383907dc48ca44fae32ceb24744"},"headline":"Design Pattern \/\/ Protokollierung eines ETL-Prozesses mit SQL","datePublished":"2024-02-17T20:21:48+00:00","dateModified":"2024-02-24T09:40:25+00:00","mainEntityOfPage":{"@id":"https:\/\/sql.marcus-belz.de\/?p=1046"},"wordCount":4183,"image":{"@id":"https:\/\/sql.marcus-belz.de\/?p=1046#primaryimage"},"thumbnailUrl":"https:\/\/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","German"],"inLanguage":"de"},{"@type":"WebPage","@id":"https:\/\/sql.marcus-belz.de\/?p=1046","url":"https:\/\/sql.marcus-belz.de\/?p=1046","name":"Design Pattern \/\/ Protokollierung eines ETL-Prozesses mit SQL - Just another SQL blog","isPartOf":{"@id":"https:\/\/sql.marcus-belz.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/sql.marcus-belz.de\/?p=1046#primaryimage"},"image":{"@id":"https:\/\/sql.marcus-belz.de\/?p=1046#primaryimage"},"thumbnailUrl":"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1-1024x195.png","datePublished":"2024-02-17T20:21:48+00:00","dateModified":"2024-02-24T09:40:25+00:00","author":{"@id":"https:\/\/sql.marcus-belz.de\/#\/schema\/person\/7b46a383907dc48ca44fae32ceb24744"},"breadcrumb":{"@id":"https:\/\/sql.marcus-belz.de\/?p=1046#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/sql.marcus-belz.de\/?p=1046"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/sql.marcus-belz.de\/?p=1046#primaryimage","url":"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1.png","contentUrl":"https:\/\/sql.marcus-belz.de\/wp-content\/uploads\/2024\/02\/0304.example.trace_-1.png","width":1476,"height":281},{"@type":"BreadcrumbList","@id":"https:\/\/sql.marcus-belz.de\/?p=1046#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/sql.marcus-belz.de\/"},{"@type":"ListItem","position":2,"name":"Design Pattern \/\/ Protokollierung eines ETL-Prozesses mit SQL"}]},{"@type":"WebSite","@id":"https:\/\/sql.marcus-belz.de\/#website","url":"https:\/\/sql.marcus-belz.de\/","name":"Just another SQL blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/sql.marcus-belz.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/sql.marcus-belz.de\/#\/schema\/person\/7b46a383907dc48ca44fae32ceb24744","name":"marcus","url":"https:\/\/sql.marcus-belz.de\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/posts\/1046","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1046"}],"version-history":[{"count":10,"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/posts\/1046\/revisions"}],"predecessor-version":[{"id":1474,"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=\/wp\/v2\/posts\/1046\/revisions\/1474"}],"wp:attachment":[{"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1046"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1046"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sql.marcus-belz.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1046"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}