新增修改
This commit is contained in:
241
final/scripts/inspect_dm_tables.py
Normal file
241
final/scripts/inspect_dm_tables.py
Normal file
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
在达梦数据库机器上运行,查看各表结构,用于编写 config 中的 db.query
|
||||
用法: python scripts/inspect_dm_tables.py
|
||||
|
||||
密码获取顺序:环境变量 DM_PASS > 下方 LOCAL_PASSWORD
|
||||
若使用 LOCAL_PASSWORD,切勿提交到 git!可执行:git update-index --assume-unchanged scripts/inspect_dm_tables.py
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 可选:在此直接填写密码(仅限本机调试,切勿提交到版本库!)
|
||||
LOCAL_PASSWORD = None # 例如: "你的密码"
|
||||
|
||||
# 支持从项目根或 scripts 目录运行
|
||||
_script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
_project_root = os.path.dirname(_script_dir)
|
||||
XLSX_PATH = os.path.join(_project_root, "1125暂时属性需求(1).xlsx")
|
||||
if _project_root not in sys.path:
|
||||
sys.path.insert(0, _project_root)
|
||||
|
||||
try:
|
||||
import dmPython
|
||||
except ImportError:
|
||||
print("请先安装: pip install dmPython")
|
||||
sys.exit(1)
|
||||
|
||||
CONFIG = {
|
||||
"user": os.getenv("DM_USER", "SYSDBA"),
|
||||
"password": os.getenv("DM_PASS") or LOCAL_PASSWORD,
|
||||
"server": os.getenv("DM_HOST", "127.0.0.1"),
|
||||
"port": int(os.getenv("DM_PORT", "9080")),
|
||||
"schema": "SYSDBA",
|
||||
}
|
||||
|
||||
TABLES = [
|
||||
"OBJECTIVE_INSTANCE",
|
||||
"METRIC_VALUE_INSTANCE",
|
||||
"METRIC_PROFILE",
|
||||
"ROLE_PROFILE",
|
||||
"TASK_PROFILE",
|
||||
"RELATION_INSTANCE",
|
||||
"RES_FORMAL_ANALYSIS",
|
||||
]
|
||||
|
||||
|
||||
def _load_required_attrs(xlsx_path: str) -> list:
|
||||
"""从 1125暂时属性需求(1).xlsx 解析需求属性列表(一条=一个属性)"""
|
||||
if not os.path.exists(xlsx_path):
|
||||
print(f" (未找到 {xlsx_path},使用内置属性列表)")
|
||||
return _DEFAULT_REQ_ATTRS
|
||||
try:
|
||||
import pandas as pd
|
||||
df = pd.read_excel(xlsx_path, header=None)
|
||||
attrs = []
|
||||
for _, row in df.iterrows():
|
||||
v0 = row[0]
|
||||
v2 = str(row[2]) if len(row) > 2 and pd.notna(row[2]) else ""
|
||||
if pd.notna(v0) and str(v0).strip() and str(v0) != "属性代码名称":
|
||||
attrs.append(str(v0).strip())
|
||||
if ":" in v2:
|
||||
sub = v2.split(":")[0].strip()
|
||||
if sub and sub not in attrs:
|
||||
attrs.append(sub)
|
||||
return attrs if attrs else _DEFAULT_REQ_ATTRS
|
||||
except Exception as e:
|
||||
print(f" (解析 xlsx 失败: {e},使用内置属性列表)")
|
||||
return _DEFAULT_REQ_ATTRS
|
||||
|
||||
|
||||
# xlsx 解析失败时的兜底属性列表(来自 1125暂时属性需求)
|
||||
_DEFAULT_REQ_ATTRS = [
|
||||
"f_IC", "f_IA", "f_CS", "f_IT", "f_DP", "f_CPS", "f_CC",
|
||||
"position", "effective_radius",
|
||||
"response_time", "cycle_time", "data_age", "time_window",
|
||||
"core_performance", "survivability", "mtbf",
|
||||
"protocol_list", "format_list", "interface_list",
|
||||
"security_level", "org_unit", "nation", "history_success",
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
if not CONFIG["password"]:
|
||||
print("请设置环境变量 DM_PASS 或在脚本中填写 LOCAL_PASSWORD")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
conn = dmPython.connect(
|
||||
user=CONFIG["user"],
|
||||
password=CONFIG["password"],
|
||||
server=CONFIG["server"],
|
||||
port=CONFIG["port"],
|
||||
schema=CONFIG["schema"],
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"连接失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
cursor = conn.cursor()
|
||||
print("=" * 60)
|
||||
print("达梦表结构(用于编写 config/db.query)")
|
||||
print("=" * 60)
|
||||
|
||||
for table in TABLES:
|
||||
try:
|
||||
cursor.execute(f'SELECT * FROM "{CONFIG["schema"]}"."{table}" WHERE 1=0')
|
||||
cols = [d[0] for d in cursor.description]
|
||||
print(f"\n【{table}】 列: {cols}")
|
||||
except Exception as e:
|
||||
print(f"\n【{table}】 查询失败: {e}")
|
||||
|
||||
# 专门查询 METRIC_VALUE_INSTANCE 的字段详情(含完整属性)
|
||||
mvi_table = "METRIC_VALUE_INSTANCE"
|
||||
print("\n" + "=" * 80)
|
||||
print(f"【{mvi_table}】 字段详情(完整属性)")
|
||||
print("=" * 80)
|
||||
try:
|
||||
# 查询 DBA_TAB_COLUMNS 全部常用属性(达梦兼容)
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT COLUMN_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE,
|
||||
NULLABLE, DATA_DEFAULT, COLUMN_ID
|
||||
FROM DBA_TAB_COLUMNS
|
||||
WHERE OWNER = ? AND TABLE_NAME = ?
|
||||
ORDER BY COLUMN_ID
|
||||
""",
|
||||
(CONFIG["schema"], mvi_table),
|
||||
)
|
||||
mvi_cols = cursor.fetchall()
|
||||
# 表头
|
||||
fmt = " {:<18} {:<16} {:<10} {:<10} {:<8} {:<10} {:<20}"
|
||||
print(fmt.format("列名", "数据类型", "长度", "精度", "标度", "可空", "默认值"))
|
||||
print(" " + "-" * 90)
|
||||
for row in mvi_cols:
|
||||
col_name, data_type, data_length, data_precision, data_scale, nullable, data_default, col_id = row
|
||||
# 类型显示:数值型用 类型(精度,标度),字符型用 类型(长度)
|
||||
if data_precision is not None:
|
||||
type_str = f"{data_type}({data_precision},{data_scale or 0})"
|
||||
elif data_length and data_type.upper() in ("VARCHAR", "CHAR", "VARCHAR2"):
|
||||
type_str = f"{data_type}({data_length})"
|
||||
elif data_length:
|
||||
type_str = f"{data_type}({data_length})"
|
||||
else:
|
||||
type_str = data_type or ""
|
||||
len_val = str(data_length) if data_length is not None else "-"
|
||||
prec_val = str(data_precision) if data_precision is not None else "-"
|
||||
scale_val = str(data_scale) if data_scale is not None else "-"
|
||||
null_str = "NULL" if nullable == "Y" else "NOT NULL"
|
||||
default_str = (str(data_default).strip() if data_default else "-")[:18]
|
||||
print(fmt.format(col_name, type_str, len_val, prec_val, scale_val, null_str, default_str))
|
||||
|
||||
# 查询样本数据(若有)
|
||||
cursor.execute(f'SELECT * FROM "{CONFIG["schema"]}"."{mvi_table}" WHERE ROWNUM <= 3')
|
||||
sample_rows = cursor.fetchall()
|
||||
if sample_rows:
|
||||
col_names = [d[0] for d in cursor.description]
|
||||
print(f"\n 样本数据 (最多 3 行):")
|
||||
for i, row in enumerate(sample_rows, 1):
|
||||
print(f" 行{i}: {dict(zip(col_names, row))}")
|
||||
else:
|
||||
print("\n (表无数据)")
|
||||
except Exception as e:
|
||||
print(f" 查询失败: {e}")
|
||||
|
||||
# 按 1125暂时属性需求(1).xlsx 查询 METRIC_VALUE_INSTANCE(一条=一个属性)
|
||||
print("\n" + "=" * 80)
|
||||
print("【METRIC_VALUE_INSTANCE】按需求属性查询(xlsx 中一条 = 一个 METRIC_ID)")
|
||||
print("=" * 80)
|
||||
try:
|
||||
# 1. 从 xlsx 解析需求属性列表
|
||||
req_attrs = _load_required_attrs(XLSX_PATH)
|
||||
print(f"\n xlsx 需求属性 ({len(req_attrs)} 个): {req_attrs}")
|
||||
|
||||
# 2. 查询库中实际存在的 METRIC_ID(distinct)
|
||||
cursor.execute(
|
||||
f'SELECT DISTINCT METRIC_ID FROM "{CONFIG["schema"]}"."METRIC_VALUE_INSTANCE" ORDER BY METRIC_ID'
|
||||
)
|
||||
db_metric_ids = [r[0] for r in cursor.fetchall()]
|
||||
print(f"\n 库中已有 METRIC_ID ({len(db_metric_ids)} 个): {db_metric_ids or '(无数据)'}")
|
||||
|
||||
# 3. METRIC_PROFILE 对照(METRIC_ID -> 中文名)
|
||||
cursor.execute(
|
||||
f'SELECT METRIC_ID, METRIC_NAME FROM "{CONFIG["schema"]}"."METRIC_PROFILE"'
|
||||
)
|
||||
profile_map = dict(cursor.fetchall())
|
||||
if profile_map:
|
||||
print("\n METRIC_PROFILE 对照:")
|
||||
for mid, mname in sorted(profile_map.items()):
|
||||
print(f" {mid} -> {mname}")
|
||||
|
||||
# 4. 交集:需求属性中在库里有的
|
||||
in_both = [a for a in req_attrs if a in db_metric_ids]
|
||||
# 需求有但库无
|
||||
missing = [a for a in req_attrs if a not in db_metric_ids]
|
||||
# 库有但需求未列
|
||||
extra = [m for m in db_metric_ids if m not in req_attrs]
|
||||
|
||||
print(f"\n 需求与库交集 (可查): {in_both or '无'}")
|
||||
print(f" 需求有但库无: {missing or '无'}")
|
||||
print(f" 库有但需求未列: {extra or '无'}")
|
||||
|
||||
# 5. 按属性查询示例 SQL
|
||||
print("\n --- 按属性查询示例 SQL ---")
|
||||
for attr in (in_both or req_attrs)[:5]: # 最多展示 5 个
|
||||
sql = f'SELECT * FROM "{CONFIG["schema"]}"."METRIC_VALUE_INSTANCE" WHERE METRIC_ID = \'{attr}\''
|
||||
print(f" -- {attr}: {sql}")
|
||||
if len(in_both or req_attrs) > 5:
|
||||
print(f" ... 其余属性同理,将 METRIC_ID = 'xxx' 替换即可")
|
||||
except Exception as e:
|
||||
print(f" 查询失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
|
||||
FROM DBA_TAB_COLUMNS
|
||||
WHERE OWNER = ?
|
||||
ORDER BY TABLE_NAME, COLUMN_ID
|
||||
""",
|
||||
(CONFIG["schema"],),
|
||||
)
|
||||
rows = cursor.fetchall()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("所有列详情 (TABLE_NAME | COLUMN_NAME | DATA_TYPE)")
|
||||
print("=" * 60)
|
||||
cur_table = None
|
||||
for table, col, dtype in rows:
|
||||
if table != cur_table:
|
||||
cur_table = table
|
||||
print(f"\n--- {table} ---")
|
||||
print(f" {col}: {dtype}")
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
print("\n完成。请根据上述结构在 config 中编写 db.query。")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user