iqd_convert.py 6.1 KB

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