mtc/load_mpoint_name.py

102 lines
3.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""一次性脚本:从「翁福 数据远传变量.xlsx」解析点位建立并灌入 mpoint_name 映射表。
- 位号(mpoint_id) 由 mqttc.code_from_name 切出,与线上入库逻辑同一套规则,杜绝漂移。
- point_name = 全名去掉尾部位号full_name 保留 Excel 原文便于溯源。
- 幂等ON CONFLICT(mpoint_id) DO UPDATE可反复执行。
用法:
python load_mpoint_name.py [Excel路径] [数据库URL]
默认读取桌面上的《数据远传变量.xlsx》写入 conf.DATABASE_URL 指向的库;
可传第二个参数指定目标库(如线上 10.0.11.52)。
"""
import os
import sys
import openpyxl
from sqlalchemy import create_engine, text
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, CUR_DIR)
import conf
from mqttc import code_from_name
DEFAULT_XLSX = r"C:\Users\11825\Desktop\01-文档资料\资料\翁福采集\数据远传变量.xlsx"
TABLE = "wengfu_mpoint_name"
DDL = f"""
CREATE TABLE IF NOT EXISTS {TABLE} (
mpoint_id varchar PRIMARY KEY,
point_name text,
full_name text,
dtype varchar
)
"""
UPSERT = f"""
INSERT INTO {TABLE} (mpoint_id, point_name, full_name, dtype)
VALUES (:mpoint_id, :point_name, :full_name, :dtype)
ON CONFLICT (mpoint_id) DO UPDATE
SET point_name = EXCLUDED.point_name,
full_name = EXCLUDED.full_name,
dtype = EXCLUDED.dtype
"""
def read_items(path):
"""Excel 为左右两张并排的表:列 A/B 和 D/E 各是 (变量名, 类型)。"""
wb = openpyxl.load_workbook(path, read_only=True, data_only=True)
ws = wb["Sheet1"]
items = []
for r in list(ws.iter_rows(values_only=True))[1:]: # 跳过表头
r = list(r)
if r and r[0]:
items.append((str(r[0]).strip(), str(r[1]).strip() if len(r) > 1 and r[1] else ''))
if len(r) > 3 and r[3]:
items.append((str(r[3]).strip(), str(r[4]).strip() if len(r) > 4 and r[4] else ''))
return items
def split_row(full_name, dtype):
code = code_from_name(full_name)
point = full_name[:len(full_name) - len(code)].rstrip('_') if code and full_name.endswith(code) else full_name
return {
"mpoint_id": code,
"point_name": point or None,
"full_name": full_name,
"dtype": dtype or None,
}
def main():
path = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_XLSX
db_url = sys.argv[2] if len(sys.argv) > 2 else conf.DATABASE_URL
items = read_items(path)
rows = [split_row(name, typ) for name, typ in items]
# 位号唯一性自检
seen = {}
collisions = []
for row in rows:
mid = row["mpoint_id"]
if mid in seen and seen[mid] != row["full_name"]:
collisions.append((mid, seen[mid], row["full_name"]))
seen[mid] = row["full_name"]
if collisions:
print(f"!! 位号冲突 {len(collisions)} 处(不同全名切出同一位号),请先核对:")
for mid, a, b in collisions[:20]:
print(f" {mid}: {a} <> {b}")
sys.exit(1)
engine = create_engine(db_url, connect_args={'connect_timeout': 10})
with engine.begin() as conn:
conn.execute(text(DDL))
for row in rows:
conn.execute(text(UPSERT), row)
total = conn.execute(text(f"SELECT COUNT(*) FROM {TABLE}")).scalar()
print(f"目标库写入完成:读取 {len(items)} 条,去重后位号 {len(seen)} 个,{TABLE} 表内现有 {total} 行。")
if __name__ == '__main__':
main()