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 

这也可以在没有子选择的情况下完成,但它更难读写...