iqd_convert.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. from pathlib import Path
  2. import re
  3. import plac
  4. from collections import defaultdict
  5. class IqdConverter:
  6. commands = ["convert", "run_folder"]
  7. target_schema_by_type = {"csv": "staging", "ims": "ims"}
  8. output_dir = "C:\\GlobalCube\\System\\OPTIMA\\SQL\\schema\\OPTIMA\\views_imr"
  9. def convert(self, iqd_file, target_type="csv", force=True):
  10. if not Path(iqd_file).exists():
  11. print(f"File {iqd_file} does not exist!")
  12. return
  13. output_file = iqd_file[:-4] + ".sql"
  14. if (
  15. not force
  16. and Path(output_file).exists()
  17. and Path(output_file).stat().st_mtime >= Path(iqd_file).stat().st_mtime
  18. ):
  19. # no update needed
  20. return
  21. query = self.get_query_from_iqdfile(iqd_file)
  22. query = self.cleanup_query(query)
  23. with open(output_file, "w", encoding="latin-1") as fwh:
  24. fwh.write(query)
  25. create_view, view_file = self.get_create_view(iqd_file, target_type, query)
  26. with open(view_file, "w", encoding="latin-1") as fwh:
  27. fwh.write(create_view)
  28. create_view_90 = self.get_create_view_90(query)
  29. with open(view_file.replace("_imr.sql", "_90.sql"), "w", encoding="latin-1") as fwh:
  30. fwh.write(create_view_90)
  31. def get_create_view(self, iqd_file, target_type, query):
  32. table = Path(iqd_file).stem.lower()
  33. if target_type == "csv":
  34. table += "_imr"
  35. schema = self.target_schema_by_type[target_type]
  36. create_view = (
  37. "SET QUOTED_IDENTIFIER ON \nGO\nSET ANSI_NULLS ON \nGO\n"
  38. + f"CREATE VIEW {schema}.{table} AS\n\n{query}\n"
  39. + "GO\nSET QUOTED_IDENTIFIER OFF \nGO\nSET ANSI_NULLS OFF \nGO\n\nGO"
  40. )
  41. view_file = f"{self.output_dir}\\{schema}.{table}.sql"
  42. return create_view, view_file
  43. def get_create_view_90(self, query):
  44. match = re.findall(r"(\"([^\"]+)\"\.)?\"([^\"]+)\"\ (T\d+)", query)
  45. tables = dict([(t[3], t[2]) for t in match])
  46. query_from_ori = re.search(r"from ([^\s].*)where", query, re.DOTALL).group(1)
  47. query_from = query_from_ori.replace("(", "").replace(")", "")
  48. query_where_ori = re.search(r"where (.*)", query, re.DOTALL).group(1)
  49. query_where = re.sub(r"-- order by.*", "", query_where_ori)
  50. # query_where = query_where_ori.replace("(", "").replace(")", "")
  51. match = re.findall(r"T\d+\.\"[^\"]+\"", query)
  52. columns = list(sorted(list(set(match))))
  53. cols_alias = []
  54. for col in columns:
  55. t_name, col_name = re.search(r"(T\d+)\.\"([^\"]+)\"", col).group(1, 2)
  56. if True or col_name in cols_alias:
  57. table_name = tables.get(t_name, t_name)
  58. cols_alias.append(f"{col_name}__{table_name}")
  59. else:
  60. cols_alias.append(col_name)
  61. columns_combined = [f'{c} AS "{a}"' for c, a in zip(columns, cols_alias)]
  62. return "SELECT " + ", ".join(columns_combined) + " FROM " + query_from + " WHERE " + query_where
  63. def get_query_from_iqdfile(self, iqd_file):
  64. if iqd_file[-4:].lower() == ".imr":
  65. iqd_file = iqd_file[:-4] + ".iqd"
  66. iqd = open(iqd_file, "r", encoding="latin-1").read()
  67. res = re.findall(r"BEGIN SQL\n(.*)\n\nEND SQL", iqd, re.MULTILINE | re.DOTALL)
  68. query = ""
  69. if len(res) > 0:
  70. query = res[0]
  71. columns = re.findall(r"COLUMN,\d+,(.*)", iqd)
  72. col_keys = [f"c{i}" for i in range(len(columns), 0, -1)]
  73. col_names = [f'"{c}"' for c in reversed(columns)]
  74. used_cols = defaultdict(int)
  75. for col_key, col_name in zip(col_keys, col_names):
  76. used_cols[col_name] += 1
  77. if used_cols[col_name] > 1:
  78. col_name = col_name[:-1] + "_" + str(used_cols[col_name]) + '"'
  79. query = re.sub(col_key + r"([^\d])", col_name + r"\1", query)
  80. columns2 = re.findall(r'\s+(c\d+) as (".*")', query)
  81. used_cols = defaultdict(int)
  82. for col in columns2:
  83. used_cols[col[1]] += 1
  84. col_name = col[1]
  85. if used_cols[col[1]] > 1:
  86. col_name = col[1][:-1] + "_" + str(used_cols[col[1]]) + '"'
  87. query = re.sub(col[0] + r" as " + col[1], col_name, query)
  88. query = re.sub(col[0] + r"([^\d])", col_name + r"\1", query)
  89. return query
  90. def cleanup_query(self, query):
  91. query = re.sub(r" from (\d+) for (\d+)\)", r", \1, \2)", query)
  92. query = query.replace(" || ", " + ")
  93. query = query.replace("truncate(", "rtrim(")
  94. query = query.replace("char_length(", "len(")
  95. query = query.replace("database(", "db_name(")
  96. query = query.replace("ascii(", "convert(varchar(50), ")
  97. query = query.replace("extract(DAY FROM ", "day(")
  98. query = query.replace("extract(MONTH FROM ", "month(")
  99. query = query.replace("extract(YEAR FROM ", "year(")
  100. query = query.replace("od_year(", "year(")
  101. query = query.replace("od_month(", "month(")
  102. query = query.replace("lastday(", "eomonth(")
  103. query = query.replace("cdatetime(", "convert(datetime, ")
  104. query = query.replace("cast_float(", "convert(float, ")
  105. query = query.replace("sy_right(", "right(")
  106. query = query.replace("od_left(", "left(")
  107. query = query.replace("od_right(", "right(")
  108. query = query.replace("length(", "len(")
  109. query = query.replace("{hour}", "hour")
  110. query = query.replace("{minute}", "minute")
  111. query = query.replace("{weekday}", "weekday")
  112. query = query.replace("dayofweek(", "datepart(weekday, ")
  113. query = query.replace("cast_numberToString(cast_integer(", "((")
  114. query = query.replace("@CURRENT_DATE", "getdate()")
  115. query = query.replace("now()", "getdate()")
  116. query = query.replace("INTERVAL '001 10:00:00.000'", "1")
  117. query = query.replace("INTERVAL '001 00:00:00.000'", "1")
  118. query = query.replace("cdate(", "(")
  119. query = re.sub(r"intdiv\(([^\)]+)\,1\)", r"\1", query)
  120. query = re.sub(r"XCOUNT\(([^\)]+) for ", r"COUNT(\1) OVER (partition by ", query)
  121. query = re.sub(r"XSUM\(([^\)]+) for ", r"SUM(\1) OVER (partition by ", query)
  122. query = re.sub(r"RSUM\(([^\)]+) for ", r"SUM(\1) OVER (partition by ", query)
  123. query = re.sub(r"XMIN\(([^\)]+) for ", r"MIN(\1) OVER (partition by ", query)
  124. query = re.sub(r"XMAX\(([^\)]+) for ", r"MAX(\1) OVER (partition by ", query)
  125. query = re.sub(r"XRANK\(([^\)]+) for ([^\)]+)", r"RANK() OVER (partition by \2 order by \1", query)
  126. query = re.sub(r"QSS\.\"[^\"]+\\([^\\]+)\.ims\"", r'"ims"."\1"', query)
  127. query = re.sub(r"DATE '([\d-]+)'", r"convert(date, '\1')", query)
  128. query = re.sub(r"TIMESTAMP '([\d\s\-\:\.]+)'", r"convert(datetime, '\1')", query)
  129. query = re.sub(r"asciiz\(([^\,]*)\,\d+\)", r"convert(varchar(50), \1)", query)
  130. query = re.sub(r"asciiz\(([^\+]*)\)", r"convert(varchar(50), \1)", query)
  131. # query = re.sub(r'day\(([^\-\<\>\=]*) \- ([^\-\<\>\=]*)\)\) as', r'datediff(day, \2, \1)) as', query)
  132. # query = re.sub(r'day\(([^\-\<\>\=]*) \- ([^\-\<\>\=]*)\)\)\)', r'datediff(day, \2, \1)))', query)
  133. query = re.sub(r"day\(([^\-\,\']*) \- ", r"-1 * datediff(day, \1, ", query)
  134. query = re.sub(r"convert\(varchar\(50\)\, ([^,]+)\,\d+\)", r"convert(varchar(50), \1)", query)
  135. query = query.replace("cdate((convert(float, ", "convert(datetime, ((")
  136. query = re.sub(r"[^ ](order by .*)", r"\n-- \1", query)
  137. return query
  138. def run_folder(self, base_dir):
  139. files = sorted([(f.stat().st_mtime, f) for f in Path(base_dir).rglob("*.iqd")])
  140. for timestamp, iqd in files:
  141. self.convert(str(iqd))
  142. if __name__ == "__main__":
  143. # IqdConverter().convert('C:\\GlobalCube_LOCOSOFT\\System\\LOCOSOFT\\IQD\\Serv_Teile\\offene_Auftraege_Ums_ben_AW.iqd')
  144. iqdconv = IqdConverter()
  145. iqdconv.output_dir = "C:\\GlobalCube_LOCOSOFT\\System\\LOCOSOFT\\SQL\\schema\\LOCOSOFT\\views_imr"
  146. iqdconv.run_folder("C:\\GlobalCube_LOCOSOFT\\System\\LOCOSOFT\\IQD")
  147. # plac.Interpreter.call(IqdConverter)