在前后端开发联调前 的提交20260223
This commit is contained in:
154
scripts/ops/run_migration_c1.py
Normal file
154
scripts/ops/run_migration_c1.py
Normal file
@@ -0,0 +1,154 @@
|
||||
"""
|
||||
在 test_etl_feiqiu 上执行迁移脚本 C1:ODS/DWD 层会员表新增 birthday 列。
|
||||
执行后自动运行验证 SQL 确认列已添加。
|
||||
|
||||
用法:python scripts/ops/run_migration_c1.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 加载根 .env
|
||||
ROOT_DIR = Path(__file__).resolve().parents[2]
|
||||
load_dotenv(ROOT_DIR / ".env")
|
||||
|
||||
TEST_DB_DSN = os.environ.get("TEST_DB_DSN")
|
||||
if not TEST_DB_DSN:
|
||||
print("❌ 错误:TEST_DB_DSN 环境变量未定义,请检查根 .env 文件")
|
||||
sys.exit(1)
|
||||
|
||||
# 确认连接的是测试库
|
||||
if "test_etl_feiqiu" not in TEST_DB_DSN:
|
||||
print(f"❌ 安全检查失败:TEST_DB_DSN 未指向 test_etl_feiqiu\n 当前值: {TEST_DB_DSN}")
|
||||
sys.exit(1)
|
||||
|
||||
import psycopg2
|
||||
|
||||
MIGRATION_FILE = ROOT_DIR / "db" / "etl_feiqiu" / "migrations" / "2026-02-22__C1_dim_member_add_birthday.sql"
|
||||
|
||||
|
||||
def run_migration(conn):
|
||||
"""执行迁移脚本"""
|
||||
sql = MIGRATION_FILE.read_text(encoding="utf-8")
|
||||
|
||||
# 提取 BEGIN...COMMIT 之间的 DDL 语句(跳过注释中的回滚和验证部分)
|
||||
# 迁移脚本本身包含 BEGIN/COMMIT,psycopg2 默认 autocommit=False 会冲突
|
||||
# 所以用 autocommit 模式,让脚本自己管理事务
|
||||
conn.autocommit = True
|
||||
cur = conn.cursor()
|
||||
|
||||
# 逐条执行 DDL(跳过纯注释行和空行,提取有效 SQL)
|
||||
statements = []
|
||||
current = []
|
||||
in_block = False
|
||||
|
||||
for line in sql.splitlines():
|
||||
stripped = line.strip()
|
||||
|
||||
# 跳过回滚和验证部分(它们被注释掉了)
|
||||
if stripped.startswith("--"):
|
||||
# BEGIN 标记进入有效区域
|
||||
if "回滚" in stripped or "验证 SQL" in stripped:
|
||||
break
|
||||
continue
|
||||
|
||||
if not stripped:
|
||||
continue
|
||||
|
||||
# 跳过 BEGIN/COMMIT(我们用 autocommit)
|
||||
if stripped.upper() in ("BEGIN;", "COMMIT;"):
|
||||
continue
|
||||
|
||||
current.append(line)
|
||||
if stripped.endswith(";"):
|
||||
statements.append("\n".join(current))
|
||||
current = []
|
||||
|
||||
print(f"📄 迁移文件: {MIGRATION_FILE.name}")
|
||||
print(f"🔗 目标库: test_etl_feiqiu")
|
||||
print(f"📝 待执行语句: {len(statements)} 条\n")
|
||||
|
||||
for i, stmt in enumerate(statements, 1):
|
||||
print(f" [{i}] {stmt.strip()[:80]}...")
|
||||
cur.execute(stmt)
|
||||
print(f" ✅ 执行成功")
|
||||
|
||||
cur.close()
|
||||
print(f"\n✅ 迁移脚本执行完成")
|
||||
|
||||
|
||||
def run_verification(conn):
|
||||
"""执行验证 SQL,确认列已添加"""
|
||||
conn.autocommit = True
|
||||
cur = conn.cursor()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("🔍 验证结果")
|
||||
print("=" * 60)
|
||||
|
||||
# 验证 1:ods.member_profiles.birthday 列存在
|
||||
cur.execute("""
|
||||
SELECT column_name, data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'ods'
|
||||
AND table_name = 'member_profiles'
|
||||
AND column_name = 'birthday'
|
||||
""")
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
print(f" ✅ ods.member_profiles.birthday 存在 (类型: {row[1]})")
|
||||
else:
|
||||
print(f" ❌ ods.member_profiles.birthday 不存在!")
|
||||
|
||||
# 验证 2:dwd.dim_member.birthday 列存在
|
||||
cur.execute("""
|
||||
SELECT column_name, data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'dwd'
|
||||
AND table_name = 'dim_member'
|
||||
AND column_name = 'birthday'
|
||||
""")
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
print(f" ✅ dwd.dim_member.birthday 存在 (类型: {row[1]})")
|
||||
else:
|
||||
print(f" ❌ dwd.dim_member.birthday 不存在!")
|
||||
|
||||
# 验证 3:列注释已设置
|
||||
cur.execute("""
|
||||
SELECT col_description(c.oid, a.attnum)
|
||||
FROM pg_class c
|
||||
JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
JOIN pg_attribute a ON a.attrelid = c.oid
|
||||
WHERE n.nspname = 'dwd'
|
||||
AND c.relname = 'dim_member'
|
||||
AND a.attname = 'birthday'
|
||||
""")
|
||||
row = cur.fetchone()
|
||||
if row and row[0]:
|
||||
print(f" ✅ dwd.dim_member.birthday 注释: {row[0]}")
|
||||
else:
|
||||
print(f" ⚠️ dwd.dim_member.birthday 注释未设置")
|
||||
|
||||
cur.close()
|
||||
print("\n🏁 验证完成")
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("迁移脚本 C1:ODS/DWD 层会员表新增 birthday 列")
|
||||
print("=" * 60 + "\n")
|
||||
|
||||
conn = psycopg2.connect(TEST_DB_DSN)
|
||||
try:
|
||||
run_migration(conn)
|
||||
run_verification(conn)
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user