Das Modul generiert ein Insert from Select Statement auf Basis der von der Entwickler eingegebenen SQL-Abfrage und führt das effektive Statement aus. Die Zuordnung der Spalten zwischen SQL-Abfrage und der Zieltabelle erfolgt über Namen.
Name | Bedeutung |
---|---|
Modul | Insert from select |
Modulklasse | DsModTemplateSQL |
Typ | Java |
Zweck | Hinfügen der Daten in eine Zieltabelle auf Basis einer SQL Abfrage |
Transformationscode | SQL Abfrage |
Quellen | Quelltabellen in einer Datenbank |
Ziele | Zieltabelle in derselben Datenbank |
Das folgende Beispiel zeigt, wie man mit Hilfe des Moduls eine Insert-Select Anweisung aufbauen kann. Zunächst die verwendete SQL-Abfrage:
SELECT c_custkey AS key
, c_name AS name
FROM staging.customer
Heißen das Zielschema "demo" und die Zieltabelle "d_customer", generiert das Modul dazu das folgende, effektive SQL:
INSERT INTO demo.d_customer (
key
, name
)
SELECT key
, name
FROM (
SELECT c_custkey AS key
, c_name AS name
FROM staging.customer
) src
Wie im Beispiel zu erkennen, müssen die Spaltennamen der Zieltabelle als Aliase angegeben werden, wenn die Quellspalten anders heißen. Im Beispiel hat die Zieltabelle "d_customer" also die Spalten "key" und "name". Das gilt insbesondere dann, wenn man Literale oder Funktionen verwendet, um Spaltenwerte zu erzeugen wie in diesem Beispiel:
SELECT c_custkey AS key
, c_name AS name
, 'de' AS country
, CURRENT_DATE() AS createdate
FROM staging.customer
Die Quellen des Moduls sind Tabellen, die über die vom datasqill Entwickler definierte Abfrage gelesen werden. Für diese Tabellen muss der datasqill Laufzeit-Benutzer Leserechte besitzen. Alle in der SQL-Abfrage verwendeten Quelltabellen müssen über die datasqill GUI im grafischen Datenmodell mit dem Eingang des Moduls verbunden werden.
Das Ziel des Moduls ist eine einzelne Tabelle. Für diese muss der datasqill Laufzeit-Benutzer Schreibrechte besitzen. Die Zieltabelle muss mit Hilfe der datasqill GUI im grafischen Datenmodell mit dem Ausgang des Moduls verbunden werden.
Name | Typ | Bedeutung |
---|---|---|
Truncate Before | Boolean | Das Modul löscht die Zieltabelle vor dem Beschreiben, wenn dieses Attribute auf 'Y' gesetzt ist. Das Löschen wird mit Hilfe einer Stored-Procedure versucht, die TRUNC_TABLE heißen muss. Ist die Stored-Procedure nicht vorhanden, wird der SQL-Befehl DELETE verwendet. |
Ein komplexeres Beispiel könnte wie folgt aussehen. Mit Hilfe der Abfrage
SELECT nation_key, part_key, supplier_key, ps_supplycost AS supplycost
, ps_availqty AS availqty, CASE WHEN MIN(ps_supplycost) OVER (PARTITION BY region_key, part_key) = ps_supplycost THEN 'Y' ELSE 'N' END is_min_supply_cost
FROM demo.d_supplier, staging.partsupp, demo.d_nation, demo.d_part
WHERE ps_partkey = part_key
AND ps_suppkey = supplier_key
AND supplier_nation_key = nation_key
werden Daten aus den Tabellen demo.d_supplier, staging.partsupp, demo.d_nation und demo.d_part in einem Join verknüpft und gelesen.
Das Modul erzeugt daraus die effektive SQL-Anweisung:
INSERT into demo.f_supplier_rank (
nation_key
, part_key
, supplier_key
, supplycost
, availqty
, is_min_supply_cost
)
SELECT nation_key
, part_key
, supplier_key
, supplycost
, availqty
, is_min_supply_cost
FROM (
SELECT nation_key, part_key, supplier_key, ps_supplycost AS supplycost
, ps_availqty AS availqty, CASE WHEN MIN(ps_supplycost) OVER (PARTITION BY region_key, part_key) = ps_supplycost THEN 'Y' ELSE 'N' END is_min_supply_cost
FROM demo.d_supplier, staging.partsupp, demo.d_nation, demo.d_part
WHERE ps_partkey = part_key
AND ps_suppkey = supplier_key
AND supplier_nation_key = nation_key
) src
Wie man erkennen kann ist die originale SQL-Abfrage exakt und im gleichen Format in der generierten enthalten.
Bei der Installation des Modules kann man weitere Attribute einstellen
Das Modul lässt sich derart erweitern, dass man das Attribut "Loop Query" aktiviert (siehe Einstellen von Modul-Attributen im Anhang):
Name | Typ | Bedeutung |
---|---|---|
Loop Query | SQL | Schleifenabfrage um die Ergebnisse in der Hauptabfrage zu verwenden. |
Dann hat man zusätzlich zum "Truncate Before" ein weiteres Attribut in dem man eine Query eingeben kann. Wenn man eine Loop-Query erfasst, dann führt das Modul pro gefundenen Datensatz die Hauptquery aus. Hierbei kann man die Spaltenergebnisse als Variablen verwenden.
Da die Hauptquery pro Ergebniszeile von der Loop-Query ausgeführt wird, sollte man die Ergebnismenge der Loop-Query gering halten. Sonst verliert man die Performanz von Mengenoperation und die Ausführung verhält sich prozedural.
Sehr sinnvoll kann man die Loop-Query auch als IF-Query verwenden. Z.B:
SELECT DISTINCT 1
FROM <source-table>
WHERE <last-change-date> >= <today>-7
Man bekommt eine Zeile, wenn sich seit 7 Tagen etwas geändert hat ansonsten keine. Somit wird die Haupt-Query einmal oder kein Mal ausgeführt.
In der Haupt-Query kann man die Spaltennamen der Loop-Query als Variablen verwenden. Es ist jedoch zu beachten, dass die Variablen jeweils als Text (String) eingefügt werden.
Hierzu ein Beispiel für die monatsweise Verarbeitung von Daten der letzten 6 Monate mit Oracle SQL.
Loop-Query:
SELECT DISTINCT TO_CHAR(TRUNC(day, 'MM'), 'DD.MM.YYYY') monat
FROM <source-table>
WHERE day >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -5)
und die Haupt-Query dazu:
SELECT day, col1, col2, ... , coln
FROM <source-table>
WHERE TRUNC(day, 'MM') = TO_DATE('${monat}', 'DD.MM.YYYY')
datasqill ersetzt in der Haupt-Query pro Schleifendurchlauf der Loop-Query die Variable ${monat} mit dem Wert der Spalte monat von der Loop-Query. Da der generierte Spaltenwert als Text übertragen wird, muss (wie in diesem Beispiel) eine Datentypenkonvertierung erfolgen.
Man kann technische Spalten definieren, die es ermöglichen, im Nachhinein zu sehen wann welche Zeilen eingefügt oder geändert wurden:
Name | Spaltendefinition | Bedeutung | Wert |
---|---|---|---|
ins_date | ta_inserted_ts | Eingefügt am | Wird mit dem aktuellen Zeitpunkt (current_date) beim Einfügen befüllt |
ins_by | ta_inserted_by | Eingefügt von | Wird mit dem aktuellen Änderer (current_by) beim Einfügen befüllt |
upd_date | ta_modified_ts | Geändert am | Wird mit dem aktuellen Zeitpunkt (current_date) beim Einfügen befüllt |
upd_by | ta_modified_by | Geändert von | Wird mit dem aktuellen Änderer (current_by) beim Einfügen befüllt |
del_date | ta_deletion_ts | Gelöscht am | Wird mit NULL beim Einfügen befüllt |
del_by | ta_deleted_by | Gelöscht von | Wird mit NULL beim Einfügen befüllt |
del_ind | ta_is_deleted | Löschkennzeichen | Wird mit 'N' beim Einfügen befüllt |
current_date | ${get_current_datetime()} | Dieser Wert definiert den aktuellen Zeitpunkt | Im Auslieferungszustand der aktuelle Zeitpunkt in date-time (ohne Millisekunden) |
current_by | ${request_id} | Dieser Wert definiert den aktuellen Änderer | Im Auslieferungszustand die Request ID der datasqill Action Ausführung |
Die verwendeten Spaltennamen (unter Spaltendefinition) kann man ändern, sodass sie z.B. nicht mehr ta_inserted_ts heißt sondern insert_date. Siehe auch hierzu das Einstellen von Modul-Attributen im Anhang.
Enthät die Zieltabelle einige oder mehrere dieser technischen Spalten, so werden sie entsprechend der obigen Tabelle gefüllt. Ändert man im allerersten Beispiel die Zieltabelle "demo.d_customer" und fügt die technischen Spalten ta_inserted_ts, ta_inserted_by, ta_modified_ts und ta_modified_by hinzu, so wird unter Postgres folgendes generiert:
INSERT INTO demo.d_customer (
key
, name
, ta_modified_by
, ta_modified_ts
, ta_inserted_by
, ta_inserted_ts
)
SELECT key
, name
, 2423589
, DATE_TRUNC('second', CURRENT_TIMESTAMP)
, 2423589
, DATE_TRUNC('second', CURRENT_TIMESTAMP)
FROM (
SELECT c_custkey AS key
, c_name AS name
FROM staging.customer
) src
Unter Oracle wäre das Resultat:
INSERT INTO demo.d_customer (
key
, name
, ta_modified_by
, ta_modified_ts
, ta_inserted_by
, ta_inserted_ts
)
SELECT key
, name
, 2423589
, SYSDATE
, 2423589
, SYSDATE
FROM (
SELECT c_custkey AS key
, c_name AS name
FROM staging.customer
) src