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