我们有2个表有多对多的关系,这些表可以简化为:
重要归因于M_Plan_ID的M-Plan表:
M_Plan_ID
VM-000001
VM-000008
授权表具有有效日期的授权ID:
GID START_DATE END_DATE ACTIVE_TIME_LINE
VG-000813 21/04/2018 28/04/2019 Y
VG-000808 29/04/2019 22/04/2020 Y
VG-000800 23/04/2020 18/04/2033 Y
VG-000812 19/04/2033 31/12/9999 Y
VG-000811 22/08/2018 NULL N
关系表描述分配给M-Plan的拨款:
M_Plan_ID GID
VM-000001 VG-000813
VM-000001 VG-000812
VM-000008 VG-000813
VM-000008 VG-000800
业务要求是,如果为M-Plan分配了多个拨款,那么所有已分配的拨款必须在日期中连续。
我们需要编写SQL,它只会向M-Plan显示缺少的Grants间隔:
例如,已为VM-000001分配了授权VG-000813和VG-000812但缺少的间隔为VG-000808和VG-000800。
同样,VM-000008已被分配VG-000813和VG-000800螺母缺失间隔为VG-000808。
期望的结果是:
M_Plan_ID GID
VM-000001 VG-000808
VM-000001 VG-000800
VM-000008 VG-000808
可以通过以下语句生成相同的表和数据:
create table M_Plan_ID (M_Plan_ID varchar(100) );
insert into M_Plan_ID(M_Plan_ID) values('VM-000001');
insert into M_Plan_ID(M_Plan_ID) values('VM-000008');
create table grants (gid varchar(100), start_date date, end_date date, active varchar(1));
insert into grants values ('VG-000813',cast('2018-04-21' as Date),cast('2019-04-28' as Date),'Y');
insert into grants values ('VG-000808',cast('2019-04-29' as Date),cast('2020-04-22' as Date),'Y');
insert into grants values ('VG-000800',cast('2020-04-23' as Date),cast('2033-04-18' as Date),'Y');
insert into grants values ('VG-000812',cast('2033-04-19' as Date),cast('9999-12-31' as Date),'Y');
insert into grants values ('VG-000811',cast('2018-08-22' as Date),null,'n');
create table rel (M_Plan_ID varchar(100), GID varchar(100) )
insert into rel values('VM-000001','VG-000813');
insert into rel values('VM-000001','VG-000812');
insert into rel values('VM-000008','VG-000813');
insert into rel values('VM-000008','VG-000800');
我正在尝试的SQL是这样的:
select
T.*,
case when start_date=lead_end_date_1 then 'True' else 'False' end
from
(
select
M.M_Plan_ID,
G.GID,
G.start_date,
ISNULL(DATEADD(D, -1,LEAD(G.start_date) over (partition by M.M_Plan_ID order by g.start_date)), cast('9999-12-31' as Date)) as lead_end_date_1,
count(*) over(partition by M.M_Plan_ID) as count_partition_M_Plan_ID
from M_Plan_ID M
join rel R on M.M_Plan_ID=R.M_Plan_ID
join grants G on R.GID=G.GID
) T
where count_partition_M_Plan_ID>1
and lead_end_date_1!='9999-12-31'.
但有了这个,我只能得到连续性突破的点,我们只需要看到所有缺失的间隔。
非常感谢您在SQL中的帮助。
谢谢
答案 0 :(得分:0)
下面的SQL(MS Sql Server)从可能的其他计划中筛选出活动计划
在现有的间隔内。
与目前的有效计划相比,过滤那些启动太晚或结束太早的那些。
with ACTIVEPLANS AS (
select p.M_Plan_ID, g.GID,
g.[START_DATE],
coalesce(g.[END_DATE], cast('9999-12-31' as date)) as [END_DATE],
min(g.[START_DATE]) over (partition by p.M_Plan_ID) as MinStartDate,
max(coalesce(g.[END_DATE],cast('9999-12-31' as date))) over (partition by p.M_Plan_ID) as MaxEndDate
from M_Plan_ID p
join rel r on (p.M_Plan_ID = r.M_Plan_ID)
join grants g on (g.GID = r.GID and g.active = 'Y')
)
select p.M_Plan_ID, g.GID
from M_Plan_ID p
join grants g on (p.M_Plan_ID <> g.GID and g.active = 'Y')
where not exists (
select 1
from ACTIVEPLANS gp
where gp.M_Plan_ID = p.M_Plan_ID
and (
gp.GID = g.GID
or (gp.[START_DATE] >= g.[START_DATE] and gp.[END_DATE] <= g.[END_DATE])
or gp.MaxEndDate <= g.[START_DATE]
or gp.MinStartDate >= g.[END_DATE]
)
);
答案 1 :(得分:0)
我假设赠款在这里不重叠。我的方法是首先弄清楚每个计划已经分配的拨款的日期范围的开始和结束(CTE PlanRange计算的)。
一旦我有了,我就可以使用 CROSS JOIN 来包含每个计划的指定日期范围的所有授权。这给了应该分配给每个计划的拨款。在此之后,对已经分配的授权进行 LEFT OUTER JOIN 很容易,然后只包括 rel 中没有条目的授权(即R .M_Plan_ID IS NULL)
请参阅:SQL Fiddle
WITH PlanRange AS (
SELECT
M.M_Plan_ID
, MIN( G.start_date ) AS start_date
, MAX( G.end_date ) AS end_date
FROM
M_Plan_ID AS M
JOIN
rel AS R ON (R.M_Plan_ID = M.M_Plan_ID)
JOIN
grants AS G ON (G.GID = R.GID)
GROUP BY
M.M_Plan_ID
)
SELECT
M.M_Plan_ID
, G.GID
FROM
M_Plan_ID AS M
JOIN
PlanRange ON (PlanRange.M_Plan_ID = M.M_Plan_ID)
CROSS JOIN
grants AS G
LEFT OUTER JOIN
rel AS R ON (
R.M_Plan_ID = M.M_Plan_ID
AND R.GID = G.GID
)
WHERE
G.active = 'Y'
AND G.start_date BETWEEN PlanRange.start_date AND PlanRange.end_date
AND R.M_Plan_ID IS NULL
ORDER BY
M.M_Plan_ID, G.GID