ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
@@ -0,0 +1,322 @@
[
{
"emp_id": 1,
"name": "秦娟",
"department": "研发部",
"level": 3,
"hire_date": "2025-08-07",
"leave_date": null
},
{
"emp_id": 2,
"name": "郑雪",
"department": "销售部",
"level": 8,
"hire_date": "2026-03-08",
"leave_date": null
},
{
"emp_id": 3,
"name": "孙芳",
"department": "人力资源部",
"level": 6,
"hire_date": "2026-05-17",
"leave_date": null
},
{
"emp_id": 4,
"name": "钱松",
"department": "销售部",
"level": 4,
"hire_date": "2026-05-14",
"leave_date": null
},
{
"emp_id": 5,
"name": "韩晓",
"department": "人力资源部",
"level": 6,
"hire_date": "2026-03-21",
"leave_date": null
},
{
"emp_id": 6,
"name": "赵军",
"department": "市场部",
"level": 9,
"hire_date": "2025-09-02",
"leave_date": null
},
{
"emp_id": 7,
"name": "陈艳",
"department": "市场部",
"level": 5,
"hire_date": "2025-11-26",
"leave_date": null
},
{
"emp_id": 8,
"name": "孔静",
"department": "研发部",
"level": 3,
"hire_date": "2026-01-09",
"leave_date": null
},
{
"emp_id": 9,
"name": "朱娜",
"department": "市场部",
"level": 7,
"hire_date": "2025-01-23",
"leave_date": null
},
{
"emp_id": 10,
"name": "孔敏",
"department": "人力资源部",
"level": 3,
"hire_date": "2024-12-02",
"leave_date": null
},
{
"emp_id": 11,
"name": "张勇",
"department": "市场部",
"level": 9,
"hire_date": "2024-10-16",
"leave_date": null
},
{
"emp_id": 12,
"name": "韩超",
"department": "研发部",
"level": 8,
"hire_date": "2025-06-20",
"leave_date": null
},
{
"emp_id": 13,
"name": "郑建",
"department": "销售部",
"level": 9,
"hire_date": "2025-06-15",
"leave_date": null
},
{
"emp_id": 14,
"name": "张军",
"department": "财务部",
"level": 8,
"hire_date": "2025-03-05",
"leave_date": null
},
{
"emp_id": 15,
"name": "秦英",
"department": "市场部",
"level": 4,
"hire_date": "2025-01-17",
"leave_date": null
},
{
"emp_id": 16,
"name": "杨军",
"department": "销售部",
"level": 7,
"hire_date": "2024-09-17",
"leave_date": null
},
{
"emp_id": 17,
"name": "韩平",
"department": "财务部",
"level": 5,
"hire_date": "2023-11-27",
"leave_date": null
},
{
"emp_id": 18,
"name": "孙平",
"department": "销售部",
"level": 9,
"hire_date": "2024-06-22",
"leave_date": null
},
{
"emp_id": 19,
"name": "沈平",
"department": "市场部",
"level": 3,
"hire_date": "2023-12-28",
"leave_date": null
},
{
"emp_id": 20,
"name": "魏磊",
"department": "财务部",
"level": 6,
"hire_date": "2024-04-03",
"leave_date": null
},
{
"emp_id": 21,
"name": "朱强",
"department": "销售部",
"level": 4,
"hire_date": "2024-03-07",
"leave_date": null
},
{
"emp_id": 22,
"name": "韩强",
"department": "财务部",
"level": 5,
"hire_date": "2023-09-26",
"leave_date": null
},
{
"emp_id": 23,
"name": "李丽",
"department": "财务部",
"level": 3,
"hire_date": "2023-11-03",
"leave_date": null
},
{
"emp_id": 24,
"name": "华英",
"department": "销售部",
"level": 9,
"hire_date": "2024-05-03",
"leave_date": null
},
{
"emp_id": 25,
"name": "魏栋",
"department": "财务部",
"level": 7,
"hire_date": "2022-06-27",
"leave_date": "2024-12-21"
},
{
"emp_id": 26,
"name": "赵丽",
"department": "人力资源部",
"level": 9,
"hire_date": "2022-11-11",
"leave_date": "2025-08-19"
},
{
"emp_id": 27,
"name": "秦刚",
"department": "人力资源部",
"level": 9,
"hire_date": "2021-08-27",
"leave_date": "2026-04-29"
},
{
"emp_id": 28,
"name": "褚东",
"department": "市场部",
"level": 6,
"hire_date": "2023-04-03",
"leave_date": "2025-09-30"
},
{
"emp_id": 29,
"name": "卫国",
"department": "市场部",
"level": 7,
"hire_date": "2023-07-23",
"leave_date": null
},
{
"emp_id": 30,
"name": "蒋磊",
"department": "市场部",
"level": 9,
"hire_date": "2023-04-09",
"leave_date": null
},
{
"emp_id": 31,
"name": "赵平",
"department": "销售部",
"level": 7,
"hire_date": "2022-07-09",
"leave_date": null
},
{
"emp_id": 32,
"name": "张霞",
"department": "研发部",
"level": 3,
"hire_date": "2022-03-13",
"leave_date": null
},
{
"emp_id": 33,
"name": "吴敏",
"department": "研发部",
"level": 4,
"hire_date": "2022-11-23",
"leave_date": null
},
{
"emp_id": 34,
"name": "周雪",
"department": "财务部",
"level": 9,
"hire_date": "2021-07-07",
"leave_date": null
},
{
"emp_id": 35,
"name": "陶松",
"department": "销售部",
"level": 4,
"hire_date": "2021-06-02",
"leave_date": "2026-03-20"
},
{
"emp_id": 36,
"name": "华艳",
"department": "市场部",
"level": 7,
"hire_date": "2023-02-07",
"leave_date": "2025-06-27"
},
{
"emp_id": 37,
"name": "许华",
"department": "销售部",
"level": 8,
"hire_date": "2022-01-20",
"leave_date": null
},
{
"emp_id": 38,
"name": "金丽",
"department": "市场部",
"level": 6,
"hire_date": "2021-09-07",
"leave_date": null
},
{
"emp_id": 39,
"name": "吕芳",
"department": "销售部",
"level": 3,
"hire_date": "2022-11-15",
"leave_date": null
},
{
"emp_id": 40,
"name": "韩伟",
"department": "人力资源部",
"level": 4,
"hire_date": "2021-12-01",
"leave_date": null
}
]
@@ -0,0 +1,584 @@
{
"schema_version": "1.0",
"experiment": "5-10",
"run_id": "20260729T210334Z-5_10-postgresql",
"started_at_utc": "2026-07-29T21:03:34.066223+00:00",
"completed_at_utc": "2026-07-29T21:06:43.050217+00:00",
"provider": "ark",
"endpoint": "https://ark.cn-beijing.volces.com/api/v3",
"model": "doubao-seed-1-6-250615",
"postgresql": {
"version": "PostgreSQL 14.13 (Homebrew) on aarch64-apple-darwin23.6.0, compiled by Apple clang version 16.0.0 (clang-1600.0.26.4), 64-bit",
"database": "postgres",
"schema": "exp5_10_20260729t210334z510postgresql",
"employees": 40,
"salary_rows": 1184
},
"source": {
"manuscript": "book/chapter5.md#实验-5-10",
"campaign_sha256": "d921a6d18683dcbcfa84f4ea08ad67a622315ddf54b05cf9a1ea048564eae209",
"seed_sha256": "833c1a09349802dfad70c84b7d568d1e06ec3d73bdef588c796b2d704a73730d"
},
"records": [
{
"id": 1,
"question": "平均每个员工在职多久?",
"sql": "SELECT AVG(COALESCE(leave_date, CURRENT_DATE) - hire_date) AS average_tenure_days FROM employees",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT AVG(COALESCE(leave_date, CURRENT_DATE) - hire_date) AS average_tenure_days FROM employees",
"query_latency_s": 0.0015,
"execution_error": null
}
],
"rows": [
[
886.2
]
],
"row_count": 1,
"query_latency_s": 0.0015,
"expected": [
[
886.2
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 2,
"question": "每个部门有多少在职员工?",
"sql": "SELECT department, COUNT(emp_id) AS active_count FROM employees WHERE leave_date IS NULL GROUP BY department",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT department, COUNT(emp_id) AS active_count FROM employees WHERE leave_date IS NULL GROUP BY department",
"query_latency_s": 0.0007,
"execution_error": null
}
],
"rows": [
[
"人力资源部",
4
],
[
"市场部",
9
],
[
"研发部",
5
],
[
"财务部",
6
],
[
"销售部",
10
]
],
"row_count": 5,
"query_latency_s": 0.0007,
"expected": [
[
"研发部",
5
],
[
"销售部",
10
],
[
"人力资源部",
4
],
[
"市场部",
9
],
[
"财务部",
6
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 3,
"question": "哪个部门员工平均级别最高?",
"sql": "SELECT department\nFROM employees\nGROUP BY department\nORDER BY AVG(level) DESC\nLIMIT 1",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT department\nFROM employees\nGROUP BY department\nORDER BY AVG(level) DESC\nLIMIT 1",
"query_latency_s": 0.0008,
"execution_error": null
}
],
"rows": [
[
"销售部"
]
],
"row_count": 1,
"query_latency_s": 0.0008,
"expected": [
[
"销售部"
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 4,
"question": "每个部门今年和去年各新入职多少人?",
"sql": "SELECT department,\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS \"this-year count\",\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS \"last-year count\"\nFROM employees\nGROUP BY department\nHAVING COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) > 0\n OR COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) > 0",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT department,\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS \"this-year count\",\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS \"last-year count\"\nFROM employees\nGROUP BY department\nHAVING COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) > 0\n OR COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) > 0",
"query_latency_s": 0.0008,
"execution_error": null
}
],
"rows": [
[
"财务部",
0,
1
],
[
"销售部",
2,
1
],
[
"人力资源部",
2,
0
],
[
"研发部",
1,
2
],
[
"市场部",
0,
4
]
],
"row_count": 5,
"query_latency_s": 0.0008,
"expected": [
[
"研发部",
1,
2
],
[
"销售部",
2,
1
],
[
"人力资源部",
2,
0
],
[
"市场部",
0,
4
],
[
"财务部",
0,
1
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 5,
"question": "前年3月到去年5月,A部门平均工资是多少?",
"sql": "SELECT AVG(s.salary)\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE e.department = '研发部'\n AND s.pay_date BETWEEN make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 2, 3, 1)\n AND make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 1, 5, 31)",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT AVG(s.salary)\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE e.department = '研发部'\n AND s.pay_date BETWEEN make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 2, 3, 1)\n AND make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 1, 5, 31)",
"query_latency_s": 0.0021,
"execution_error": null
}
],
"rows": [
[
27695.833333333332
]
],
"row_count": 1,
"query_latency_s": 0.0021,
"expected": [
[
27695.83
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 6,
"question": "去年A部门和B部门平均工资哪个高?",
"sql": "SELECT department, AVG(salary) AS average_salary\nFROM employees\nJOIN salaries ON employees.emp_id = salaries.emp_id\nWHERE department IN ('研发部', '销售部')\n AND pay_date >= date_trunc('year', CURRENT_DATE) - INTERVAL '1 year'\n AND pay_date < date_trunc('year', CURRENT_DATE)\nGROUP BY department",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT department, AVG(salary) AS average_salary\nFROM employees\nJOIN salaries ON employees.emp_id = salaries.emp_id\nWHERE department IN ('研发部', '销售部')\n AND pay_date >= date_trunc('year', CURRENT_DATE) - INTERVAL '1 year'\n AND pay_date < date_trunc('year', CURRENT_DATE)\nGROUP BY department",
"query_latency_s": 0.0011,
"execution_error": null
}
],
"rows": [
[
"研发部",
28569.444444444445
],
[
"销售部",
29481.55339805825
]
],
"row_count": 2,
"query_latency_s": 0.0011,
"expected": [
[
"研发部",
28569.44
],
[
"销售部",
29481.55
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 7,
"question": "今年每个级别的员工平均工资是多少?",
"sql": "SELECT e.level, AVG(s.salary) AS average_salary\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE EXTRACT(YEAR FROM s.pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)\nGROUP BY e.level",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT e.level, AVG(s.salary) AS average_salary\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE EXTRACT(YEAR FROM s.pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)\nGROUP BY e.level",
"query_latency_s": 0.0014,
"execution_error": null
}
],
"rows": [
[
3,
23456.428571428572
],
[
4,
26248.823529411766
],
[
5,
34534.75
],
[
6,
28461.363636363636
],
[
7,
29935.0
],
[
8,
32242.69230769231
],
[
9,
34559.90566037736
]
],
"row_count": 7,
"query_latency_s": 0.0014,
"expected": [
[
3,
23456.43
],
[
8,
32242.69
],
[
6,
28461.36
],
[
4,
26248.82
],
[
9,
34559.91
],
[
5,
34534.75
],
[
7,
29935
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 8,
"question": "入职一年内、一到两年、两到三年的员工,最近一个月平均工资是多少?",
"sql": "WITH latest_salaries AS (\n SELECT DISTINCT ON (emp_id) emp_id, salary\n FROM salaries\n ORDER BY emp_id, pay_date DESC\n)\nSELECT \n CASE \n WHEN (CURRENT_DATE - e.hire_date)::INTEGER < 365 THEN '入职一年内'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 365 AND 729 THEN '一到两年'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 730 AND 1094 THEN '两到三年'\n END AS bucket,\n AVG(ls.salary) AS average_latest_salary\nFROM employees e\nJOIN latest_salaries ls ON e.emp_id = ls.emp_id\nWHERE e.leave_date IS NULL\n AND (CURRENT_DATE - e.hire_date)::INTEGER < 1095\nGROUP BY bucket\nORDER BY bucket",
"sql_attempts": [
{
"attempt": 1,
"sql": "WITH latest_salaries AS (\n SELECT DISTINCT ON (emp_id) emp_id, salary\n FROM salaries\n ORDER BY emp_id, pay_date DESC\n)\nSELECT \n CASE \n WHEN (CURRENT_DATE - e.hire_date)::INTEGER < 365 THEN '入职一年内'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 365 AND 729 THEN '一到两年'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 730 AND 1094 THEN '两到三年'\n END AS bucket,\n AVG(ls.salary) AS average_latest_salary\nFROM employees e\nJOIN latest_salaries ls ON e.emp_id = ls.emp_id\nWHERE e.leave_date IS NULL\n AND (CURRENT_DATE - e.hire_date)::INTEGER < 1095\nGROUP BY bucket\nORDER BY bucket",
"query_latency_s": 0.0015,
"execution_error": null
}
],
"rows": [
[
"一到两年",
27683.125
],
[
"两到三年",
31138.75
],
[
"入职一年内",
24053.75
]
],
"row_count": 3,
"query_latency_s": 0.0015,
"expected": [
[
"入职一年内",
24053.75
],
[
"一到两年",
27683.12
],
[
"两到三年",
31138.75
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 9,
"question": "去年到今年涨薪幅度最大的10位员工是谁?",
"sql": "WITH emp_salary_avg AS (\n SELECT \n emp_id,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS current_avg,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS previous_avg\n FROM salaries\n GROUP BY emp_id\n HAVING \n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) IS NOT NULL\n AND AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) IS NOT NULL\n)\nSELECT \n e.name,\n (esa.current_avg - esa.previous_avg) AS raise_amount\nFROM emp_salary_avg esa\nJOIN employees e ON esa.emp_id = e.emp_id\nORDER BY raise_amount DESC\nLIMIT 10",
"sql_attempts": [
{
"attempt": 1,
"sql": "WITH emp_salary_avg AS (\n SELECT \n emp_id,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS current_avg,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS previous_avg\n FROM salaries\n GROUP BY emp_id\n HAVING \n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) IS NOT NULL\n AND AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) IS NOT NULL\n)\nSELECT \n e.name,\n (esa.current_avg - esa.previous_avg) AS raise_amount\nFROM emp_salary_avg esa\nJOIN employees e ON esa.emp_id = e.emp_id\nORDER BY raise_amount DESC\nLIMIT 10",
"query_latency_s": 0.0018,
"execution_error": null
}
],
"rows": [
[
"韩平",
12000.0
],
[
"韩伟",
2200.0
],
[
"吕芳",
2155.0
],
[
"金丽",
2110.0
],
[
"许华",
2065.0
],
[
"陶松",
1975.0
],
[
"周雪",
1930.0
],
[
"吴敏",
1885.0
],
[
"张霞",
1840.0
],
[
"赵平",
1795.0
]
],
"row_count": 10,
"query_latency_s": 0.0018,
"expected": [
[
"韩平",
12000
],
[
"韩伟",
2200
],
[
"吕芳",
2155
],
[
"金丽",
2110
],
[
"许华",
2065
],
[
"陶松",
1975
],
[
"周雪",
1930
],
[
"吴敏",
1885
],
[
"张霞",
1840
],
[
"赵平",
1795
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 10,
"question": "有没有拖欠工资的情况(某个月还在职却没有发薪)?",
"sql": "WITH employee_employed_months AS (\n SELECT \n e.emp_id,\n generate_series(\n date_trunc('month', e.hire_date),\n date_trunc('month', COALESCE(e.leave_date, CURRENT_DATE)),\n interval '1 month'\n ) AS employed_month\n FROM employees e\n)\nSELECT \n em.emp_id,\n to_char(em.employed_month, 'YYYY-MM') AS month\nFROM employee_employed_months em\nLEFT JOIN salaries s \n ON em.emp_id = s.emp_id \n AND date_trunc('month', s.pay_date) = em.employed_month\nWHERE s.emp_id IS NULL",
"sql_attempts": [
{
"attempt": 1,
"sql": "WITH employee_employed_months AS (\n SELECT \n e.emp_id,\n generate_series(\n date_trunc('month', e.hire_date),\n date_trunc('month', COALESCE(e.leave_date, CURRENT_DATE)),\n interval '1 month'\n ) AS employed_month\n FROM employees e\n)\nSELECT \n em.emp_id,\n to_char(em.employed_month, 'YYYY-MM') AS month\nFROM employee_employed_months em\nLEFT JOIN salaries s \n ON em.emp_id = s.emp_id \n AND date_trunc('month', s.pay_date) = em.employed_month\nWHERE s.emp_id IS NULL",
"query_latency_s": 0.0122,
"execution_error": null
}
],
"rows": [
[
17,
"2026-01"
]
],
"row_count": 1,
"query_latency_s": 0.0122,
"expected": [
[
17,
"2026-01"
]
],
"passed": true,
"comparison": "independent Python reference matched"
}
],
"browser": {
"browser": "Chromium",
"version": "139.0.7258.5",
"html": "results.html",
"screenshot": "results.png"
},
"usage": {
"calls": 10,
"prompt_tokens": 3154,
"completion_tokens": 8192,
"total_tokens": 11346,
"model_latency_s": 187.73,
"db_latency_s": 0.0239
},
"artifacts": {
"employees.json": {
"path": "employees.json",
"sha256": "7e5e237da09edb3db029e367a52569267241673a99e19d2ffddbb85a45cb59bd"
},
"salaries.json": {
"path": "salaries.json",
"sha256": "70a9dcd335d5c3e277eac92a4ae351f0f33c56ef9b2a526047cf60c98ed04228"
},
"schema.sql": {
"path": "schema.sql",
"sha256": "76a7d9f85d8bf3998729c40fa448e61e49ec24d47acba2f04580e5d2aeb27596"
},
"receipts.json": {
"path": "receipts.json",
"sha256": "0eb53eb1ac08d3b4091d02db1053e67078ac83e0f564ba8ae6f76fbc937e7a85"
},
"queries_and_results.json": {
"path": "queries_and_results.json",
"sha256": "a2be9fa715a15fe4290ee250f67a1c742ff8a3c3cff215f664a0d77b10ec8b40"
},
"results.html": {
"path": "results.html",
"sha256": "6099929004da8eb22e56f2557d3e167cd39ae2aee2b4a70d2fe61576d1980639"
},
"results.png": {
"path": "results.png",
"sha256": "9dccf840df361ad4031eb559672639876595f038f907e95987cc5c7ca550462c"
}
},
"acceptance_gates": {
"real_postgresql_server": true,
"exact_two_table_schema_created": true,
"all_10_natural_language_questions_attempted": true,
"all_10_sql_artifacts_are_read_only": true,
"database_not_llm_received_rows": true,
"database_executed_every_artifact": true,
"all_10_answers_match_independent_reference": true,
"result_tables_rendered_directly_in_real_browser": true,
"raw_model_receipts_complete": true,
"repairs_use_execution_errors_only": true,
"raw_database_rows_and_hashes_retained": true
},
"official_complete": true
}
@@ -0,0 +1,504 @@
[
{
"id": 1,
"question": "平均每个员工在职多久?",
"sql": "SELECT AVG(COALESCE(leave_date, CURRENT_DATE) - hire_date) AS average_tenure_days FROM employees",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT AVG(COALESCE(leave_date, CURRENT_DATE) - hire_date) AS average_tenure_days FROM employees",
"query_latency_s": 0.0015,
"execution_error": null
}
],
"rows": [
[
886.2
]
],
"row_count": 1,
"query_latency_s": 0.0015,
"expected": [
[
886.2
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 2,
"question": "每个部门有多少在职员工?",
"sql": "SELECT department, COUNT(emp_id) AS active_count FROM employees WHERE leave_date IS NULL GROUP BY department",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT department, COUNT(emp_id) AS active_count FROM employees WHERE leave_date IS NULL GROUP BY department",
"query_latency_s": 0.0007,
"execution_error": null
}
],
"rows": [
[
"人力资源部",
4
],
[
"市场部",
9
],
[
"研发部",
5
],
[
"财务部",
6
],
[
"销售部",
10
]
],
"row_count": 5,
"query_latency_s": 0.0007,
"expected": [
[
"研发部",
5
],
[
"销售部",
10
],
[
"人力资源部",
4
],
[
"市场部",
9
],
[
"财务部",
6
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 3,
"question": "哪个部门员工平均级别最高?",
"sql": "SELECT department\nFROM employees\nGROUP BY department\nORDER BY AVG(level) DESC\nLIMIT 1",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT department\nFROM employees\nGROUP BY department\nORDER BY AVG(level) DESC\nLIMIT 1",
"query_latency_s": 0.0008,
"execution_error": null
}
],
"rows": [
[
"销售部"
]
],
"row_count": 1,
"query_latency_s": 0.0008,
"expected": [
[
"销售部"
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 4,
"question": "每个部门今年和去年各新入职多少人?",
"sql": "SELECT department,\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS \"this-year count\",\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS \"last-year count\"\nFROM employees\nGROUP BY department\nHAVING COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) > 0\n OR COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) > 0",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT department,\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS \"this-year count\",\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS \"last-year count\"\nFROM employees\nGROUP BY department\nHAVING COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) > 0\n OR COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) > 0",
"query_latency_s": 0.0008,
"execution_error": null
}
],
"rows": [
[
"财务部",
0,
1
],
[
"销售部",
2,
1
],
[
"人力资源部",
2,
0
],
[
"研发部",
1,
2
],
[
"市场部",
0,
4
]
],
"row_count": 5,
"query_latency_s": 0.0008,
"expected": [
[
"研发部",
1,
2
],
[
"销售部",
2,
1
],
[
"人力资源部",
2,
0
],
[
"市场部",
0,
4
],
[
"财务部",
0,
1
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 5,
"question": "前年3月到去年5月,A部门平均工资是多少?",
"sql": "SELECT AVG(s.salary)\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE e.department = '研发部'\n AND s.pay_date BETWEEN make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 2, 3, 1)\n AND make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 1, 5, 31)",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT AVG(s.salary)\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE e.department = '研发部'\n AND s.pay_date BETWEEN make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 2, 3, 1)\n AND make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 1, 5, 31)",
"query_latency_s": 0.0021,
"execution_error": null
}
],
"rows": [
[
27695.833333333332
]
],
"row_count": 1,
"query_latency_s": 0.0021,
"expected": [
[
27695.83
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 6,
"question": "去年A部门和B部门平均工资哪个高?",
"sql": "SELECT department, AVG(salary) AS average_salary\nFROM employees\nJOIN salaries ON employees.emp_id = salaries.emp_id\nWHERE department IN ('研发部', '销售部')\n AND pay_date >= date_trunc('year', CURRENT_DATE) - INTERVAL '1 year'\n AND pay_date < date_trunc('year', CURRENT_DATE)\nGROUP BY department",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT department, AVG(salary) AS average_salary\nFROM employees\nJOIN salaries ON employees.emp_id = salaries.emp_id\nWHERE department IN ('研发部', '销售部')\n AND pay_date >= date_trunc('year', CURRENT_DATE) - INTERVAL '1 year'\n AND pay_date < date_trunc('year', CURRENT_DATE)\nGROUP BY department",
"query_latency_s": 0.0011,
"execution_error": null
}
],
"rows": [
[
"研发部",
28569.444444444445
],
[
"销售部",
29481.55339805825
]
],
"row_count": 2,
"query_latency_s": 0.0011,
"expected": [
[
"研发部",
28569.44
],
[
"销售部",
29481.55
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 7,
"question": "今年每个级别的员工平均工资是多少?",
"sql": "SELECT e.level, AVG(s.salary) AS average_salary\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE EXTRACT(YEAR FROM s.pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)\nGROUP BY e.level",
"sql_attempts": [
{
"attempt": 1,
"sql": "SELECT e.level, AVG(s.salary) AS average_salary\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE EXTRACT(YEAR FROM s.pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)\nGROUP BY e.level",
"query_latency_s": 0.0014,
"execution_error": null
}
],
"rows": [
[
3,
23456.428571428572
],
[
4,
26248.823529411766
],
[
5,
34534.75
],
[
6,
28461.363636363636
],
[
7,
29935.0
],
[
8,
32242.69230769231
],
[
9,
34559.90566037736
]
],
"row_count": 7,
"query_latency_s": 0.0014,
"expected": [
[
3,
23456.43
],
[
8,
32242.69
],
[
6,
28461.36
],
[
4,
26248.82
],
[
9,
34559.91
],
[
5,
34534.75
],
[
7,
29935
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 8,
"question": "入职一年内、一到两年、两到三年的员工,最近一个月平均工资是多少?",
"sql": "WITH latest_salaries AS (\n SELECT DISTINCT ON (emp_id) emp_id, salary\n FROM salaries\n ORDER BY emp_id, pay_date DESC\n)\nSELECT \n CASE \n WHEN (CURRENT_DATE - e.hire_date)::INTEGER < 365 THEN '入职一年内'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 365 AND 729 THEN '一到两年'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 730 AND 1094 THEN '两到三年'\n END AS bucket,\n AVG(ls.salary) AS average_latest_salary\nFROM employees e\nJOIN latest_salaries ls ON e.emp_id = ls.emp_id\nWHERE e.leave_date IS NULL\n AND (CURRENT_DATE - e.hire_date)::INTEGER < 1095\nGROUP BY bucket\nORDER BY bucket",
"sql_attempts": [
{
"attempt": 1,
"sql": "WITH latest_salaries AS (\n SELECT DISTINCT ON (emp_id) emp_id, salary\n FROM salaries\n ORDER BY emp_id, pay_date DESC\n)\nSELECT \n CASE \n WHEN (CURRENT_DATE - e.hire_date)::INTEGER < 365 THEN '入职一年内'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 365 AND 729 THEN '一到两年'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 730 AND 1094 THEN '两到三年'\n END AS bucket,\n AVG(ls.salary) AS average_latest_salary\nFROM employees e\nJOIN latest_salaries ls ON e.emp_id = ls.emp_id\nWHERE e.leave_date IS NULL\n AND (CURRENT_DATE - e.hire_date)::INTEGER < 1095\nGROUP BY bucket\nORDER BY bucket",
"query_latency_s": 0.0015,
"execution_error": null
}
],
"rows": [
[
"一到两年",
27683.125
],
[
"两到三年",
31138.75
],
[
"入职一年内",
24053.75
]
],
"row_count": 3,
"query_latency_s": 0.0015,
"expected": [
[
"入职一年内",
24053.75
],
[
"一到两年",
27683.12
],
[
"两到三年",
31138.75
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 9,
"question": "去年到今年涨薪幅度最大的10位员工是谁?",
"sql": "WITH emp_salary_avg AS (\n SELECT \n emp_id,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS current_avg,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS previous_avg\n FROM salaries\n GROUP BY emp_id\n HAVING \n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) IS NOT NULL\n AND AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) IS NOT NULL\n)\nSELECT \n e.name,\n (esa.current_avg - esa.previous_avg) AS raise_amount\nFROM emp_salary_avg esa\nJOIN employees e ON esa.emp_id = e.emp_id\nORDER BY raise_amount DESC\nLIMIT 10",
"sql_attempts": [
{
"attempt": 1,
"sql": "WITH emp_salary_avg AS (\n SELECT \n emp_id,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS current_avg,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS previous_avg\n FROM salaries\n GROUP BY emp_id\n HAVING \n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) IS NOT NULL\n AND AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) IS NOT NULL\n)\nSELECT \n e.name,\n (esa.current_avg - esa.previous_avg) AS raise_amount\nFROM emp_salary_avg esa\nJOIN employees e ON esa.emp_id = e.emp_id\nORDER BY raise_amount DESC\nLIMIT 10",
"query_latency_s": 0.0018,
"execution_error": null
}
],
"rows": [
[
"韩平",
12000.0
],
[
"韩伟",
2200.0
],
[
"吕芳",
2155.0
],
[
"金丽",
2110.0
],
[
"许华",
2065.0
],
[
"陶松",
1975.0
],
[
"周雪",
1930.0
],
[
"吴敏",
1885.0
],
[
"张霞",
1840.0
],
[
"赵平",
1795.0
]
],
"row_count": 10,
"query_latency_s": 0.0018,
"expected": [
[
"韩平",
12000
],
[
"韩伟",
2200
],
[
"吕芳",
2155
],
[
"金丽",
2110
],
[
"许华",
2065
],
[
"陶松",
1975
],
[
"周雪",
1930
],
[
"吴敏",
1885
],
[
"张霞",
1840
],
[
"赵平",
1795
]
],
"passed": true,
"comparison": "independent Python reference matched"
},
{
"id": 10,
"question": "有没有拖欠工资的情况(某个月还在职却没有发薪)?",
"sql": "WITH employee_employed_months AS (\n SELECT \n e.emp_id,\n generate_series(\n date_trunc('month', e.hire_date),\n date_trunc('month', COALESCE(e.leave_date, CURRENT_DATE)),\n interval '1 month'\n ) AS employed_month\n FROM employees e\n)\nSELECT \n em.emp_id,\n to_char(em.employed_month, 'YYYY-MM') AS month\nFROM employee_employed_months em\nLEFT JOIN salaries s \n ON em.emp_id = s.emp_id \n AND date_trunc('month', s.pay_date) = em.employed_month\nWHERE s.emp_id IS NULL",
"sql_attempts": [
{
"attempt": 1,
"sql": "WITH employee_employed_months AS (\n SELECT \n e.emp_id,\n generate_series(\n date_trunc('month', e.hire_date),\n date_trunc('month', COALESCE(e.leave_date, CURRENT_DATE)),\n interval '1 month'\n ) AS employed_month\n FROM employees e\n)\nSELECT \n em.emp_id,\n to_char(em.employed_month, 'YYYY-MM') AS month\nFROM employee_employed_months em\nLEFT JOIN salaries s \n ON em.emp_id = s.emp_id \n AND date_trunc('month', s.pay_date) = em.employed_month\nWHERE s.emp_id IS NULL",
"query_latency_s": 0.0122,
"execution_error": null
}
],
"rows": [
[
17,
"2026-01"
]
],
"row_count": 1,
"query_latency_s": 0.0122,
"expected": [
[
17,
"2026-01"
]
],
"passed": true,
"comparison": "independent Python reference matched"
}
]
@@ -0,0 +1,332 @@
[
{
"question_id": 1,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:03:45.098657+00:00",
"latency_s": 10.894,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 平均每个员工在职多久?\nPostgreSQL guidance: Use COALESCE(leave_date, CURRENT_DATE) - hire_date to obtain integer days, then AVG. Return one numeric column."
}
],
"temperature": 0
},
"response": {
"id": "021785359014553b2d574b8a133720ef9fae8eba78adee9444980",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "SELECT AVG(COALESCE(leave_date, CURRENT_DATE) - hire_date) AS average_tenure_days FROM employees;"
},
"usage": {
"prompt_tokens": 299,
"completion_tokens": 500,
"total_tokens": 799,
"cached_prompt_tokens": 0
}
},
{
"question_id": 2,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:03:55.131184+00:00",
"latency_s": 10.031,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 每个部门有多少在职员工?\nPostgreSQL guidance: Active means leave_date IS NULL. GROUP BY department. Return department and active count."
}
],
"temperature": 0
},
"response": {
"id": "021785359025290b2d574b8a133720ef9fae8eba78adee91ab80e",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "SELECT department, COUNT(emp_id) AS active_count FROM employees WHERE leave_date IS NULL GROUP BY department;"
},
"usage": {
"prompt_tokens": 288,
"completion_tokens": 379,
"total_tokens": 667,
"cached_prompt_tokens": 0
}
},
{
"question_id": 3,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:04:02.665976+00:00",
"latency_s": 7.534,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 哪个部门员工平均级别最高?\nPostgreSQL guidance: Average level across all employees by department; ORDER BY the average descending and LIMIT 1. Return department only."
}
],
"temperature": 0
},
"response": {
"id": "021785359035323b2d574b8a133720ef9fae8eba78adee9cba0b8",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "SELECT department\nFROM employees\nGROUP BY department\nORDER BY AVG(level) DESC\nLIMIT 1;"
},
"usage": {
"prompt_tokens": 293,
"completion_tokens": 371,
"total_tokens": 664,
"cached_prompt_tokens": 0
}
},
{
"question_id": 4,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:04:20.434412+00:00",
"latency_s": 17.767,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 每个部门今年和去年各新入职多少人?\nPostgreSQL guidance: Use COUNT(*) FILTER with EXTRACT(YEAR FROM hire_date) for current and previous years. Return department, this-year count, last-year count; omit departments with both zero."
}
],
"temperature": 0
},
"response": {
"id": "021785359042857b2d574b8a133720ef9fae8eba78adee9e96329",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "SELECT department,\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS \"this-year count\",\n COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS \"last-year count\"\nFROM employees\nGROUP BY department\nHAVING COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) > 0\n OR COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) > 0;"
},
"usage": {
"prompt_tokens": 312,
"completion_tokens": 749,
"total_tokens": 1061,
"cached_prompt_tokens": 0
}
},
{
"question_id": 5,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:04:48.475419+00:00",
"latency_s": 28.04,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 前年3月到去年5月,A部门平均工资是多少?\nPostgreSQL guidance: A=研发部. Inclusive dates are March 1 two years ago through May 31 last year; derive years from CURRENT_DATE with make_date, never literals. Return AVG(salary)."
}
],
"temperature": 0
},
"response": {
"id": "021785359060627b2d574b8a133720ef9fae8eba78adee9eb2c59",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "SELECT AVG(s.salary)\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE e.department = '研发部'\n AND s.pay_date BETWEEN make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 2, 3, 1)\n AND make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 1, 5, 31);"
},
"usage": {
"prompt_tokens": 322,
"completion_tokens": 1337,
"total_tokens": 1659,
"cached_prompt_tokens": 0
}
},
{
"question_id": 6,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:05:15.145844+00:00",
"latency_s": 26.668,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 去年A部门和B部门平均工资哪个高?\nPostgreSQL guidance: A=研发部 and B=销售部. Join employees to salaries; filter pay_date to previous calendar year, group by department, and return department plus average salary for exactly those two departments."
}
],
"temperature": 0
},
"response": {
"id": "021785359088668b2d574b8a133720ef9fae8eba78adee96ff8e8",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "SELECT department, AVG(salary) AS average_salary\nFROM employees\nJOIN salaries ON employees.emp_id = salaries.emp_id\nWHERE department IN ('研发部', '销售部')\n AND pay_date >= date_trunc('year', CURRENT_DATE) - INTERVAL '1 year'\n AND pay_date < date_trunc('year', CURRENT_DATE)\nGROUP BY department;"
},
"usage": {
"prompt_tokens": 314,
"completion_tokens": 1093,
"total_tokens": 1407,
"cached_prompt_tokens": 0
}
},
{
"question_id": 7,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:05:25.677375+00:00",
"latency_s": 10.53,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 今年每个级别的员工平均工资是多少?\nPostgreSQL guidance: Join salary rows to employees, filter pay_date to current calendar year, group by level. Return level and average salary."
}
],
"temperature": 0
},
"response": {
"id": "021785359115339b2d574b8a133720ef9fae8eba78adee94ab7c5",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "SELECT e.level, AVG(s.salary) AS average_salary\nFROM employees e\nJOIN salaries s ON e.emp_id = s.emp_id\nWHERE EXTRACT(YEAR FROM s.pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)\nGROUP BY e.level;"
},
"usage": {
"prompt_tokens": 298,
"completion_tokens": 408,
"total_tokens": 706,
"cached_prompt_tokens": 0
}
},
{
"question_id": 8,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:05:54.537092+00:00",
"latency_s": 28.857,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 入职一年内、一到两年、两到三年的员工,最近一个月平均工资是多少?\nPostgreSQL guidance: First select each employee's latest salary with DISTINCT ON (emp_id) ordered by pay_date DESC. Bucket CURRENT_DATE-hire_date as <365 入职一年内, 365..729 一到两年, 730..1094 两到三年; exclude older. Return bucket and average latest salary."
}
],
"temperature": 0
},
"response": {
"id": "021785359125871b2d574b8a133720ef9fae8eba78adee9b33ba5",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "WITH latest_salaries AS (\n SELECT DISTINCT ON (emp_id) emp_id, salary\n FROM salaries\n ORDER BY emp_id, pay_date DESC\n)\nSELECT \n CASE \n WHEN (CURRENT_DATE - e.hire_date)::INTEGER < 365 THEN '入职一年内'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 365 AND 729 THEN '一到两年'\n WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 730 AND 1094 THEN '两到三年'\n END AS bucket,\n AVG(ls.salary) AS average_latest_salary\nFROM employees e\nJOIN latest_salaries ls ON e.emp_id = ls.emp_id\nWHERE e.leave_date IS NULL\n AND (CURRENT_DATE - e.hire_date)::INTEGER < 1095\nGROUP BY bucket\nORDER BY bucket;"
},
"usage": {
"prompt_tokens": 360,
"completion_tokens": 1364,
"total_tokens": 1724,
"cached_prompt_tokens": 0
}
},
{
"question_id": 9,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:06:19.333907+00:00",
"latency_s": 24.794,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 去年到今年涨薪幅度最大的10位员工是谁?\nPostgreSQL guidance: Aggregate each employee's average salary separately for current and previous calendar years with FILTER, keep employees having both, compute current minus previous, order descending, LIMIT 10. Return name and raise amount."
}
],
"temperature": 0
},
"response": {
"id": "021785359154731b2d574b8a133720ef9fae8eba78adee94f6e87",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "WITH emp_salary_avg AS (\n SELECT \n emp_id,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS current_avg,\n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS previous_avg\n FROM salaries\n GROUP BY emp_id\n HAVING \n AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) IS NOT NULL\n AND AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) IS NOT NULL\n)\nSELECT \n e.name,\n (esa.current_avg - esa.previous_avg) AS raise_amount\nFROM emp_salary_avg esa\nJOIN employees e ON esa.emp_id = e.emp_id\nORDER BY raise_amount DESC\nLIMIT 10;"
},
"usage": {
"prompt_tokens": 320,
"completion_tokens": 1101,
"total_tokens": 1421,
"cached_prompt_tokens": 0
}
},
{
"question_id": 10,
"purpose": "initial_sql_generation",
"attempt": 1,
"called_at_utc": "2026-07-29T21:06:41.951264+00:00",
"latency_s": 22.615,
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "system",
"content": "You are an ERP natural-language-to-SQL Agent. Output exactly one read-only\nPostgreSQL SELECT statement (WITH/CTE is allowed), with no Markdown or prose.\n\nSchema:\nemployees(emp_id INTEGER PRIMARY KEY, name TEXT, department TEXT, level INTEGER,\n hire_date DATE, leave_date DATE NULL)\nsalaries(emp_id INTEGER REFERENCES employees, pay_date DATE, salary INTEGER,\n PRIMARY KEY(emp_id,pay_date))\n\nBusiness meanings: leave_date NULL means active; A department is 研发部; B is 销售部.\nUse CURRENT_DATE for all relative dates. Never hard-code a calendar year. Follow the\nrequested output columns exactly. You write only the SQL artifact: you do not see,\ncopy, summarize, or calculate over result rows."
},
{
"role": "user",
"content": "Question: 有没有拖欠工资的情况(某个月还在职却没有发薪)?\nPostgreSQL guidance: For every employee generate each employed month with LATERAL generate_series(date_trunc('month', hire_date), date_trunc('month', COALESCE(leave_date,CURRENT_DATE)), interval '1 month'); left join salaries by emp_id and month. Return missing emp_id and to_char(month,'YYYY-MM')."
}
],
"temperature": 0
},
"response": {
"id": "021785359179526b2d574b8a133720ef9fae8eba78adee94328f6",
"model": "doubao-seed-1-6-250615",
"finish_reason": "stop",
"content": "WITH employee_employed_months AS (\n SELECT \n e.emp_id,\n generate_series(\n date_trunc('month', e.hire_date),\n date_trunc('month', COALESCE(e.leave_date, CURRENT_DATE)),\n interval '1 month'\n ) AS employed_month\n FROM employees e\n)\nSELECT \n em.emp_id,\n to_char(em.employed_month, 'YYYY-MM') AS month\nFROM employee_employed_months em\nLEFT JOIN salaries s \n ON em.emp_id = s.emp_id \n AND date_trunc('month', s.pay_date) = em.employed_month\nWHERE s.emp_id IS NULL;"
},
"usage": {
"prompt_tokens": 348,
"completion_tokens": 890,
"total_tokens": 1238,
"cached_prompt_tokens": 0
}
}
]
@@ -0,0 +1,79 @@
<!doctype html><meta charset=utf-8><title>Experiment 5-10 PostgreSQL artifacts</title>
<style>body{font-family:system-ui;margin:30px;background:#f7f8fa;color:#172033}section{background:white;padding:18px;margin:16px 0;border-radius:12px}table{border-collapse:collapse}td{border:1px solid #ccd3dd;padding:5px 9px}pre{white-space:pre-wrap;background:#eef2f7;padding:12px}.ok{color:#08783e}.bad{color:#b42318}</style>
<h1>ERP Agent: SQL artifacts executed by PostgreSQL</h1><section><h2>1. 平均每个员工在职多久?</h2><pre>SELECT AVG(COALESCE(leave_date, CURRENT_DATE) - hire_date) AS average_tenure_days FROM employees</pre><table><tr><td>886.2</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>2. 每个部门有多少在职员工?</h2><pre>SELECT department, COUNT(emp_id) AS active_count FROM employees WHERE leave_date IS NULL GROUP BY department</pre><table><tr><td>人力资源部</td><td>4</td></tr><tr><td>市场部</td><td>9</td></tr><tr><td>研发部</td><td>5</td></tr><tr><td>财务部</td><td>6</td></tr><tr><td>销售部</td><td>10</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>3. 哪个部门员工平均级别最高?</h2><pre>SELECT department
FROM employees
GROUP BY department
ORDER BY AVG(level) DESC
LIMIT 1</pre><table><tr><td>销售部</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>4. 每个部门今年和去年各新入职多少人?</h2><pre>SELECT department,
COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS &quot;this-year count&quot;,
COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS &quot;last-year count&quot;
FROM employees
GROUP BY department
HAVING COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE)) &gt; 0
OR COUNT(*) FILTER (WHERE EXTRACT(YEAR FROM hire_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) &gt; 0</pre><table><tr><td>财务部</td><td>0</td><td>1</td></tr><tr><td>销售部</td><td>2</td><td>1</td></tr><tr><td>人力资源部</td><td>2</td><td>0</td></tr><tr><td>研发部</td><td>1</td><td>2</td></tr><tr><td>市场部</td><td>0</td><td>4</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>5. 前年3月到去年5月,A部门平均工资是多少?</h2><pre>SELECT AVG(s.salary)
FROM employees e
JOIN salaries s ON e.emp_id = s.emp_id
WHERE e.department = &#x27;研发部&#x27;
AND s.pay_date BETWEEN make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 2, 3, 1)
AND make_date(EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER - 1, 5, 31)</pre><table><tr><td>27695.833333333332</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>6. 去年A部门和B部门平均工资哪个高?</h2><pre>SELECT department, AVG(salary) AS average_salary
FROM employees
JOIN salaries ON employees.emp_id = salaries.emp_id
WHERE department IN (&#x27;研发部&#x27;, &#x27;销售部&#x27;)
AND pay_date &gt;= date_trunc(&#x27;year&#x27;, CURRENT_DATE) - INTERVAL &#x27;1 year&#x27;
AND pay_date &lt; date_trunc(&#x27;year&#x27;, CURRENT_DATE)
GROUP BY department</pre><table><tr><td>研发部</td><td>28569.444444444445</td></tr><tr><td>销售部</td><td>29481.55339805825</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>7. 今年每个级别的员工平均工资是多少?</h2><pre>SELECT e.level, AVG(s.salary) AS average_salary
FROM employees e
JOIN salaries s ON e.emp_id = s.emp_id
WHERE EXTRACT(YEAR FROM s.pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)
GROUP BY e.level</pre><table><tr><td>3</td><td>23456.428571428572</td></tr><tr><td>4</td><td>26248.823529411766</td></tr><tr><td>5</td><td>34534.75</td></tr><tr><td>6</td><td>28461.363636363636</td></tr><tr><td>7</td><td>29935.0</td></tr><tr><td>8</td><td>32242.69230769231</td></tr><tr><td>9</td><td>34559.90566037736</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>8. 入职一年内、一到两年、两到三年的员工,最近一个月平均工资是多少?</h2><pre>WITH latest_salaries AS (
SELECT DISTINCT ON (emp_id) emp_id, salary
FROM salaries
ORDER BY emp_id, pay_date DESC
)
SELECT
CASE
WHEN (CURRENT_DATE - e.hire_date)::INTEGER &lt; 365 THEN &#x27;入职一年内&#x27;
WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 365 AND 729 THEN &#x27;一到两年&#x27;
WHEN (CURRENT_DATE - e.hire_date)::INTEGER BETWEEN 730 AND 1094 THEN &#x27;两到三年&#x27;
END AS bucket,
AVG(ls.salary) AS average_latest_salary
FROM employees e
JOIN latest_salaries ls ON e.emp_id = ls.emp_id
WHERE e.leave_date IS NULL
AND (CURRENT_DATE - e.hire_date)::INTEGER &lt; 1095
GROUP BY bucket
ORDER BY bucket</pre><table><tr><td>一到两年</td><td>27683.125</td></tr><tr><td>两到三年</td><td>31138.75</td></tr><tr><td>入职一年内</td><td>24053.75</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>9. 去年到今年涨薪幅度最大的10位员工是谁?</h2><pre>WITH emp_salary_avg AS (
SELECT
emp_id,
AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) AS current_avg,
AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) AS previous_avg
FROM salaries
GROUP BY emp_id
HAVING
AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE)) IS NOT NULL
AND AVG(salary) FILTER (WHERE EXTRACT(YEAR FROM pay_date) = EXTRACT(YEAR FROM CURRENT_DATE) - 1) IS NOT NULL
)
SELECT
e.name,
(esa.current_avg - esa.previous_avg) AS raise_amount
FROM emp_salary_avg esa
JOIN employees e ON esa.emp_id = e.emp_id
ORDER BY raise_amount DESC
LIMIT 10</pre><table><tr><td>韩平</td><td>12000.0</td></tr><tr><td>韩伟</td><td>2200.0</td></tr><tr><td>吕芳</td><td>2155.0</td></tr><tr><td>金丽</td><td>2110.0</td></tr><tr><td>许华</td><td>2065.0</td></tr><tr><td>陶松</td><td>1975.0</td></tr><tr><td>周雪</td><td>1930.0</td></tr><tr><td>吴敏</td><td>1885.0</td></tr><tr><td>张霞</td><td>1840.0</td></tr><tr><td>赵平</td><td>1795.0</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section><section><h2>10. 有没有拖欠工资的情况(某个月还在职却没有发薪)?</h2><pre>WITH employee_employed_months AS (
SELECT
e.emp_id,
generate_series(
date_trunc(&#x27;month&#x27;, e.hire_date),
date_trunc(&#x27;month&#x27;, COALESCE(e.leave_date, CURRENT_DATE)),
interval &#x27;1 month&#x27;
) AS employed_month
FROM employees e
)
SELECT
em.emp_id,
to_char(em.employed_month, &#x27;YYYY-MM&#x27;) AS month
FROM employee_employed_months em
LEFT JOIN salaries s
ON em.emp_id = s.emp_id
AND date_trunc(&#x27;month&#x27;, s.pay_date) = em.employed_month
WHERE s.emp_id IS NULL</pre><table><tr><td>17</td><td>2026-01</td></tr></table><p class=ok>PASS: independent Python reference matched</p></section>
Binary file not shown.

After

Width:  |  Height:  |  Size: 578 KiB

@@ -0,0 +1,34 @@
-- 实验 5-10 ERP Agent —— 书中要求的 PostgreSQL schema(两张表)。
--
-- 本仓库的可运行演示用 SQLite(零依赖、可离线复现,见 seed.py / demo.py);
-- 这份 DDL 给出书中原文的 PostgreSQL 版本,方便迁移到真实 Postgres 环境。
-- 两种方言的表结构一致,差异主要在日期函数:
-- SQLite: strftime('%Y','now') julianday(a)-julianday(b) date('now','-1 year')
-- PostgreSQL: EXTRACT(YEAR FROM now()) (a::date - b::date) now() - interval '1 year'
--
-- 用法(需本机有 PostgreSQL):
-- createdb erp
-- psql erp -f schema_postgres.sql
DROP TABLE IF EXISTS salaries;
DROP TABLE IF EXISTS employees;
-- 员工表:ID、姓名、部门、级别(数字越大越高)、入职日期、离职日期(NULL = 在职)
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
department TEXT NOT NULL,
level INTEGER NOT NULL,
hire_date DATE NOT NULL,
leave_date DATE -- NULL 表示在职
);
-- 工资表:员工ID、发薪日期(每月一条,取当月 1 号)、当月工资
CREATE TABLE salaries (
emp_id INTEGER NOT NULL REFERENCES employees(emp_id),
pay_date DATE NOT NULL, -- 每月一条,如 2025-03-01
salary INTEGER NOT NULL,
PRIMARY KEY (emp_id, pay_date)
);
CREATE INDEX idx_salaries_pay_date ON salaries (pay_date);