MAX(),但前提是所有值都不为空
MAX(), but only if all values are not null
在 SQL Server 2016 中,我有一个 table 看起来像这样:
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 实际上应该是null,正确的输出应该是这样的:
id
name
job_start_date
job_end_date
0
First Job
2017-04-01
2017-04-3
1
Second Job
2017-04-02
null
除了 COUNT() 之外,所有聚合函数都忽略 null。所以,我现在的想法是使用一个 table 值函数,并传入 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
是否有更好的方法来获取此数据视图?也许是一种在不完全影响性能的情况下保持视野的方法?
如有任何建议,我们将不胜感激。
(省略了视图和函数样板)
您可以使用 case
表达式:
SELECT jobs.id, jobs.name,
MIN(tasks.start_date) as job_start_date,
(CASE WHEN COUNT(task.end_date) = COUNT(*)
THEN MAX(task.end_date)
END) as job_end_date
您可以使用 COALESCE 和一个大日期和一个案例将其转换回 null,例如
SELECT id, name, job_start_date,
(CASE WHEN job_end_date <> {d '2100-01-01'}
THEN job_end_date
END) as job_end_date
FROM
(SELECT
jobs.id,
jobs.name,
MIN(tasks.start_date) as job_start_date,
MAX(COALESCE(task.end_date,{d '2100-01-01'} )) 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) A
这也可以在没有子选择的情况下完成,但它更难读写...
在 SQL Server 2016 中,我有一个 table 看起来像这样:
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 实际上应该是null,正确的输出应该是这样的:
id | name | job_start_date | job_end_date |
---|---|---|---|
0 | First Job | 2017-04-01 | 2017-04-3 |
1 | Second Job | 2017-04-02 | null |
除了 COUNT() 之外,所有聚合函数都忽略 null。所以,我现在的想法是使用一个 table 值函数,并传入 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
是否有更好的方法来获取此数据视图?也许是一种在不完全影响性能的情况下保持视野的方法?
如有任何建议,我们将不胜感激。
(省略了视图和函数样板)
您可以使用 case
表达式:
SELECT jobs.id, jobs.name,
MIN(tasks.start_date) as job_start_date,
(CASE WHEN COUNT(task.end_date) = COUNT(*)
THEN MAX(task.end_date)
END) as job_end_date
您可以使用 COALESCE 和一个大日期和一个案例将其转换回 null,例如
SELECT id, name, job_start_date,
(CASE WHEN job_end_date <> {d '2100-01-01'}
THEN job_end_date
END) as job_end_date
FROM
(SELECT
jobs.id,
jobs.name,
MIN(tasks.start_date) as job_start_date,
MAX(COALESCE(task.end_date,{d '2100-01-01'} )) 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) A
这也可以在没有子选择的情况下完成,但它更难读写...