iqd_convert.py 6.1 KB

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