Выполнение_запроса_по_списку_БД
Настройка Python
В Python версии 3.7 и выше дополнительно необходимо установить pip install oracledb, pip install pandas, pip install requests, pip install openpyxl.
В Python версии 3.7 и выше cx_oracle не работает, нужен oracledb, при необходимости запуска на Python 3.0-3.7 заменить oracledb на cx_oracle
Python 3.7+ Параллельный запуск запроса или скрипта
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | import oracledb import threading from pandas import DataFrame import datetime import os import requests ########################################################################################## ### Список переменных, которые нужно изменить ### ########################################################################################## # Директория с клиентом Oracle oracledb.init_oracle_client(lib_dir=r"D:\instantclient_21_11") # Запрос или скрипт в txt файле, который нужно выполнять QUERY = open('qry/hidden_par_val.sql').read() # Режим выполнения: # 0 - выполнение запроса, 1 - выполнение скрипта execution_mode = 0 # Режим получения списка баз данных: # 0 - получение из файла, 1 - получение всех актуальных БД через HTTP-запрос к CDMS db_list_mode = 1 # Файл с списком БД для db_list_mode=0 BASELIST = open('bases/baselist.txt').readlines() # Токен для подключения к CDMS для db_list_mode=1 api_token = "cdmt@pve!" # Логин и пароль для подключения к БД Oracle or_usr = 'sys' or_pas = '' ########################################################################################## ### Далее ничего менять не нужно. Результат выполнения будет сохранён в excel файл ### ### в директорию output с именем - script_res или query_res и текущей датой ### ########################################################################################## # Функция для получения списка баз данных через HTTP-запрос к CDMS def get_oracle_bases_from_http(): db_url = "https://cdms.colvir.ru/api/getactualdb" headers = { "Content-Type": "application/json", "Accept": "application/json" } payload = { "api_token": api_token } try: print("Получаем список БД через API") response = requests.get( db_url, headers=headers, json=payload ) response.raise_for_status() data = response.json() print(f"HTTP Status Code: {response.status_code}") return [item['con_str'] for item in data] except requests.exceptions.RequestException as e: print(f"Ошибка при выполнении HTTP-запроса: {e}") return [] except ValueError as ve: print(f"Ошибка декодирования JSON: {ve}") return [] except KeyError as ke: print(f"Ошибка в структуре ответа: отсутствует ключ {ke}") return [] #Очистка экрана def cls(): os.system('cls' if os.name=='nt' else 'clear') #выполнение запроса или скрипта def exec_qry(idx, con_str): print(f"Поток {idx}: обработка {con_str}".ljust(80), end='\r') try: exc = ' ' val = ' ' # Условие для установки режима SYSDBA только для пользователя 'sys' if or_usr.lower() == 'sys': con = oracledb.connect(user=or_usr, password=or_pas, dsn=con_str, mode=oracledb.SYSDBA) else: con = oracledb.connect(user=or_usr, password=or_pas, dsn=con_str) cur = con.cursor() cur.execute(QUERY) # Выполнение запроса if execution_mode == 0: for result in cur: val = ';'.join(map(str, result)) # Выполнение скрипта else: val = 'Ok' cur.close() con.close() except oracledb.DatabaseError as e: error_obj, = e.args exc = error_obj.message finally: base_list.append(con_str) value_list.append(val) except_list.append(exc) return #Основной код cls() # Получение списка баз данных BASES = BASELIST if db_list_mode == 0 else get_oracle_bases_from_http() if len(BASES) == 0: print("Нет БД для обработки. Выходим") exit() else: print(f"Список БД получен, количество БД в списке: {len(BASES)}") print("Запускаем многопоточную обработку") base_list, value_list, except_list = [], [], [] # Запуск потоков для каждой базы данных threads = list() for BASE in BASES: idx = len(threads) x = threading.Thread(target=exec_qry, args=(idx, BASE.strip(),)) threads.append(x) x.start() print(f"Все потоки запущены. Количество запущенных потоков:{idx+1}") for index, thread in enumerate(threads): print(f"Основной поток: ожидаем ответ потока #{index} для БД {BASES[index].strip()}".ljust(80), end='\r') thread.join() print() print(f"Закончили, формируем excel файл ") # Генерация имени выходного файла и создание директории, если её нет os.makedirs('output', exist_ok=True) output_prefix = 'script_res' if execution_mode == 1 else 'query_res' date_str = datetime.datetime.now().strftime('%Y%m%d') output_filename = f"{output_prefix}-{date_str}-1.xlsx" # Проверка на существование файла counter = 1 while os.path.exists(f"output/{output_filename}"): counter += 1 output_filename = f"{output_prefix}-{date_str}-{counter}.xlsx" df = DataFrame({'База': base_list, 'Результат': value_list, 'Исключение': except_list}) df.to_excel(f'output/{output_filename}', sheet_name='sheet1', index=False) print(f"Excel файл сформирован: output/{output_filename}") |