Browse Source

db_compare auf neue Struktur umgestellt

gc-server3 9 months ago
parent
commit
73bac88fd3
4 changed files with 165 additions and 171 deletions
  1. 78 78
      database/CARLO.csv
  2. 54 68
      database/db_compare.py
  3. 4 6
      database/db_create.py
  4. 29 19
      database/model.py

+ 78 - 78
database/CARLO.csv

@@ -1,78 +1,78 @@
-source;target;filter;query;iterative
-{0}$Abnehmergruppe VW;Abnehmergruppe_VW;;;
-{0}$Arbeitswertposten;Arbeitswertposten;T1.[Buchungsdatum] >= {1};;timestamp
-{0}$Archiv_ Filialauftragskopf;Archiv_Filialauftragskopf;;;
-{0}$Archiv_ Filialauftragszeile;Archiv_Filialauftragszeile;;;
-{0}$Archiv_ Werkstattkopf;Archiv_Werkstattkopf;T1.[Buchungsdatum] >= {1};;
-{0}$Archiv_ Werkstattzeile;Archiv_Werkstattzeile;;SELECT T1.* FROM [{0}$Archiv_ Werkstattzeile] T1 INNER JOIN [{0}$Archiv_ Werkstattkopf] T2 ON T1.[Belegart] = T2.[Belegart] AND T1.[Belegnr_] = T2.[Nr_] WHERE T2.[Buchungsdatum] >= {2};
-{0}$Archivierter Verkaufskopf;Archiv_Verkaufskopf;T1.[Buchungsdatum] >= {1};;
-{0}$Artikel;Artikel;;;timestamp
-{0}$Artikel Buch_-Blattzeile;Artikel_Buch_Blattzeile;;;
-{0}$Calendar_T;Calendar_T;;;
-{0}$Debitor;Debitor;;;
-{0}$Debitorenposten;Debitorenposten;T1.[Buchungsdatum] >= {2} OR T1.[Offen] = '1';;timestamp
-{0}$Debitorgruppe;Debitorgruppe;;;
-{0}$Employee;Employee;;;
-{0}$Employee_T;Employee_T;;;
-{0}$Fahrzeug;Fahrzeug;;;timestamp
-{0}$Fahrzeug Ausstattung;Fahrzeug_Ausstattung;T1.[Ausstattungskennzeichen] = '1' OR T1.[Zeilennr_] = '10000';;timestamp
-{0}$Fahrzeug Hauptgruppe;Fahrzeug_Hauptgruppe;;;
-{0}$Fahrzeug Untergruppe;Fahrzeug_Untergruppe;;;
-{0}$Fahrzeugposten;Fahrzeugposten;T1.[Buchungsdatum] >= {1};;
-{0}$Fibu Buch_-Blatt Name;Fibu_Buch_Blatt_Name;;;
-{0}$Fibu Buch_-Blatt Verteilung;Fibu_Buch_Blatt_Verteilung;;;
-{0}$Fibu Buch_-Blatt Vorlage;Fibu_Buch_Blatt_Vorlage;;;
-{0}$Fibu Buch_-Blattzeile;Fibu_Buch_Blattzeile;;;
-{0}$Filialbezeichnung;Filialbezeichnung;;;
-{0}$Geschäftsbuchungsgrp_;Geschaeftsbuchungsgrp;;;
-{0}$Herkunftscode;Herkunftscode;;;
-{0}$Kontensch_Kontrolle Sachp BKR;Kontensch_Kontrolle_Sachp_BKR;;;
-{0}$Kostenstelle;Kostenstelle;;;
-{0}$Kostenträgerbuchungsgruppe;Kostentraegerbuchungsgruppe;;;
-{0}$Kostenträgerkonto;Kostentraegerkonto;;;
-{0}$Kostenträgerposten;Kostentraegerposten;;;
-{0}$Kreditor;Kreditor;;;
-{0}$Kreditorenposten;Kreditorenposten;T1.[Buchungsdatum] >= {1};;
-{0}$Marke;Marke;;;
-{0}$MB Branchcode Mapping;MB_Branchcode_Mapping;;;
-{0}$MB Costcenter;MB_Costcenter;;;
-{0}$MB Costcentercode Mapping;MB_Costcentercode_Mapping;;;
-{0}$MB Costunit;MB_Costunit;;;
-{0}$MB Costunitcode Mapping;MB_Costunitcode_Mapping;;;
-{0}$MB Distr_-channelcode Mapping;MB_Distr_Channelcode_Mapping;;;
-{0}$MB Distributionchannel;MB_Distributionchannel;;;
-{0}$MB Location;MB_Location;;;
-{0}$MB Locationcode Mapping;MB_Locationcode_Mapping;;;
-{0}$MB Make;MB_Make;;;
-{0}$MB Make KBA No_ Mapping;MB_Make_KBA_No_Mapping;;;
-{0}$MB Makecode Mapping;MB_Makecode_Mapping;;;
-{0}$MB Setup;MB_Setup;;;
-{0}$Modell Line Neu;Modell_Line_Neu;;;
-{0}$Modell-Aufbauten;Modell_Aufbauten;;;
-{0}$Modellinien;Modellinien;;;
-{0}$Model-Linien alt;Model_Linien_alt;;;
-{0}$Modelljahre;Modelljahre;;;
-{0}$Paketposten;Paketposten;;;
-{0}$Produktbuchungsgrp_;Produktbuchungsgrp;;;
-{0}$Produktklasse;Produktklasse;;;
-{0}$Sachkonto;Sachkonto;;;
-{0}$Sachposten;Sachposten;T1.[Buchungsdatum] >= {2};;timestamp
-{0}$Task Acquisition Ledger Entry;Task_Acquisition_Ledger_Entry;T1.[Date] >= {1};;
-{0}$Task Type;Task_Type;;;
-{0}$Teilehandel-Statistik Details;Teilehandel_Statistik_Details;;;
-{0}$Teilehandel-Statistik Summen;Teilehandel_Statistik_Summen;;;
-{0}$Time Account_T;Time_Account_T;;;
-{0}$Time Entry_T;Time_Entry_T;T1.[Current Date] >= {1};;timestamp
-{0}$Verkäufer_Einkäufer;Verkaeufer_Einkaeufer;;;
-{0}$Verkaufsanfragekopf;Verkaufsanfragekopf;;;
-{0}$Verkaufsanfragezeile;Verkaufsanfragezeile;;;
-{0}$Verkaufsgutschriftskopf;Verkaufsgutschriftskopf;T1.[Buchungsdatum] >= {1};;
-{0}$Verkaufsgutschriftszeile;Verkaufsgutschriftszeile;T1.[Buchungsdatum] >= {1};;
-{0}$Verkaufskopf;Verkaufskopf;;;
-{0}$Verkaufsrechnungskopf;Verkaufsrechnungskopf;T1.[Buchungsdatum] >= {1};;timestamp
-{0}$Verkaufsrechnungszeile;Verkaufsrechnungszeile;T1.[Buchungsdatum] >= {2};;timestamp
-{0}$Verkaufszeile;Verkaufszeile;;;
-{0}$Werkstattkopf;Werkstattkopf;;;
-{0}$Werkstattposten;Werkstattposten;T1.[Buchungsdatum] >= {2};;timestamp
-{0}$Werkstattzeile;Werkstattzeile;;;
-{0}$Wertposten;Wertposten;T1.[Buchungsdatum] >= {1};;timestamp
+source;dest;dest_db;filter;query;iterative;cols
+{0}$Abnehmergruppe VW;Abnehmergruppe_VW;CARLO2;;;;
+{0}$Arbeitswertposten;Arbeitswertposten;CARLO2;T1.[Buchungsdatum] >= '{1}';;timestamp;
+{0}$Archiv_ Filialauftragskopf;Archiv_Filialauftragskopf;CARLO2;;;;
+{0}$Archiv_ Filialauftragszeile;Archiv_Filialauftragszeile;CARLO2;;;;
+{0}$Archiv_ Werkstattkopf;Archiv_Werkstattkopf;CARLO2;T1.[Buchungsdatum] >= '{1}';;;
+{0}$Archiv_ Werkstattzeile;Archiv_Werkstattzeile;CARLO2;;SELECT T1.* FROM [{0}$Archiv_ Werkstattzeile] T1 INNER JOIN [{0}$Archiv_ Werkstattkopf] T2 ON T1.[Belegart] = T2.[Belegart] AND T1.[Belegnr_] = T2.[Nr_] WHERE T2.[Buchungsdatum] >= '{2}';;
+{0}$Archivierter Verkaufskopf;Archiv_Verkaufskopf;CARLO2;T1.[Buchungsdatum] >= '{1}';;;
+{0}$Artikel;Artikel;CARLO2;;;timestamp;
+{0}$Artikel Buch_-Blattzeile;Artikel_Buch_Blattzeile;CARLO2;;;;
+{0}$Calendar_T;Calendar_T;CARLO2;;;;
+{0}$Debitor;Debitor;CARLO2;;;;
+{0}$Debitorenposten;Debitorenposten;CARLO2;T1.[Buchungsdatum] >= '{2}' OR T1.[Offen] = '1';;timestamp;
+{0}$Debitorgruppe;Debitorgruppe;CARLO2;;;;
+{0}$Employee;Employee;CARLO2;;;;
+{0}$Employee_T;Employee_T;CARLO2;;;;
+{0}$Fahrzeug;Fahrzeug;CARLO2;;;timestamp;
+{0}$Fahrzeug Ausstattung;Fahrzeug_Ausstattung;CARLO2;T1.[Ausstattungskennzeichen] = '1' OR T1.[Zeilennr_] = '10000';;timestamp;
+{0}$Fahrzeug Hauptgruppe;Fahrzeug_Hauptgruppe;CARLO2;;;;
+{0}$Fahrzeug Untergruppe;Fahrzeug_Untergruppe;CARLO2;;;;
+{0}$Fahrzeugposten;Fahrzeugposten;CARLO2;T1.[Buchungsdatum] >= '{1}';;;
+{0}$Fibu Buch_-Blatt Name;Fibu_Buch_Blatt_Name;CARLO2;;;;
+{0}$Fibu Buch_-Blatt Verteilung;Fibu_Buch_Blatt_Verteilung;CARLO2;;;;
+{0}$Fibu Buch_-Blatt Vorlage;Fibu_Buch_Blatt_Vorlage;CARLO2;;;;
+{0}$Fibu Buch_-Blattzeile;Fibu_Buch_Blattzeile;CARLO2;;;;
+{0}$Filialbezeichnung;Filialbezeichnung;CARLO2;;;;
+{0}$Gesch�ftsbuchungsgrp_;Geschaeftsbuchungsgrp;CARLO2;;;;
+{0}$Herkunftscode;Herkunftscode;CARLO2;;;;
+{0}$Kontensch_Kontrolle Sachp BKR;Kontensch_Kontrolle_Sachp_BKR;CARLO2;;;;
+{0}$Kostenstelle;Kostenstelle;CARLO2;;;;
+{0}$Kostentr�gerbuchungsgruppe;Kostentraegerbuchungsgruppe;CARLO2;;;;
+{0}$Kostentr�gerkonto;Kostentraegerkonto;CARLO2;;;;
+{0}$Kostentr�gerposten;Kostentraegerposten;CARLO2;;;;
+{0}$Kreditor;Kreditor;CARLO2;;;;
+{0}$Kreditorenposten;Kreditorenposten;CARLO2;T1.[Buchungsdatum] >= '{1}';;;
+{0}$Marke;Marke;CARLO2;;;;
+{0}$MB Branchcode Mapping;MB_Branchcode_Mapping;CARLO2;;;;
+{0}$MB Costcenter;MB_Costcenter;CARLO2;;;;
+{0}$MB Costcentercode Mapping;MB_Costcentercode_Mapping;CARLO2;;;;
+{0}$MB Costunit;MB_Costunit;CARLO2;;;;
+{0}$MB Costunitcode Mapping;MB_Costunitcode_Mapping;CARLO2;;;;
+{0}$MB Distr_-channelcode Mapping;MB_Distr_Channelcode_Mapping;CARLO2;;;;
+{0}$MB Distributionchannel;MB_Distributionchannel;CARLO2;;;;
+{0}$MB Location;MB_Location;CARLO2;;;;
+{0}$MB Locationcode Mapping;MB_Locationcode_Mapping;CARLO2;;;;
+{0}$MB Make;MB_Make;CARLO2;;;;
+{0}$MB Make KBA No_ Mapping;MB_Make_KBA_No_Mapping;CARLO2;;;;
+{0}$MB Makecode Mapping;MB_Makecode_Mapping;CARLO2;;;;
+{0}$MB Setup;MB_Setup;CARLO2;;;;
+{0}$Modell Line Neu;Modell_Line_Neu;CARLO2;;;;
+{0}$Modell-Aufbauten;Modell_Aufbauten;CARLO2;;;;
+{0}$Modellinien;Modellinien;CARLO2;;;;
+{0}$Model-Linien alt;Model_Linien_alt;CARLO2;;;;
+{0}$Modelljahre;Modelljahre;CARLO2;;;;
+{0}$Paketposten;Paketposten;CARLO2;;;;
+{0}$Produktbuchungsgrp_;Produktbuchungsgrp;CARLO2;;;;
+{0}$Produktklasse;Produktklasse;CARLO2;;;;
+{0}$Sachkonto;Sachkonto;CARLO2;;;;
+{0}$Sachposten;Sachposten;CARLO2;T1.[Buchungsdatum] >= '{2}';;timestamp;
+{0}$Task Acquisition Ledger Entry;Task_Acquisition_Ledger_Entry;CARLO2;T1.[Date] >= '{1}';;;
+{0}$Task Type;Task_Type;CARLO2;;;;
+{0}$Teilehandel-Statistik Details;Teilehandel_Statistik_Details;CARLO2;;;;
+{0}$Teilehandel-Statistik Summen;Teilehandel_Statistik_Summen;CARLO2;;;;
+{0}$Time Account_T;Time_Account_T;CARLO2;;;;
+{0}$Time Entry_T;Time_Entry_T;CARLO2;T1.[Current Date] >= '{1}';;timestamp;
+{0}$Verk�ufer_Eink�ufer;Verkaeufer_Einkaeufer;CARLO2;;;;
+{0}$Verkaufsanfragekopf;Verkaufsanfragekopf;CARLO2;;;;
+{0}$Verkaufsanfragezeile;Verkaufsanfragezeile;CARLO2;;;;
+{0}$Verkaufsgutschriftskopf;Verkaufsgutschriftskopf;CARLO2;T1.[Buchungsdatum] >= '{1}';;;
+{0}$Verkaufsgutschriftszeile;Verkaufsgutschriftszeile;CARLO2;T1.[Buchungsdatum] >= '{1}';;;
+{0}$Verkaufskopf;Verkaufskopf;CARLO2;;;;
+{0}$Verkaufsrechnungskopf;Verkaufsrechnungskopf;CARLO2;T1.[Buchungsdatum] >= '{1}';;timestamp;
+{0}$Verkaufsrechnungszeile;Verkaufsrechnungszeile;CARLO2;T1.[Buchungsdatum] >= '{2}';;timestamp;
+{0}$Verkaufszeile;Verkaufszeile;CARLO2;;;;
+{0}$Werkstattkopf;Werkstattkopf;CARLO2;;;;
+{0}$Werkstattposten;Werkstattposten;CARLO2;T1.[Buchungsdatum] >= '{2}';;timestamp;
+{0}$Werkstattzeile;Werkstattzeile;CARLO2;;;;
+{0}$Wertposten;Wertposten;CARLO2;T1.[Buchungsdatum] >= '{1}';;timestamp;

+ 54 - 68
database/db_compare.py

@@ -1,11 +1,12 @@
 import codecs
-from pathlib import Path
+import sys
 
 import pandas as pd
 from pyodbc import ProgrammingError
 
-from database.db_create import get_import_config
-from database.model import DatabaseInspect, DbCreateConfig
+sys.path.insert(0, "C:\\Projekte\\tools")
+from database.db_create import get_table_config  # noqa:E402
+from database.model import DbCreateConfig, DestTable, SourceTable2  # noqa:E402
 
 
 def decode_ts(ts_binary):
@@ -14,55 +15,42 @@ def decode_ts(ts_binary):
 
 def compare(config_file: str = "database/CARLO.json"):
     cfg = DbCreateConfig.load_config(config_file)
-    base_dir = str(Path(config_file).parent.parent.resolve())
-    config = get_import_config(f"{base_dir}/config/{cfg.csv_file}", cfg.dest_dsn.database)
+    table_config = get_table_config(cfg)
 
-    source_db = DatabaseInspect(cfg.source_dsn, source=True)
-    source_tables = source_db.tables_list()
-
-    dest_db = DatabaseInspect(cfg.dest_dsn)
-    dest_tables = dest_db.tables_list()
-
-    for _, current_table in config.iterrows():
+    for dest_table in table_config:
         dest_row_count = {}
         dest_timestamp = {}
-        if current_table["dest"] in dest_tables:
-            full_table_name = f'[{current_table["dest_db"]}].[{cfg.dest_dsn.schema}].[{current_table["dest"]}]'
-            query_count_dest = f"SELECT [Client_DB], COUNT(*) as [Rows] FROM {full_table_name} GROUP BY [Client_DB]"
-            q = dest_db.cursor.execute(query_count_dest)
-            dest_row_count = dict([(col[0], col[1]) for col in q.fetchall()])
-
-            query_timestamp_dest = (
-                f"SELECT [Client_DB], max(timestamp) as [TS] FROM {full_table_name} GROUP BY [Client_DB]"
-            )
-            q = dest_db.cursor.execute(query_timestamp_dest)
-            dest_timestamp = dict([(col[0], decode_ts(col[1])) for col in q.fetchall()])
+        if dest_table.dest not in cfg.dest_inspect.tables_list:
+            print(f"Ziel-Tabelle '{dest_table.dest}' existiert nicht!")
+            continue
+
+        query_count_dest = (
+            f"SELECT [Client_DB], COUNT(*) as [Rows] FROM {dest_table.full_table_name} GROUP BY [Client_DB]"
+        )
+        q = cfg.dest_inspect.cursor.execute(query_count_dest)
+        dest_row_count = dict([(col[0], col[1]) for col in q.fetchall()])
+
+        query_timestamp_dest = (
+            f"SELECT [Client_DB], max(timestamp) as [TS] FROM {dest_table.full_table_name} GROUP BY [Client_DB]"
+        )
+        q = cfg.dest_inspect.cursor.execute(query_timestamp_dest)
+        dest_timestamp = dict([(col[0], decode_ts(col[1])) for col in q.fetchall()])
 
         source_row_count = {}
         source_row_count_ts = {}
 
-        for client_db, prefix in cfg.clients.items():
-            source_table = current_table["source"].format(prefix)
-            source_table2 = source_table.split(".")[-1][1:-1]
-
-            if source_table in source_tables or source_table2 in source_tables:
-                if not pd.isnull(current_table["query"]):
-                    select_query = current_table["query"].format(prefix, cfg.filter[0], cfg.filter[1])
-                elif "." in source_table or cfg.source_dsn.schema == "":
-                    if source_table[0] != "[":
-                        source_table = f"[{source_table}]"
-                    select_query = f"SELECT T1.* FROM {source_table} T1 "
-                else:
-                    select_query = f"SELECT T1.* FROM [{cfg.source_dsn.schema}].[{source_table}] T1 "
+        for source_table in dest_table.source_tables:
+            source_table2 = cfg.source_inspect.convert_table(source_table.table_name)
+            client_db = source_table.client_db
 
-                if not pd.isnull(current_table["filter"]):
-                    select_query += " WHERE " + current_table["filter"].format("", cfg.filter[0], cfg.filter[1])
-                elif "WHERE" not in select_query:
-                    select_query += " WHERE 1 = 1"
-                query_count_source = select_query.replace("T1.*", "COUNT(*) as [Rows]")
+            if (
+                source_table.table_name in cfg.source_inspect.tables_list
+                or source_table2 in cfg.source_inspect.tables_list
+            ):
+                query_count_source = source_table.select_query.replace("T1.*", "COUNT(*) as [Rows]")
                 # print(query_count_source)
 
-                q = source_db.cursor.execute(query_count_source)
+                q = cfg.source_inspect.cursor.execute(query_count_source)
                 source_row_count[client_db] = q.fetchone()[0]
 
                 query_ts = query_count_source
@@ -73,31 +61,21 @@ def compare(config_file: str = "database/CARLO.json"):
                     query_ts += f" WHERE T1.[timestamp] <= convert(binary(8), '{ts}', 1)"
                 # print(query_ts)
                 try:
-                    q = source_db.cursor.execute(query_ts)
+                    q = cfg.source_inspect.cursor.execute(query_ts)
                     source_row_count_ts[client_db] = q.fetchone()[0]
                 except ProgrammingError:
                     pass
 
             if dest_row_count.get(client_db, 0) != source_row_count.get(client_db, 0):
-                print(f"Tabelle {current_table['dest']} mit Client {client_db} stimmt nicht ueberein.")
+                print(f"Tabelle {dest_table.dest} mit Client {client_db} stimmt nicht ueberein.")
                 print(f"  Quelle:          {source_row_count.get(client_db, 0):>8}")
                 print(f"  Quelle (bis ts): {source_row_count_ts.get(client_db, 0):>8}")
                 print(f"  dest:            {dest_row_count.get(client_db, 0):>8}")
-                compare_details(current_table, client_db, source_db, dest_db, query_count_source, full_table_name, cfg)
-
-
-def compare_details(
-    current_table: pd.Series,
-    client_db: str,
-    source_db: DatabaseInspect,
-    dest_db: DatabaseInspect,
-    query_count_source: str,
-    full_table_name: str,
-    cfg: DbCreateConfig,
-):
-    table_client = f'{current_table["dest"]}_{client_db}'
-    pkey = dest_db.get_pkey(current_table["dest"], current_table["dest_db"])
-    cols = pkey + ["timestamp"]
+                compare_details(source_table, dest_table, query_count_source, cfg)
+
+
+def compare_details(source_table: SourceTable2, dest_table: DestTable, query_count_source: str, cfg: DbCreateConfig):
+    cols = dest_table.primary_key + ["timestamp"]
     if "Client_DB" in cols:
         cols.remove("Client_DB")
     if "CLIENT_DB" in cols:
@@ -107,22 +85,23 @@ def compare_details(
     query_source = query_count_source.replace("COUNT(*) as [Rows]", query_cols)
     query_source += f" ORDER BY {query_cols}"
     query_dest = (
-        f"SELECT {query_cols} FROM {full_table_name} T1 WHERE T1.[Client_DB] = '{client_db}' ORDER BY {query_cols}"
+        f"SELECT {query_cols} FROM {dest_table.full_table_name} T1 "
+        f"WHERE T1.[Client_DB] = '{source_table.client_db}' ORDER BY {query_cols}"
     )
 
-    source_file = f"{cfg.stage_dir}\\source\\{table_client}.csv"
-    source_data = pd.read_sql(query_source, source_db.sqlalchemy_engine)
+    source_file = f"{cfg.stage_dir}\\source\\{source_table.table_client}.csv"
+    source_data = pd.read_sql(query_source, cfg.source_inspect.sqlalchemy_engine)
     source_data["timestamp"] = source_data["timestamp"].apply(decode_ts)
     source_data.to_csv(source_file, index=False)
 
-    dest_file = f"{cfg.stage_dir}\\dest\\{table_client}.csv"
-    dest_data = pd.read_sql(query_dest, dest_db.sqlalchemy_engine)
+    dest_file = f"{cfg.stage_dir}\\dest\\{source_table.table_client}.csv"
+    dest_data = pd.read_sql(query_dest, cfg.dest_inspect.sqlalchemy_engine)
     dest_data["timestamp"] = dest_data["timestamp"].apply(decode_ts)
     dest_data.to_csv(dest_file, index=False)
 
     cols_without_ts = cols[:-1]
 
-    only_in_source_file = f"{cfg.stage_dir}\\diff\\{table_client}_only_in_source.sql"
+    only_in_source_file = f"{cfg.stage_dir}\\diff\\{source_table.table_client}_only_in_source.sql"
     only_in_source = pd.merge(source_data, dest_data, how="left", on=cols_without_ts)
     only_in_source = only_in_source[pd.isna(only_in_source["timestamp_y"])]
     if only_in_source.shape[0] > 0:
@@ -132,16 +111,19 @@ def compare_details(
         with open(only_in_source_file, "w") as fwh:
             fwh.write(query)
 
-    only_in_dest_file = f"{cfg.stage_dir}\\diff\\{table_client}_only_in_dest.sql"
+    only_in_dest_file = f"{cfg.stage_dir}\\diff\\{source_table.table_client}_only_in_dest.sql"
     only_in_dest = pd.merge(dest_data, source_data, how="left", on=cols_without_ts)
     only_in_dest = only_in_dest[pd.isna(only_in_dest["timestamp_y"])]
     if only_in_dest.shape[0] > 0:
         ts_list = ", ".join(only_in_dest.to_dict(orient="list")["timestamp_x"])
-        query = f"SELECT T1.* FROM {full_table_name} T1 WHERE T1.[Client_DB] = '{client_db}' AND T1.[timestamp] IN ({ts_list})"
+        query = (
+            f"SELECT T1.* FROM {dest_table.full_table_name} T1 "
+            f"WHERE T1.[Client_DB] = '{source_table.client_db}' AND T1.[timestamp] IN ({ts_list})"
+        )
         with open(only_in_dest_file, "w") as fwh:
             fwh.write(query)
 
-    not_updated_file = f"{cfg.stage_dir}\\diff\\{table_client}_not_updated.sql"
+    not_updated_file = f"{cfg.stage_dir}\\diff\\{source_table.table_client}_not_updated.sql"
     not_updated = pd.merge(source_data, dest_data, how="inner", on=cols_without_ts)
     not_updated = not_updated[not_updated["timestamp_x"] != not_updated["timestamp_y"]]
     if not_updated.shape[0] > 0:
@@ -150,3 +132,7 @@ def compare_details(
         query += f" AND T1.[timestamp] IN ({ts_list})"
         with open(not_updated_file, "w") as fwh:
             fwh.write(query)
+
+
+if __name__ == "__main__":
+    compare()

+ 4 - 6
database/db_create.py

@@ -21,6 +21,8 @@ def get_import_config(filename: str, db_name: str) -> pd.DataFrame:
 
 def get_table_config(cfg: DbCreateConfig) -> list[DestTable]:
     config = get_import_config(cfg.csv_file, cfg.dest_dsn.database)
+    SourceTable2.source_inspect = cfg.source_inspect
+    SourceTable2.cfg = cfg
     table_config = [DestTable(*row.values()) for row in config.to_dict(orient="records")]
     for dest_table in table_config:
         dest_table.cfg = cfg
@@ -37,10 +39,6 @@ def create(config_file: str = "database/CARLO.json"):
     cfg = DbCreateConfig.load_config(config_file)
     cfg.create_db_ini()
     print(json.dumps(cfg.source_inspect.get_prefix(), indent=2))
-    SourceTable2.source_inspect = cfg.source_inspect
-    SourceTable2.cfg = cfg
-
-    DestTable.cfg = cfg
 
     table_config = get_table_config(cfg)
 
@@ -68,7 +66,7 @@ def create(config_file: str = "database/CARLO.json"):
                         print(f"Quell-Tabelle '{source_table.table_name}' existiert nicht!")
                         continue
 
-                select_query = source_table.select_query.replace("%", "%%%%")  # batch-Problem
+                select_query = source_table.select_query_with_columns.replace("%", "%%%%")  # batch-Problem
                 f.write(source_table.info)
                 if select_query == "":
                     print(f"Ziel-Tabelle '{dest_table.dest}' Spalte 'Client_DB' fehlt!")
@@ -85,7 +83,7 @@ def create(config_file: str = "database/CARLO.json"):
 
             f.write(f'  call sql_query.bat "TRUNCATE TABLE {dest_table.temp_table_name}"\n\n')
             for source_table in dest_table.source_tables:
-                select_query = source_table.select_query
+                select_query = source_table.select_query_with_columns
                 convert_timestamp = "T1.[timestamp] > convert(binary(8), '%TS%', 1)"
                 if "WHERE" in select_query:
                     select_query = select_query.replace("WHERE", f"WHERE {convert_timestamp} AND")

+ 29 - 19
database/model.py

@@ -322,17 +322,18 @@ class SourceTable2(SourceTable):
     def table_name(self) -> str:
         return self.source.format(self.prefix)
 
+    @cached_property
+    def source_columns(self) -> set[str]:
+        return set(self.source_inspect.get_columns(self.table_name))
+
     @cached_property
     def select_query(self):
         f = io.StringIO()
-        source_columns = set(self.source_inspect.get_columns(self.table_name))
-
-        intersect = source_columns.intersection(self.dest_table.columns_list)
         # print("Auf beiden Seiten: " + ";".join(intersect))
-        diff1 = source_columns.difference(self.dest_table.columns_list)
+        diff1 = self.source_columns.difference(self.dest_table.columns_list)
         if len(diff1) > 0:
             f.write("rem Nur in Quelle: " + ";".join(diff1) + "\n")
-        diff2 = set(self.dest_table.columns_list).difference(source_columns)
+        diff2 = set(self.dest_table.columns_list).difference(self.source_columns)
         if "Client_DB" not in diff2:
             f.write("echo Spalte 'Client_DB' fehlt!\n")
             return
@@ -353,23 +354,32 @@ class SourceTable2(SourceTable):
             select_query += " WHERE " + self.dest_table.filter_.format("", self.cfg.filter[0], self.cfg.filter[1])
         elif "WHERE" not in select_query:
             select_query += " WHERE 1 = 1"
-        # select_columns = "T1.[" + "], T1.[".join(intersect) + "],"
-        select_columns = ""
+
+        if "timestamp" not in self.source_columns:
+            print(self.dest_table.dest + " hat kein timestamp-Feld")
+        self.info = f.getvalue()
+        return select_query
+
+    @property
+    def select_query_with_columns(self) -> str:
+        res = self.select_query.replace("T1.*", self.select_columns)
+        if "timestamp" in self.source_columns:
+            res += " ORDER BY T1.[timestamp] "
+        return res
+
+    @property
+    def select_columns(self):
+        intersect = self.source_columns.intersection(self.dest_table.columns_list)
+        res = ""
         for col, is_char_type in zip(self.dest_table.columns_list, self.dest_table.column_types):
             if col in intersect:
                 if False and is_char_type:  # vorerst deaktiviert
-                    select_columns += f"dbo.cln(T1.[{col}]), "
+                    res += f"dbo.cln(T1.[{col}]), "
                 else:
-                    select_columns += f"T1.[{col}], "
+                    res += f"T1.[{col}], "
             elif col == "Client_DB":
-                select_columns += f"'{self.client_db}' as [Client_DB], "
+                res += f"'{self.client_db}' as [Client_DB], "
             else:
-                select_columns += "'' as [" + col + "], "
-
-        select_query = select_query.replace("T1.*", select_columns[:-2])
-        if "timestamp" in source_columns:
-            select_query += " ORDER BY T1.[timestamp] "
-        else:
-            print(self.dest_table.dest + " hat kein timestamp-Feld")
-        self.info = f.getvalue()
-        return select_query
+                res += "'' as [" + col + "], "
+        res = res[:-2]
+        return res