关联表查询需求:获取主表单行数据及聚合/关联字段值
表结构
table1
| 字段名 |
|---|
| tasknum |
| description |
| refid |
| sysdesc |
table2
| 字段名 |
|---|
| tasknum |
| stepno |
| stepdetail |
| approvaldate |
table3
现有SQL代码
SELECT
t1.tasknum
, t1.description
, t1.refid
, t1.sysdesc
, t2.stepno
, t2.stepdetail
, t2.approvaldate
, MIN(t3.startdate) AS min_date1
, MIN(t3.enddate) AS min_date2
FROM TABLE1 t1
LEFT OUTER JOIN TABLE2 t2 ON t1.tasknum = t2.tasknum
AND t2.stepno = (
SELECT MIN(stepno)
FROM TABLE2
WHERE tasknum = t2.tasknum
)
LEFT OUTER JOIN TABLE3 t3 ON t1.refid = t3.id
WHERE t1.sysdesc LIKE 'Apple'
GROUP BY
t1.tasknum
, t1.description
, t1.refid
, t1.sysdesc
, t2.stepno
, t2.stepdetail
, t2.approvaldate
表数据
table1
| tasknum | description | refid | sysdesc |
|---|
| 1 | Australia | 1 | Apple |
| 2 | India | 2 | Apple |
| 3 | West Indies | 3 | Orange |
| 4 | Cambodia | 4 | Apple |
table2
| tasknum | stepno | stepdetail | approvaldate |
|---|
| 1 | 10 | Start | 1-Apr |
| 1 | 20 | Review | 2-Apr |
| 1 | 30 | In Work | 5-Apr |
| 1 | 40 | Release | |
| 1 | 50 | Close | |
| 2 | 10 | Start | 1-Apr |
| 2 | 20 | Review | |
| 2 | 30 | In Work | |
| 2 | 40 | Release | |
| 2 | 50 | Close | |
table3
| id | startdate | enddate |
|---|
| 1 | 3/8/2025 | 4/9/2025 |
| 1 | 3/9/2025 | 4/5/2025 |
| 1 | 3/10/2025 | 4/9/2025 |
| 2 | 3/11/2025 | 4/12/2025 |
| 3 | 3/12/2025 | 4/13/2025 |
| 3 | 3/13/2025 | 4/12/2025 |
查询条件
- 筛选table1中sysdesc为'Apple'的所有记录;
- 获取每个tasknum对应的无approvaldate的最小stepno及stepdetail;
- 获取每个tasknum对应的有approvaldate的最大step相关信息;
- 获取每个id对应的最小startdate和enddate。
期望输出样例(tasknum=1)
| tasknum | description | refid | sysdesc | stepno | stepdetail | approvaldate | startdate | enddate |
|---|
| 1 | Australia | 1 | Apple | 40 | Release | 5-Apr | 3/8/2025 | 4/5/2025 |
问题说明
现有SQL仅能获取全局最小stepno的记录,无法满足条件2(无审批日期的最小stepno)和条件3(有审批日期的最大step)的需求,需调整查询逻辑。
修正后的SQL
WITH step_data AS (
-- 提取每个tasknum的两类关键step数据
SELECT
tasknum,
-- 无审批日期的最小stepno及对应详情
MIN(CASE WHEN approvaldate IS NULL THEN stepno END) AS min_null_approval_stepno,
MAX(CASE WHEN stepno = MIN(CASE WHEN approvaldate IS NULL THEN stepno END) THEN stepdetail END) AS min_null_approval_stepdetail,
-- 有审批日期的最大step相关信息
MAX(CASE WHEN approvaldate IS NOT NULL THEN stepno END) AS max_approval_stepno,
MAX(CASE WHEN stepno = MAX(CASE WHEN approvaldate IS NOT NULL THEN stepno END) THEN stepdetail END) AS max_approval_stepdetail,
MAX(CASE WHEN stepno = MAX(CASE WHEN approvaldate IS NOT NULL THEN stepno END) THEN approvaldate END) AS max_approval_date
FROM table2
GROUP BY tasknum
),
date_data AS (
-- 聚合每个id的最小日期数据
SELECT
id,
MIN(startdate) AS min_startdate,
MIN(enddate) AS min_enddate
FROM table3
GROUP BY id
)
SELECT
t1.tasknum,
t1.description,
t1.refid,
t1.sysdesc,
s.min_null_approval_stepno AS stepno,
s.min_null_approval_stepdetail AS stepdetail,
s.max_approval_date AS approvaldate,
d.min_startdate AS startdate,
d.min_enddate AS enddate
FROM table1 t1
LEFT JOIN step_data s ON t1.tasknum = s.tasknum
LEFT JOIN date_data d ON t1.refid = d.id
WHERE t1.sysdesc = 'Apple';
逻辑说明
- step_data CTE:通过条件聚合分别提取每个tasknum下无审批日期的最小stepno及对应详情,还有有审批日期的最大step的详情和审批日期;
- date_data CTE:聚合获取每个id对应的最小startdate和enddate;
- 主查询将table1与两个CTE关联,筛选sysdesc为'Apple'的记录,得到符合要求的单行结果。
内容的提问来源于stack exchange,提问作者NewBie