【发布时间】:2021-07-13 00:31:53
【问题描述】:
在 SQL Server 2016 中,我有一个如下所示的表:
dbo.jobs
| id | name |
|---|---|
| 0 | First Job |
| 1 | Second Job |
dbo.tasks
| id | start_date | end_date |
|---|---|---|
| 0 | 2017-04-01 | 2017-04-3 |
| 1 | 2017-04-02 | 2017-04-4 |
| 2 | 2017-04-03 | null |
dbo.job_tasks
| id | job_id | task_id |
|---|---|---|
| 0 | 0 | 0 |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
我正在尝试做的是创建一个包含作业的视图,其中任务的最低开始日期和最高结束日期反映了作业的开始和结束日期。这相对容易,在视图中查询如下:
SELECT
jobs.id,
jobs.name,
MIN(tasks.start_date) as job_start_date,
MAX(task.end_date) as job_end_date,
FROM
jobs
LEFT OUTER JOIN job_tasks on jobs.id = job_tasks.job_id
LEFT OUTER JOIN tasks on job_tasks.task_id = tasks.task_id
GROUP BY jobs.id, jobs.name, job_tasks.job_id, job_tasks.task_id, tasks.task_id
结果如下:
| id | name | job_start_date | job_end_date |
|---|---|---|---|
| 0 | First Job | 2017-04-01 | 2017-04-3 |
| 1 | Second Job | 2017-04-02 | 2017-04-4 |
但是,如果有一个任务的 end_date 为空,例如“第二个作业”,则该任务未完成 - 所以 job_end_date 实际上应该为空,正确的输出应该是这样的:
| id | name | job_start_date | job_end_date |
|---|---|---|---|
| 0 | First Job | 2017-04-01 | 2017-04-3 |
| 1 | Second Job | 2017-04-02 | null |
所有聚合函数都忽略 null,但 COUNT() 除外。所以,我现在的想法是使用表值函数,并传入job_id。这将限制正在处理的数据的范围,并允许我检查空结束日期并使用 CASE 语句进行相应调整。像这样的:
DECLARE @completed bit
SET @completed = 1
IF EXISTS(
SELECT * FROM job_tasks
INNER JOIN tasks on tasks.task_id = job_tasks.task_id AND tasks.end_date IS NULL
WHERE job_tasks.task_id = @taskId
)
BEGIN
SET @completed = 0
END
SELECT
jobs.id,
jobs.name,
MIN(tasks.start_date) as job_start_date,
CASE WHEN @completed = 0 THEN NULL
ELSE (MAX(tasks.end_date)) END AS job_end_date
FROM
jobs
... joins and group by clause
WHERE jobs.id = @jobId
是否有更好的方法来获取这种数据视图?也许是一种在不完全影响性能的情况下保留视图的方法?
任何建议将不胜感激。
(省略了视图和函数样板)
【问题讨论】:
标签: sql sql-server tsql aggregate-functions sql-view