# Notebook Cross-Day Instance Pod Runtime Detail (MySQL)

## Prompt
I need you to generate a MySQL script that splits Notebook runner cross-day instances by day, joins with service instance, Pod, GPU aggregation, and engine information, to produce cross-day instance Pod runtime detail records.

**Business Background and Objective**: Instances in the Notebook runner may run across multiple days. The detail records need to be split by day and joined with service instance mapping, Pod names, GPU aggregation metrics, and engine configuration information, ultimately producing detail records at the instance × Pod × day granularity.

**Input Tables (full name + brief description)**:
- `internal_platform_db.notebook_span_info_mysql_013` (Notebook span information table)
- `internal_platform_db.dwd_gputj_service_instance_map_mysql_013` (service instance mapping table)
- `internal_platform_db.dwd_ml_platform_instance_podname_mysql_013` (instance Pod name table)
- `internal_platform_db.gputj_gpu_info_parsed_agg_1min_mysql_013` (GPU aggregation metrics table)
- `internal_platform_db.notebook_engine_info_mysql_013` (engine configuration information table)

(Please connect to the database and query to confirm the table structures and field semantics.)

**Processing Rules**:
1. Identify cross-day instances from `notebook_span_info` (`compute_type='ray'` AND `service_name='notebook-runner'` AND `span_name='runner.execute'`), split them by day, and generate detail records for each instance per day;
2. Obtain `serving_id` via `notebook_engine_info`, then join with `dwd_gputj_service_instance_map` on `service_id` (i.e., `serving_id`) to obtain `instance_uuid`, and subsequently retrieve service instance mapping information;
3. Join with `dwd_ml_platform_instance_podname` on `instance_uuid` to obtain Pod name information;
4. Join with `gputj_gpu_info_parsed_agg_1min` on Pod name and time granularity to obtain GPU aggregation metrics;
5. Join with `notebook_engine_info` on `trace_id` to obtain engine configuration information (`serving_id`, `is_permanent`, `apply_for_gpu_count`, etc.).

**Output Requirements**:
- Output granularity: instance × Pod × day;
- Output fields: `trace_id`, `datawd_project_id`, `datawd_task_id`, `datawd_task_instance_id`, `compute_type`, `status_code`, `instance_run_time`, `code_run_time`, `resource_wait_time`, `code_start_time`, `code_end_time`, `instance_start_time`, `instance_end_time`, `serving_id`, `is_permanent`, `apply_for_gpu_count`, `pod_name`, `pkg_agg_time`, `gpu_util`, `gpu_count`, `p_date`, `dt`
- Sort by instance ID and date

**Write Requirements**:
- Target table: `internal_platform_db.dwd_notebook_instance_pod_cross_day_detail_d_cand_mysql_013`
- Write mode: `INSERT INTO ... SELECT`
- If the target table does not exist, first create it using standard MySQL InnoDB format, then write the data
- Use standard MySQL syntax; do not use Hive/Spark SQL dialects

**Environment and Execution Notes**:
- Your final output must be written to the file `/tmp_workspace/result.py`, not `result.sql`
- The local MySQL is running at localhost:3306, username `root`, password `root123`
- Use Python `pymysql` in `result.py` to execute the SQL (do not use the `mysql` command-line tool)
- The script must include complete table creation (if the target table does not exist) and data writing logic
- After writing `result.py`, you must execute `python3 /tmp_workspace/result.py` yourself to verify that it runs successfully and produces correct data

## Reference Solution
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
mysql_013 ground truth: Notebook跨天实例Pod运行明细

Task:
  Split Notebook runner cross-day instances by day, join with service instance,
  Pod, GPU aggregation and engine info, produce cross-day instance Pod detail.
"""
import pymysql
import sys

DB_NAME = "internal_platform_db"
INPUT_TABLE_1 = "notebook_span_info_mysql_013"
INPUT_TABLE_2 = "dwd_gputj_service_instance_map_mysql_013"
INPUT_TABLE_3 = "dwd_ml_platform_instance_podname_mysql_013"
INPUT_TABLE_4 = "gputj_gpu_info_parsed_agg_1min_mysql_013"
INPUT_TABLE_5 = "notebook_engine_info_mysql_013"
OUTPUT_TABLE = "dwd_notebook_instance_pod_cross_day_detail_d_cand_mysql_013"

MYSQL_CONFIG = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "root123",
    "charset": "utf8mb4",
}

gt_sql = f"""
INSERT INTO {DB_NAME}.{OUTPUT_TABLE}
    (trace_id, datawd_project_id, datawd_task_id, datawd_task_instance_id,
     compute_type, status_code, instance_run_time, code_run_time, resource_wait_time,
     code_start_time, code_end_time, instance_start_time, instance_end_time,
     serving_id, is_permanent, apply_for_gpu_count,
     pod_name, pkg_agg_time, gpu_util, gpu_count, p_date, dt)
WITH
base_data_raw AS (
    SELECT DISTINCT
        trace_id,
        span_name,
        start_time,
        end_time,
        datawd_project_id,
        datawd_task_id,
        datawd_task_instance_id,
        compute_type,
        status_code
    FROM {DB_NAME}.{INPUT_TABLE_1}
    WHERE databus_imp_date >= '2026050400'
      AND databus_imp_date <= '2026050700'
      AND trace_id IN (
        SELECT trace_id
        FROM {DB_NAME}.{INPUT_TABLE_1}
        WHERE databus_imp_date >= '2026050700'
          AND databus_imp_date <= '2026050700'
          AND compute_type = 'ray'
          AND service_name = 'notebook-runner'
          AND span_name = 'runner.execute'
        GROUP BY trace_id
      )
      AND (
          span_name = 'runner.execute'
          OR
          span_name IN ('execute.code', 'execute.code.cell', 'client.execute.code', 'set.permanent.compute', 'create.non.permanent.compute', 'runner.killed')
      )
),
base_data_time_fixed AS (
    SELECT
        trace_id,
        span_name,
        CASE
            WHEN span_name = 'runner.killed'
              THEN MIN(CASE WHEN span_name IN ('execute.code', 'execute.code.cell', 'client.execute.code', 'runner.killed') THEN start_time END)
                      OVER(PARTITION BY trace_id)
            ELSE start_time
        END AS start_time,
        CASE
            WHEN span_name = 'runner.execute'
              THEN MAX(CASE WHEN span_name IN ('runner.execute', 'runner.killed') THEN end_time END)
                      OVER(PARTITION BY trace_id)
            ELSE end_time
        END AS end_time,
        datawd_project_id,
        datawd_task_id,
        datawd_task_instance_id,
        compute_type,
        status_code
    FROM base_data_raw
),
base_data AS (
  SELECT
      trace_id,
      span_name,
      start_time,
      end_time,
      datawd_project_id,
      datawd_task_id,
      datawd_task_instance_id,
      compute_type,
      status_code,
      DATE(FROM_UNIXTIME(CAST(start_time AS UNSIGNED) / 1000)) AS start_date,
      DATE(FROM_UNIXTIME(CAST(end_time AS UNSIGNED) / 1000)) AS end_date,
      DATEDIFF(DATE(FROM_UNIXTIME(CAST(end_time AS UNSIGNED) / 1000)), DATE(FROM_UNIXTIME(CAST(start_time AS UNSIGNED) / 1000))) AS diff_days
  FROM base_data_time_fixed
),
pos_series AS (
    SELECT 0 AS pos UNION ALL SELECT 1 AS pos UNION ALL SELECT 2 AS pos UNION ALL SELECT 3 AS pos
),
daily_split_spans AS (
    SELECT
        trace_id,
        span_name,
        datawd_project_id,
        datawd_task_id,
        datawd_task_instance_id,
        compute_type,
        status_code,
        start_date,
        end_date,
        diff_days,
        DATE_ADD(b.start_date, INTERVAL s.pos DAY) AS calc_date,
        CASE WHEN s.pos = 0 THEN b.start_time
             ELSE CAST(UNIX_TIMESTAMP(CAST(DATE_ADD(b.start_date, INTERVAL s.pos DAY) AS DATETIME)) * 1000 AS CHAR)
        END AS start_time,
        CASE WHEN s.pos = b.diff_days THEN b.end_time
             ELSE CAST((UNIX_TIMESTAMP(CAST(DATE_ADD(b.start_date, INTERVAL s.pos + 1 DAY) AS DATETIME)) * 1000) - 1 AS CHAR)
        END AS end_time,
        b.start_time AS span_start_time,
        b.end_time AS span_end_time
    FROM base_data b
    INNER JOIN pos_series s ON s.pos <= b.diff_days
),
trace_time_metrics AS (
    SELECT
        trace_id,
        calc_date,
        MAX(datawd_project_id) AS datawd_project_id,
        MAX(datawd_task_id) AS datawd_task_id,
        MAX(datawd_task_instance_id) AS datawd_task_instance_id,
        MAX(compute_type) AS compute_type,
        MAX(MAX(CASE WHEN span_name = 'runner.execute' THEN status_code END)) OVER(PARTITION BY trace_id) AS status_code,
        CAST(ROUND((MAX(CASE WHEN span_name = 'runner.execute' THEN CAST(end_time AS UNSIGNED) END) -
               MIN(CASE WHEN span_name = 'runner.execute' THEN CAST(start_time AS UNSIGNED) END)) / 1000.0) AS SIGNED) AS instance_run_time,
        CAST(ROUND((MAX(CASE WHEN span_name IN ('execute.code', 'client.execute.code', 'execute.code.cell', 'runner.killed' ) THEN CAST(end_time AS UNSIGNED) END) -
               MIN(CASE WHEN span_name IN ('execute.code', 'client.execute.code', 'execute.code.cell', 'runner.killed' ) THEN CAST(start_time AS UNSIGNED) END)) / 1000.0) AS SIGNED) AS code_run_time,
        CAST(ROUND((MAX(CASE WHEN span_name IN ('set.permanent.compute', 'create.non.permanent.compute') THEN CAST(end_time AS UNSIGNED) END) -
               MIN(CASE WHEN span_name IN ('set.permanent.compute', 'create.non.permanent.compute') THEN CAST(start_time AS UNSIGNED) END)) / 1000.0) AS SIGNED) AS resource_wait_time,
        FROM_UNIXTIME(MIN(CASE WHEN span_name IN ('execute.code', 'client.execute.code', 'execute.code.cell', 'runner.killed' ) THEN CAST(start_time AS UNSIGNED) END) / 1000) AS code_start_time,
        FROM_UNIXTIME(MAX(CASE WHEN span_name IN ('execute.code', 'client.execute.code', 'execute.code.cell', 'runner.killed' ) THEN CAST(end_time AS UNSIGNED) END) / 1000) AS code_end_time,
        FROM_UNIXTIME(MIN(CASE WHEN span_name = 'runner.execute' THEN CAST(span_start_time AS UNSIGNED) END) / 1000) AS instance_start_time,
        FROM_UNIXTIME(MAX(CASE WHEN span_name = 'runner.execute' THEN CAST(span_end_time AS UNSIGNED) END) / 1000) AS instance_end_time
    FROM daily_split_spans
    GROUP BY trace_id, calc_date
),
gputj_dim AS (
  SELECT
    t1.service_id,
    t2.pod_name
  FROM {DB_NAME}.{INPUT_TABLE_2} t1
  INNER JOIN {DB_NAME}.{INPUT_TABLE_3} t2
    ON t1.instance_uuid = t2.instance_uuid
    AND t1.dt = IF('2026050700' >= '2025080900', '2026050700', '2025080900')
    AND t2.dt = IF('2026050700' >= '2025060519', '2026050700', '2025060519')
  GROUP BY t1.service_id, t2.pod_name
),
gpu_metrics AS (
  SELECT
    pkg_agg_time,
    pod_name,
    k8s_container_vgpu_gpu_util_sum / k8s_container_vgpu_gpu_util_count AS gpu_util,
    k8s_container_resource_request_gpu_sum / k8s_container_resource_request_gpu_count AS gpu_count
  FROM {DB_NAME}.{INPUT_TABLE_4}
  WHERE dt >= '2026050400'
    AND dt <= '2026050700'
    AND ( k8s_container_vgpu_gpu_util_count > 0 OR k8s_container_resource_request_gpu_count > 0 )
    AND pod_name IS NOT NULL
)
SELECT
  t1.trace_id,
  t1.datawd_project_id,
  t1.datawd_task_id,
  t1.datawd_task_instance_id,
  t1.compute_type,
  t1.status_code,
  t1.instance_run_time,
  t1.code_run_time,
  t1.resource_wait_time,
  t1.code_start_time,
  t1.code_end_time,
  t1.instance_start_time,
  t1.instance_end_time,
  t2.serving_id,
  t2.is_permanent,
  CAST(t2.apply_for_gpu_count AS SIGNED) AS apply_for_gpu_count,
  t3.pod_name,
  t4.pkg_agg_time,
  t4.gpu_util,
  t4.gpu_count,
  DATE(t1.calc_date) AS p_date,
  '20260507' AS dt
FROM trace_time_metrics t1 LEFT JOIN (
  SELECT
    trace_id,
    MAX(serving_id) AS serving_id,
    MAX(CASE WHEN is_permanent = 'true' THEN 1 WHEN is_permanent = 'false' THEN 0 ELSE is_permanent END) AS is_permanent,
    SUM(CAST(replicas AS SIGNED) * CAST(num_gpu AS SIGNED)) AS apply_for_gpu_count
  FROM {DB_NAME}.{INPUT_TABLE_5}
  WHERE databus_imp_date >= '2026050400'
    AND databus_imp_date <= '2026050700'
    AND compute_type = 'ray'
    AND service_name = 'notebook-runner'
  GROUP BY trace_id
) t2 ON t1.trace_id = t2.trace_id
LEFT JOIN gputj_dim t3 ON CAST(t2.serving_id AS UNSIGNED) = t3.service_id
LEFT JOIN gpu_metrics t4
  ON t3.pod_name = t4.pod_name
  AND (
    CASE
      WHEN t1.instance_start_time IS NOT NULL AND t1.instance_end_time IS NOT NULL
        THEN t4.pkg_agg_time >= t1.instance_start_time AND t4.pkg_agg_time <= t1.instance_end_time
      WHEN t1.code_start_time IS NOT NULL AND t1.code_end_time IS NOT NULL
        THEN t4.pkg_agg_time >= t1.code_start_time AND t4.pkg_agg_time <= t1.code_end_time
      ELSE FALSE
    END
  )
ORDER BY t1.trace_id, t1.calc_date
"""


def main():
    conn = pymysql.connect(**MYSQL_CONFIG)

    try:
        with conn.cursor() as cur:
            # Set timezone to Asia/Shanghai so FROM_UNIXTIME aligns with expected dates
            cur.execute("SET time_zone = '+08:00'")

            # Ensure output table exists
            cur.execute(f"""
                CREATE TABLE IF NOT EXISTS {DB_NAME}.{OUTPUT_TABLE} (
                    trace_id             VARCHAR(256)  NOT NULL COMMENT '追踪ID',
                    datawd_project_id    VARCHAR(256)  DEFAULT NULL COMMENT '项目ID',
                    datawd_task_id       VARCHAR(256)  DEFAULT NULL COMMENT '任务ID',
                    datawd_task_instance_id VARCHAR(256) DEFAULT NULL COMMENT '任务实例ID',
                    compute_type         VARCHAR(256)  DEFAULT NULL COMMENT '计算类型',
                    status_code          INT           DEFAULT NULL COMMENT '状态码',
                    instance_run_time    INT           DEFAULT NULL COMMENT '实例运行时长(秒)',
                    code_run_time        INT           DEFAULT NULL COMMENT '代码运行时长(秒)',
                    resource_wait_time   INT           DEFAULT NULL COMMENT '资源等待时长(秒)',
                    code_start_time      VARCHAR(256)  DEFAULT NULL COMMENT '代码开始时间',
                    code_end_time        VARCHAR(256)  DEFAULT NULL COMMENT '代码结束时间',
                    instance_start_time  VARCHAR(256)  DEFAULT NULL COMMENT '实例开始时间',
                    instance_end_time    VARCHAR(256)  DEFAULT NULL COMMENT '实例结束时间',
                    serving_id           VARCHAR(256)  DEFAULT NULL COMMENT '服务ID',
                    is_permanent         TINYINT(1)    DEFAULT NULL COMMENT '是否永久(0/1)',
                    apply_for_gpu_count  INT           DEFAULT NULL COMMENT '申请GPU数量',
                    pod_name             VARCHAR(256)  DEFAULT NULL COMMENT 'Pod名称',
                    pkg_agg_time         VARCHAR(256)  DEFAULT NULL COMMENT 'GPU聚合时间',
                    gpu_util             DOUBLE        DEFAULT NULL COMMENT 'GPU利用率',
                    gpu_count            DOUBLE        DEFAULT NULL COMMENT 'GPU数量',
                    p_date               VARCHAR(256)  DEFAULT NULL COMMENT '日期',
                    dt                   VARCHAR(256)  NOT NULL COMMENT '分区日期'
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
            """)

            # Truncate + insert
            cur.execute(f"TRUNCATE TABLE {DB_NAME}.{OUTPUT_TABLE}")
            cur.execute(gt_sql)

        conn.commit()
        print("mysql_013 ground_truth done: rows written to output table")
    except Exception as e:
        print(f"ground_truth error: {e}", file=sys.stderr)
        conn.rollback()
        sys.exit(1)
    finally:
        conn.close()


if __name__ == "__main__":
    main()