Commit ae09c9

2025-12-07 11:35:16 feagor: -/-
/dev/null .. Python/Выполнение_запроса_по_списку_БД.md
@@ 0,0 1,142 @@
+ # Выполнение_запроса_по_списку_БД
+ ## Настройка 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+ Параллельный запуск запроса или скрипта
+ ```python
+ 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}")
+ ```
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9