Выполнение_запроса_по_списку_БД

Настройка 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}")