在SQL中具有条件的范围内查找最小日期
我需要在相同的LegalStart/LegalEnd日期内按客户查找第一个StayStart,该日期>=8天LOS且仅为类型1。第1类连续停留时间少于8天的,如果加起来是8天,并且没有其他类型的中断,则计算在内。在这种情况下,我需要最早的连续停留。而这正是我无法理解的方法。将8岁以下但累计到8岁的连续住宿相加。我很想发布一些我尝试过的东西,但我一无所获。 这是我的桌子:在SQL中具有条件的范围内查找最小日期,sql,Sql,我需要在相同的LegalStart/LegalEnd日期内按客户查找第一个StayStart,该日期>=8天LOS且仅为类型1。第1类连续停留时间少于8天的,如果加起来是8天,并且没有其他类型的中断,则计算在内。在这种情况下,我需要最早的连续停留。而这正是我无法理解的方法。将8岁以下但累计到8岁的连续住宿相加。我很想发布一些我尝试过的东西,但我一无所获。 这是我的桌子: cust# LegalStart StayStart StayEnd LegalEnd Type
cust# LegalStart StayStart StayEnd LegalEnd Type LOS(days)
1000 5/3/2013 2/1/2016 2/5/2016 11/18/2016 1 4
1000 5/3/2013 2/5/2016 2/8/2016 11/18/2016 1 3
1000 5/3/2013 2/8/2016 2/11/2016 11/18/2016 2 3
1000 5/3/2013 2/11/2016 2/28/2016 11/18/2016 1 17
1000 3/2/2016 3/2/2016 3/5/2016 11/18/2016 1 4
1000 3/2/2016 3/5/2016 3/7/2016 11/18/2016 1 2
1000 3/2/2016 3/7/2016 3/11/2016 11/18/2016 1 4
1000 3/2/2016 3/12/2016 3/22/2016 11/18/2016 1 10
2000 3/1/2011 12/1/2015 12/3/2015 1/8/2016 1 2
2000 3/1/2011 12/3/2015 12/5/2015 1/8/2016 1 2
2000 3/1/2011 12/5/2015 12/6/2015 1/8/2016 1 1
2000 3/1/2011 12/6/2015 12/18/2015 1/8/2016 1 12
预期结果
cust# LegalStart StayStart StayEnd LegalEnd Type LOS(days)
1000 5/3/2013 2/11/2016 2/28/2016 11/18/2016 1 17
1000 3/2/2016 3/2/2016 3/5/2016 11/18/2016 1 4
2000 3/1/2011 12/1/2015 12/3/2015 1/8/2016 1 2
我的第一个结果是17个服务水平,因为之前的客户的行加起来是10天,但是,其中一个是2类,所以不算在内。另外两次住宿加起来是7天,所以不算在内。因此,2016年2月11日的StayStart(服务水平为17)是符合我标准的最短日期。
同一客户的第二个结果是在下一个法定日期时间段内,4天的停留时间加上接下来的2天和4天的停留时间均为1类,因此它们加起来超过或等于8天。因此,2016年3月2日的StayStart日期是符合我的标准的最小日期。
第三个结果行是下一个客户的结果行,这是正确的,因为该客户的所有4行都是类型1,加起来>=8天。因此,15年1月12日的StayStart是符合我的标准的最小日期。
感谢您提供的帮助。这在MySQL中有点混乱,它缺乏对分析函数的支持,但可以使用变量来完成,假设您的表名为theTable:
select custNum, legalStart, legalEnd, stayStart, stayEnd, type, losDays from (
select
@custNum as custNum,
@legalStart as legalStart,
@legalEnd as legalEnd,
@stayStart as stayStart,
@stayEnd as stayEnd,
@type as type,
@losDays as losDays,
@newGroup :=
(@custNum != custNum
or @legalStart != legalStart
or @legalEnd != legalEnd
or @type != type)
as newGroup,
@aggLosDays as groupAggLosDays,
@aggLosDays :=
case when @newGroup
then losDays
else @aggLosDays + losDays end as __________,
case when @newGroup then @losDays := losDays else null end as _,
@custNum :=
case when @custNum != custNum
then custNum else @custNum end as ___,
@legalStart :=
case when @legalStart != legalStart
then legalStart else @legalStart end as ____,
@legalEnd :=
case when @legalEnd != legalEnd
then legalEnd else @legalEnd end as _____,
@type :=
case when @type != type
then type else @type end as ______,
@stayStart :=
case when @newGroup
then stayStart else @stayStart end as _______,
@stayEnd :=
case when @newGroup
then stayEnd else @stayEnd end as ________
from
(
(
select
custNum, legalStart, legalEnd, stayStart, stayEnd,
type, datediff(stayEnd,stayStart) as losDays
from theTable
order by custNum, legalStart, legalEnd, stayStart, type
) union all (
select -1, date('0000-00-00'), date('0000-00-00'),
date('0000-00-00'), date('0000-00-00'), -1, null
)
) tt
join (select @aggLosDays := -1) z1
join (select @custNum := -1) z2
join (select @legalStart := date('0000-00-00')) z3
join (select @legalEnd := date('0000-00-00')) z4
join (select @stayStart := date('0000-00-00')) z5
join (select @staylEnd := date('0000-00-00')) z6
join (select @type := -1) z7
join (select @losDays := null) z8
order by
custNum,
legalStart,
legalEnd,
stayStart,
stayEnd,
type,
losDays
) z
where
newGroup
and type=1
and groupAggLosDays >= 8
;
此查询使用变量计算具有相同客户、法定日期范围和类型的组之间的运行总计。棘手的部分是,从内部查询返回的每一行实际上并不包含来自当前表行的任何数据,而是表示来自同一组中先前行的汇总日期的变量的内容。当客户、法定日期范围或类型发生更改时,@newGroup变量设置为TRUE,表示新组的开始。外部查询的where子句将从内部查询中选择一行,前提是该行被标记为新组,类型为1,总天数>=8
将存根行追加到查询的表格行,以触发对最终组的处理
MySQL不是我的主要RDBMS,所以我相信它可以变得更干净。这里有一个版本应该与支持分析功能的MS SQL Server版本一起使用
select distinct custNum, legalStart, stayStart, stayEnd, legalEnd, type, losDays
from (
select
custNum, legalStart, legalEnd, type,
first_value(stayStart) over (partition by gg order by stayStart) as stayStart,
first_value(stayEnd) over (partition by gg order by stayEnd) as stayEnd,
first_value(losDays) over (partition by gg order by stayEnd) as losDays,
sum(losDays) over (partition by gg order by stayStart) as accLosDays
from (
select
custNum, legalStart, legalEnd, stayStart, stayEnd, type, losDays,
case when g is not null
then g
else min(g) over (
partition by custNum, legalStart, legalEnd
rows between current row and unbounded following)
end as gg
from (
select
custNum, legalStart, legalEnd, stayStart, stayEnd, type,
datediff(day,stayStart,stayEnd) as losDays,
case
when lead(type, 1, -1)
over (partition by custNum, legalStart, legalEnd order by stayStart) != type
then row_number() over ()
else null end as g
from
theTable
order by
custNum,
legalStart,
legalEnd,
stayStart,
type
) z
) zz
where
type=1
) zzz
where
accLosDays >= 8;
为了理解它是如何工作的,我建议从最里面的语句开始运行每个select语句,然后向外运行:
select
custNum, legalStart, legalEnd, stayStart, stayEnd, type,
datediff(day,stayStart,stayEnd) as losDays,
case
when lead(type, 1, -1)
over (partition by custNum, legalStart, legalEnd order by stayStart) != type
then row_number() over ()
else null end as g
from
theTable
order by
custNum,
legalStart,
legalEnd,
stayStart,
type
此查询按客户和法定日期范围将表行分组到分区中。每个组的最后一行由分区的结尾或type列的值的更改确定,这将触发要分配给名为g的输出列的当前总行号,否则g将保留为null
下一个查询将使用g set的值获取这些行,并发出一个新列gg,该列将g的空值填充为其组的正确值:
select
custNum, legalStart, legalEnd, stayStart, stayEnd, type, losDays,
case
when g is not null
then g
else min(g) over (
partition by custNum, legalStart, legalEnd
rows between current row and unbounded following
) end as gg
from
<<<<inner query>>>>
最后,提取结果的第一个stayStart、stayEnd和losDays值,并按类型和每组的总天数进行过滤:
select distinct
custNum, legalStart, stayStart, stayEnd, legalEnd, type, losDays
from (
select
custNum, legalStart, legalEnd, type,
first_value(stayStart)
over (partition by gg order by stayStart) as stayStart,
first_value(stayEnd)
over (partition by gg order by stayEnd) as stayEnd,
first_value(losDays)
over (partition by gg order by stayEnd) as losDays,
sum(losDays)
over (partition by gg order by stayStart) as accLosDays
from (
<<<<inner query>>>>
where
type=1
) zzz
where
accLosDays >= 8
您正在使用哪些关系数据库管理系统:mysql、sql server、postgresql、oracle。。。?这些日期是存储为日期类型还是其他类型?您尝试过什么吗?应该是最大值而不是最小值。但是您可以使用sql server的秩或行号窗口函数,可能还有一些类型库,我想我已经在顶部添加了我正在使用sql server。当我必须找到第一个日期时,为什么会是max…,最老的,或最早的,等等?不,我没有尝试过任何b/c我写了这个代码只是为了找到min date,它是Thank you Mark。有几个问题。这是什么?:=ManagementStudio出错了,我在web上搜索MySQL命令时找不到它。MSSMS还告诉我没有名为date的函数,那么DATEADD呢?还是别的什么?我错了,我把你上面写的误读为MySQL而不是SQL Server。