我需要创建一个包含下一个适用日期的有效数据集。根据某些参数,这将需要在一周的某一天进行,但可能不止一个工作日。为了确保选择下一个日期,我整理了一个嵌套的case语句。
一些示例数据:
Job:
+----+-------------+----------+----------+----------+
| ID | SERV_PERIOD | SERV_SUN | SERV_MON | SERV_TUE |
+----+-------------+----------+----------+----------+
| 1 | W | Y | N | N |
| 2 | W | N | N | Y |
| 3 | W | Y | N | Y |
| 4 | W | N | Y | Y |
| 5 | F | Y | N | N |
| 6 | F | N | N | Y |
| 7 | F | Y | N | Y |
| 8 | F | N | Y | Y |
+----+-------------+----------+----------+----------+
Service:
+----+--------+------------+
| ID | JOB_ID | DATE |
+----+--------+------------+
| 1 | 1 | 2019-24-03 |
| 2 | 2 | 2019-26-03 |
| 3 | 3 | 2019-24-03 |
| 4 | 4 | 2019-26-03 |
| 5 | 5 | 2019-24-03 |
| 6 | 6 | 2019-26-03 |
| 7 | 7 | 2019-24-03 |
| 8 | 8 | 2019-26-03 |
+----+--------+------------+
Desired result: (one NextServiceDate for each Job)
+--------+-------------------------------+
| JOB.ID | NextServiceDate |
+--------+-------------------------------+
| 1 | 2019-31-03 (the next Sunday) |
| 2 | 2019-02-04 (the next Tuesday) |
| 3 | 2019-26-03 (the next Tuesday) |
| 4 | 2019-01-04 (the next Monday) |
| 5 | 2019-07-04 (2 Sundays ahead) |
| 6 | 2019-09-04 (2 Tuesdays ahead) |
| 7 | 2019-02-04 (the next Tuesday) |
| 8 | 2019-08-04 (2 Mondays ahead) |
+--------+-------------------------------+
因为可以使用多个工作日,所以检查其有效性的顺序很重要:如果Job 3首先检查SERV_SUN,则发现星期日有效,因此选择下一个星期日日期,将错过26日星期二。工作可以每周一次或每两周一次的事实增加了额外的复杂性。
不足为奇的是,案例陈述中的以下怪物被认为太深了:
CASE
WHEN J.SERV_PERIOD = 'W' THEN CASE
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 1 THEN CASE
WHEN SERV_MON = Y THEN DATEADD(DD,1,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,2,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,3,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,4,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,5,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,6,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,7,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 2 THEN CASE
WHEN SERV_TUE = Y THEN DATEADD(DD,1,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,2,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,3,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,4,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,5,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,6,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,7,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 3 THEN CASE
WHEN SERV_WED = Y THEN DATEADD(DD,1,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,2,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,3,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,4,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,5,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,6,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,7,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 4 THEN CASE
WHEN SERV_THU = Y THEN DATEADD(DD,1,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,2,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,3,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,4,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,5,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,6,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,7,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 5 THEN CASE
WHEN SERV_FRI = Y THEN DATEADD(DD,1,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,2,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,3,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,4,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,5,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,6,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,7,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 6 THEN CASE
WHEN SERV_SAT = Y THEN DATEADD(DD,1,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,2,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,3,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,4,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,5,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,6,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,7,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 7 THEN CASE
WHEN SERV_SUN = Y THEN DATEADD(DD,1,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,2,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,3,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,4,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,5,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,6,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,7,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN J.SERV_PERIOD = 'F' THEN CASE
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 1 THEN CASE
WHEN SERV_MON = Y THEN DATEADD(DD,8,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,9,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,10,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,11,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,12,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,13,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,14,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 2 THEN CASE
WHEN SERV_TUE = Y THEN DATEADD(DD,8,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,9,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,10,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,11,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,12,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,13,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,14,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 3 THEN CASE
WHEN SERV_WED = Y THEN DATEADD(DD,8,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,9,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,10,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,11,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,12,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,13,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,14,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 4 THEN CASE
WHEN SERV_THU = Y THEN DATEADD(DD,8,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,9,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,10,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,11,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,12,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,13,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,14,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 5 THEN CASE
WHEN SERV_FRI = Y THEN DATEADD(DD,8,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,9,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,10,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,11,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,12,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,13,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,14,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 6 THEN CASE
WHEN SERV_SAT = Y THEN DATEADD(DD,8,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SUN = Y THEN DATEADD(DD,9,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,10,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,11,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,12,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,13,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,14,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN DATEPART(DW,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID)) = 7 THEN CASE
WHEN SERV_SUN = Y THEN DATEADD(DD,8,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_MON = Y THEN DATEADD(DD,9,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_TUE = Y THEN DATEADD(DD,10,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_WED = Y THEN DATEADD(DD,11,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_THU = Y THEN DATEADD(DD,12,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_FRI = Y THEN DATEADD(DD,13,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
WHEN SERV_SAT = Y THEN DATEADD(DD,14,(SELECT MAX(DATE) FROM SERVICE WHERE JOB_ID = J.ID))
END AS NextServiceDate
我必须以不同的顺序浏览SERV_字段,具体取决于最后一次服务执行的工作日,以便避免跳过有效日期。如何避免这个问题?我缺少一种更简单的方法吗?
尽管我的错误与this one相同,但我没有找到一种消除嵌套的方法,就像那里的解决方案一样。
答案 0 :(得分:3)
分解它,构建一些CTE来帮助您达到目标:
declare @Job table (ID int,Serv_Period char(1), Serv_Sun char(1),
Serv_mon char(1), Serv_Tue char(1))
insert into @Job(ID,SERV_PERIOD,SERV_SUN,SERV_MON,SERV_TUE) values
(1,'W','Y','N','N'),
(2,'W','N','N','Y'),
(3,'W','Y','N','Y'),
(4,'W','N','Y','Y')
declare @Service table (ID int, Job_id int, Date date)
insert into @Service(ID,JOB_ID,DATE) values
(1,1,'20190324'),
(2,2,'20190326'),
(3,3,'20190324'),
(4,4,'20190326')
--Desired result:
--+--------+-------------------------------+
--| JOB.ID | NextServiceDate |
--+--------+-------------------------------+
--| 1 | 2019-31-03 (the next Sunday) |
--| 2 | 2019-02-04 (the next Tuesday) |
--| 3 | 2019-26-03 (the next Tuesday) |
--| 4 | 2019-01-04 (the next Monday) |
--+--------+-------------------------------+
;With Recent as (
select Job_ID,MAX(Date) as Recent from @Service group by Job_ID
), Numbers as (
select 1 as n union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6 union all select 7
), Possibles as (
select
Job_ID,DATEADD(day,n,Recent) as PossibleDate
from
Recent r
cross join
Numbers n
--Where clause if it's a real numbers table
)
select
j.ID,
MIN(PossibleDate)
from
@Job j
inner join
Possibles p
on
j.ID = p.Job_id
where
(j.Serv_Sun = 'Y' and DATEPART(weekday,PossibleDate) = DATEPART(weekday,'20150104')) or
(j.Serv_Mon = 'Y' and DATEPART(weekday,PossibleDate) = DATEPART(weekday,'20150105')) or
(j.Serv_Tue = 'Y' and DATEPART(weekday,PossibleDate) = DATEPART(weekday,'20150106'))
group by j.ID
结果:
ID
----------- ----------
1 2019-03-31
2 2019-04-02
3 2019-03-26
4 2019-04-01
那么,我们该怎么办? Recent
仅找到我们的开始日期。 Numbers
为我们提供1到7之间的数字(如果您的系统中有实数表,请跳过该数字)。
PossibleDates
结合起来将这些天加到Recent
中。
然后我们将其加入到工作表中,过滤出所有满足服务条件的行,然后(通过GROUP BY
和MIN
)选择这些日期最早是我们的结果。
最后,我通过比较“已知的良好”日期来过滤工作日。我这样做是为了避免对当前DATEFIRST
设置的依赖。
您可以通过设置多个CTE来扩展此范围,每种服务期限各一个,并根据该期限LEFT JOIN
对其进行分类。
答案 1 :(得分:1)
摆脱重复的子查询:
/* same case with MAX_DATE instead of subquery */
FROM ...
CROSS APPLY (SELECT MAX(DATE) MAX_DATE FROM SERVICE WHERE JOB_ID = J.ID) d
可能的版本
FROM ...
INNER JOIN (SELECT MAX(DATE) MAX_DATE, JOB_ID FROM SERVICE S GROUP BY S.JOB_ID) d
ON D.JOB_ID = J.ID
如果要对单个作业执行此操作-如果要对所有作业都选择版本1,则首选版本2。
根据嵌套案例系统化基本算术:
;WITH cteJobs As (
SELECT
CASE
WHEN SERV_MON = 'Y' THEN 1
WHEN SERV_TUE = 'Y' THEN 2
WHEN SERV_WED = 'Y' THEN 3
WHEN SERV_THU = 'Y' THEN 4
WHEN SERV_FRI = 'Y' THEN 5
WHEN SERV_SAT = 'Y' THEN 6
WHEN SERV_SUN = 'Y' THEN 7
END DW,
*
FROM JOBS J
)
SELECT
CASE
WHEN J.SERV_PERIOD = 'W' THEN
CASE
WHEN DATEPART(DW, d.MAX_DATE) >= j.DW
/* "fill" till the end of week, then add supported DW */
THEN DATEADD(DD, 7 - DATEPART(DW, d.MAX_DATE) + j.DW + 1, d.MAX_DATE)
/* add delta between last date (Mon) and next avail date within this week (Tue) (delta = 1) */
ELSE DATEADD(DD, j.DW - DATEPART(DW, d.MAX_DATE) + 1, d.MAX_DATE)
END
WHEN J.SERV_PERIOD = 'F' THEN
...
END NextServiceDate
FROM cteJobs J
CROSS APPLY (SELECT MAX(DATE) MAX_DATE FROM SERVICE WHERE JOB_ID = J.ID) d
还将SERV_PERIOD转换为数字:
;WITH cteJobs As (
SELECT
CASE
WHEN SERV_MON = 'Y' THEN 1
WHEN SERV_TUE = 'Y' THEN 2
WHEN SERV_WED = 'Y' THEN 3
WHEN SERV_THU = 'Y' THEN 4
WHEN SERV_FRI = 'Y' THEN 5
WHEN SERV_SAT = 'Y' THEN 6
WHEN SERV_SUN = 'Y' THEN 7
END DW,
CASE
WHEN SERV_PERIOD = 'W' THEN 1
WHEN SERV_PERIOD = 'F' THEN 8
END SERV_PERIOD_INC,
*
FROM JOB J
)
SELECT
J.*,
d.MAX_DATE LastServiceDate,
DATEPART(DW, d.MAX_DATE) LastWeekDay,
CASE
/* if no avail date within this week */
WHEN DATEPART(DW, d.MAX_DATE) >= j.DW
THEN DATEADD(DD, 7 - DATEPART(DW, d.MAX_DATE) + j.DW + J.SERV_PERIOD_INC, d.MAX_DATE)
ELSE DATEADD(DD, j.DW - DATEPART(DW, d.MAX_DATE) + J.SERV_PERIOD_INC, d.MAX_DATE)
END NextServiceDate,
DATEPART(DW, CASE
WHEN DATEPART(DW, d.MAX_DATE) >= j.DW
THEN DATEADD(DD, 7 - DATEPART(DW, d.MAX_DATE) + j.DW + J.SERV_PERIOD_INC, d.MAX_DATE)
ELSE DATEADD(DD, j.DW - DATEPART(DW, d.MAX_DATE) + J.SERV_PERIOD_INC, d.MAX_DATE)
END) NextWeekDay,
J.SERV_PERIOD_INC
FROM cteJobs J
INNER JOIN (SELECT MAX(DATE) MAX_DATE, JOB_ID FROM SERVICE S GROUP BY S.JOB_ID) d
ON D.JOB_ID = J.ID
标准化您的数据以停止查找可用日期列表:
;WITH cteJobs AS (
SELECT
d_norm.DW_NUM AS DW,
CASE
WHEN SERV_PERIOD = 'W' THEN 1
WHEN SERV_PERIOD = 'F' THEN 8
END SERV_PERIOD_INC,
*
FROM JOB J
CROSS APPLY (
SELECT 1 AS DW_NUM
WHERE J.SERV_MON = 'Y'
UNION ALL
SELECT 2
WHERE J.SERV_TUE = 'Y'
UNION ALL
SELECT 3
WHERE J.SERV_WED = 'Y'
UNION ALL
SELECT 4
WHERE J.SERV_THU = 'Y'
UNION ALL
SELECT 5
WHERE J.SERV_FRI = 'Y'
UNION ALL
SELECT 6
WHERE J.SERV_SAT = 'Y'
UNION ALL
SELECT 7
WHERE J.SERV_SUN = 'Y'
) d_norm
)
SELECT
J.ID JOB_ID,
d.MAX_DATE LastServiceDate,
MIN(CASE
WHEN DATEPART(DW, d.MAX_DATE) >= j.DW
THEN DATEADD(DD, 7 - DATEPART(DW, d.MAX_DATE) + j.DW + J.SERV_PERIOD_INC, d.MAX_DATE)
ELSE DATEADD(DD, j.DW - DATEPART(DW, d.MAX_DATE) + J.SERV_PERIOD_INC, d.MAX_DATE)
END) NextServiceDate
FROM cteJobs J
INNER JOIN (SELECT MAX(DATE) MAX_DATE, JOB_ID FROM SERVICE S GROUP BY S.JOB_ID) d
ON D.JOB_ID = J.ID
GROUP BY J.ID, d.MAX_DATE
ORDER BY J.ID
这可以修复您的代码,并可以找到最接近的可用日期。考虑标准化您的数据模型。可用日期应该是行,而不是列。
| JOB_ID | LastServiceDate | NextServiceDate |
|--------|-----------------|-----------------|
| 1 | 2019-03-24 | 2019-03-31 |
| 2 | 2019-03-26 | 2019-04-02 |
| 3 | 2019-03-24 | 2019-03-26 |
| 4 | 2019-03-26 | 2019-04-01 |
| 5 | 2019-03-24 | 2019-04-07 |
| 6 | 2019-03-26 | 2019-04-09 |
| 7 | 2019-03-24 | 2019-04-02 |
| 8 | 2019-03-26 | 2019-04-08 |
答案 2 :(得分:0)
虽然Damian The Unbeliever's answer和Ivan Starostin's answer都进行了一些改进,以使查询更高效,更易读,但问题的原因是内部嵌套{{1} }语句未关闭。
整理CTE(按照他们的建议)使查询本身更具可读性,并且使用Damian的CASE
和CROSS JOIN
文字数字来减少占用的空间,甚至可以做更多。不过,您仍然可以使用大小合适的UNION
语句作为子查询或CTE;尽管它冗长而费力,但实际上并没有很多层次,如果使用正确的语法,它也可以正常工作:
CASE
请注意;WITH cteLastService AS (
SELECT MAX(DATE) AS LastServiceDate,
JOB_ID
FROM SERVICE GROUP BY SERVICE.JOB_ID
), cteWeekly AS (
SELECT CASE J.SERV_PERIOD
WHEN 'F' THEN 7
ELSE NULL
END AS 'WeekDayAdd',
ID
FROM JOB AS J
), cteNextService AS (
SELECT CASE
WHEN J.SERV_PERIOD IN ('W','F') THEN CASE
WHEN DATEPART(DW,S.LastServiceDate) = 1 THEN CASE
WHEN SERV_MON = 'Y' THEN DATEADD(DD,1 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_TUE = 'Y' THEN DATEADD(DD,2 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_WED = 'Y' THEN DATEADD(DD,3 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_THU = 'Y' THEN DATEADD(DD,4 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_FRI = 'Y' THEN DATEADD(DD,5 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SAT = 'Y' THEN DATEADD(DD,6 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SUN = 'Y' THEN DATEADD(DD,7 + W.WeekDayAdd,S.LastServiceDate)
END
WHEN DATEPART(DW,S.LastServiceDate) = 2 THEN CASE
WHEN SERV_TUE = 'Y' THEN DATEADD(DD,1 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_WED = 'Y' THEN DATEADD(DD,2 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_THU = 'Y' THEN DATEADD(DD,3 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_FRI = 'Y' THEN DATEADD(DD,4 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SAT = 'Y' THEN DATEADD(DD,5 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SUN = 'Y' THEN DATEADD(DD,6 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_MON = 'Y' THEN DATEADD(DD,7 + W.WeekDayAdd,S.LastServiceDate)
END
WHEN DATEPART(DW,S.LastServiceDate) = 3 THEN CASE
WHEN SERV_WED = 'Y' THEN DATEADD(DD,1 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_THU = 'Y' THEN DATEADD(DD,2 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_FRI = 'Y' THEN DATEADD(DD,3 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SAT = 'Y' THEN DATEADD(DD,4 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SUN = 'Y' THEN DATEADD(DD,5 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_MON = 'Y' THEN DATEADD(DD,6 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_TUE = 'Y' THEN DATEADD(DD,7 + W.WeekDayAdd,S.LastServiceDate)
END
WHEN DATEPART(DW,S.LastServiceDate) = 4 THEN CASE
WHEN SERV_THU = 'Y' THEN DATEADD(DD,1 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_FRI = 'Y' THEN DATEADD(DD,2 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SAT = 'Y' THEN DATEADD(DD,3 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SUN = 'Y' THEN DATEADD(DD,4 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_MON = 'Y' THEN DATEADD(DD,5 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_TUE = 'Y' THEN DATEADD(DD,6 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_WED = 'Y' THEN DATEADD(DD,7 + W.WeekDayAdd,S.LastServiceDate)
END
WHEN DATEPART(DW,S.LastServiceDate) = 5 THEN CASE
WHEN SERV_FRI = 'Y' THEN DATEADD(DD,1 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SAT = 'Y' THEN DATEADD(DD,2 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SUN = 'Y' THEN DATEADD(DD,3 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_MON = 'Y' THEN DATEADD(DD,4 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_TUE = 'Y' THEN DATEADD(DD,5 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_WED = 'Y' THEN DATEADD(DD,6 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_THU = 'Y' THEN DATEADD(DD,7 + W.WeekDayAdd,S.LastServiceDate)
END
WHEN DATEPART(DW,S.LastServiceDate) = 6 THEN CASE
WHEN SERV_SAT = 'Y' THEN DATEADD(DD,1 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SUN = 'Y' THEN DATEADD(DD,2 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_MON = 'Y' THEN DATEADD(DD,3 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_TUE = 'Y' THEN DATEADD(DD,4 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_WED = 'Y' THEN DATEADD(DD,5 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_THU = 'Y' THEN DATEADD(DD,6 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_FRI = 'Y' THEN DATEADD(DD,7 + W.WeekDayAdd,S.LastServiceDate)
END
WHEN DATEPART(DW,S.LastServiceDate) = 7 THEN CASE
WHEN SERV_SUN = 'Y' THEN DATEADD(DD,1 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_MON = 'Y' THEN DATEADD(DD,2 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_TUE = 'Y' THEN DATEADD(DD,3 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_WED = 'Y' THEN DATEADD(DD,4 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_THU = 'Y' THEN DATEADD(DD,5 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_FRI = 'Y' THEN DATEADD(DD,6 + W.WeekDayAdd,S.LastServiceDate)
WHEN SERV_SAT = 'Y' THEN DATEADD(DD,7 + W.WeekDayAdd,S.LastServiceDate)
END
END
END AS 'NextServiceDate',
J.ID
FROM JOB AS J INNER JOIN
cteLastService AS S ON S.JOB_ID = J.ID INNER JOIN
cteWeekly AS W ON W.ID = J.ID
)
关键字-如果没有关键字,原始语句嵌套的深度为 17个级别 。仅有它们的 3 。在这种情况下,良好的缩进可以使它看起来井井有条,但是却不会告诉每个段要关闭...这意味着将它们放在一起就这么简单:
END