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
```