#!/bin/bash # 课时完成记录查询脚本 # 查询指定课时(chapter_id)的首次完成记录,包含角色信息、最近登录、课程耗时 # 数据库:线上 PostgreSQL (vala_bi) # 输出:xlsx 格式 # 用法:bash scripts/query_chapter_play.sh set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" source "${SCRIPT_DIR}/../secrets.env" DB_HOST="bj-postgres-16pob4sg.sql.tencentcdb.com" DB_PORT="28591" DB_USER="ai_member" DB_NAME="vala_bi" OUTPUT_DIR="${SCRIPT_DIR}/../output" mkdir -p "$OUTPUT_DIR" TIMESTAMP=$(date +%Y%m%d_%H%M%S) CSV_TMP="${OUTPUT_DIR}/.chapter_play_${TIMESTAMP}.csv" OUTPUT_FILE="${OUTPUT_DIR}/chapter_play_${TIMESTAMP}.xlsx" SQL=$(cat <<'EOF' WITH chapter_play AS ( SELECT user_id, chapter_id, chapter_unique_id, date(updated_at) AS finish_date FROM bi_user_chapter_play_record_0 WHERE chapter_id IN (55,56,57,58,59,343,344,345,346,348) AND play_status = 1 UNION ALL SELECT user_id, chapter_id, chapter_unique_id, date(updated_at) FROM bi_user_chapter_play_record_1 WHERE chapter_id IN (55,56,57,58,59,343,344,345,346,348) AND play_status = 1 UNION ALL SELECT user_id, chapter_id, chapter_unique_id, date(updated_at) FROM bi_user_chapter_play_record_2 WHERE chapter_id IN (55,56,57,58,59,343,344,345,346,348) AND play_status = 1 UNION ALL SELECT user_id, chapter_id, chapter_unique_id, date(updated_at) FROM bi_user_chapter_play_record_3 WHERE chapter_id IN (55,56,57,58,59,343,344,345,346,348) AND play_status = 1 UNION ALL SELECT user_id, chapter_id, chapter_unique_id, date(updated_at) FROM bi_user_chapter_play_record_4 WHERE chapter_id IN (55,56,57,58,59,343,344,345,346,348) AND play_status = 1 UNION ALL SELECT user_id, chapter_id, chapter_unique_id, date(updated_at) FROM bi_user_chapter_play_record_5 WHERE chapter_id IN (55,56,57,58,59,343,344,345,346,348) AND play_status = 1 UNION ALL SELECT user_id, chapter_id, chapter_unique_id, date(updated_at) FROM bi_user_chapter_play_record_6 WHERE chapter_id IN (55,56,57,58,59,343,344,345,346,348) AND play_status = 1 UNION ALL SELECT user_id, chapter_id, chapter_unique_id, date(updated_at) FROM bi_user_chapter_play_record_7 WHERE chapter_id IN (55,56,57,58,59,343,344,345,346,348) AND play_status = 1 ), comp_time AS ( SELECT chapter_unique_id, SUM(interval_time) AS total_interval FROM ( SELECT chapter_unique_id, interval_time FROM bi_user_component_play_record_0 UNION ALL SELECT chapter_unique_id, interval_time FROM bi_user_component_play_record_1 UNION ALL SELECT chapter_unique_id, interval_time FROM bi_user_component_play_record_2 UNION ALL SELECT chapter_unique_id, interval_time FROM bi_user_component_play_record_3 UNION ALL SELECT chapter_unique_id, interval_time FROM bi_user_component_play_record_4 UNION ALL SELECT chapter_unique_id, interval_time FROM bi_user_component_play_record_5 UNION ALL SELECT chapter_unique_id, interval_time FROM bi_user_component_play_record_6 UNION ALL SELECT chapter_unique_id, interval_time FROM bi_user_component_play_record_7 ) t GROUP BY chapter_unique_id ), course_detail AS ( SELECT cp.user_id, cp.chapter_id, FORMAT('%s-%s-%s-%s', l.course_level, l.course_season, l.course_unit, l.course_lesson) AS course_id, cp.finish_date, FORMAT('%s:%s', FLOOR(ct.total_interval / 1000 / 60), LPAD(CAST(MOD(ct.total_interval / 1000, 60) AS TEXT), 2, '0') ) AS finish_time FROM ( SELECT user_id, chapter_id, chapter_unique_id, finish_date, ROW_NUMBER() OVER (PARTITION BY user_id, chapter_id ORDER BY finish_date) AS rn FROM chapter_play ) cp LEFT JOIN bi_level_unit_lesson l ON cp.chapter_id = l.id LEFT JOIN comp_time ct ON cp.chapter_unique_id = ct.chapter_unique_id WHERE cp.rn = 1 ) SELECT a.account_id AS "账号ID", a.id AS "角色ID", DATE(a.created_at) AS "注册日期", DATE(TO_TIMESTAMP(b.latest_active_time)) AS "最近登录时间", c.course_id AS "课程名称", c.finish_date AS "课程完成时间", c.finish_time AS "课程耗时" FROM bi_vala_app_character a LEFT JOIN user_detail_info b ON a.id = b.user_id LEFT JOIN course_detail c ON a.id = c.user_id WHERE a.status = 1 ORDER BY a.id, c.course_id; EOF ) echo "正在查询..." PGPASSWORD="$PG_ONLINE_PASSWORD" psql \ -h "$DB_HOST" \ -p "$DB_PORT" \ -U "$DB_USER" \ -d "$DB_NAME" \ --csv \ -c "$SQL" \ > "$CSV_TMP" ROW_COUNT=$(tail -n +2 "$CSV_TMP" | wc -l) echo "查询完成,共 ${ROW_COUNT} 条记录,正在转换为 xlsx..." python3 - "$CSV_TMP" "$OUTPUT_FILE" <<'PYEOF' import csv, sys from openpyxl import Workbook from openpyxl.styles import Font, Alignment, PatternFill csv_path, xlsx_path = sys.argv[1], sys.argv[2] wb = Workbook() ws = wb.active ws.title = "课时完成记录" # 读取 CSV with open(csv_path, 'r', encoding='utf-8') as f: reader = csv.reader(f) for row in reader: ws.append(row) # 表头样式 header_font = Font(bold=True, color="FFFFFF", size=11) header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") header_align = Alignment(horizontal="center", vertical="center") for cell in ws[1]: cell.font = header_font cell.fill = header_fill cell.alignment = header_align # 自动列宽 for col in ws.columns: max_len = 0 col_letter = col[0].column_letter for cell in col: val = str(cell.value) if cell.value else "" # 中文字符算 2 宽度 width = sum(2 if ord(c) > 127 else 1 for c in val) if width > max_len: max_len = width ws.column_dimensions[col_letter].width = min(max_len + 3, 30) # 冻结首行 ws.freeze_panes = "A2" wb.save(xlsx_path) print(f"xlsx 已保存: {xlsx_path}") PYEOF # 清理临时 CSV rm -f "$CSV_TMP" echo "完成!结果已保存至: ${OUTPUT_FILE}"