sql server中两个日期之间的月份(每个日期的开始日期和结束日期在sql server中的结束日期)可以为空

sql server中两个日期之间的月份(每个日期的开始日期和结束日期在sql server中的结束日期)可以为空,sql,sql-server,Sql,Sql Server,我想得到两个日期之间的月份,包括开始日期和结束日期。假设我输入的起始日期为2019年6月7日,结束日期为2019年9月18日,我想分别列出两者之间的月份及其开始和结束日期。请建议我如何实现。此外,如果Utc结束日期为空,则应自动将日期拆分为当前日期,即19/09/19 输入表BusinessGoal: BusinessRefId Period GoalType Amount StartDateUtc EndDateUtc Curre

我想得到两个日期之间的月份,包括开始日期和结束日期。假设我输入的起始日期为2019年6月7日,结束日期为2019年9月18日,我想分别列出两者之间的月份及其开始和结束日期。请建议我如何实现。此外,如果Utc结束日期为空,则应自动将日期拆分为当前日期,即19/09/19

输入表BusinessGoal:

BusinessRefId   Period  GoalType                Amount  StartDateUtc      EndDateUtc         Currency
Business C      Year    CommittedTransactionFee 18000   05/07/19 00:00:00 19/09/19 00:00:00  USD

BusinessRefId   Period              GoalType                Amount  StartDateUtc         EndDateUtc           Currency
Business C      2019-07 - 2019-08   CommittedTransactionFee 18000   05/07/2019 00:00:00  05/08/2019 00:00:00    USD
Business C      2019-08 - 2019-09   CommittedTransactionFee 18000   05/08/2019 00:00:00  05/09/2019 00:00:00    USD
Business C      2019-09 - 2019-10   CommittedTransactionFee 18000   05/09/2019 00:00:00  05/10/2019 00:00:00    USD

输出表业务目标:

BusinessRefId   Period  GoalType                Amount  StartDateUtc      EndDateUtc         Currency
Business C      Year    CommittedTransactionFee 18000   05/07/19 00:00:00 19/09/19 00:00:00  USD

BusinessRefId   Period              GoalType                Amount  StartDateUtc         EndDateUtc           Currency
Business C      2019-07 - 2019-08   CommittedTransactionFee 18000   05/07/2019 00:00:00  05/08/2019 00:00:00    USD
Business C      2019-08 - 2019-09   CommittedTransactionFee 18000   05/08/2019 00:00:00  05/09/2019 00:00:00    USD
Business C      2019-09 - 2019-10   CommittedTransactionFee 18000   05/09/2019 00:00:00  05/10/2019 00:00:00    USD

我已经写了一个查询,它根据年度分割日期,即BusinessGoal.Period='Year'

declare @BusinessGoal table  
(BusinessRefId varchar(50),   
Period varchar(50), 
GoalType varchar(100),    
Amount money, 
StartDateUtc datetime,   
EndDateUtc datetime, 
Currency varchar(10));

insert into @BusinessGoal values
  ('Business A', 'Year', 'CommittedTransactionFee', 45000, '2019-06-07 00:00:00', NULL, 'USD'),
  ('Business B', 'Year', 'CommittedTransactionFee', 18000, '2017-06-07 00:00:00', NULL, 'USD'),
  ('Business E', 'Year', 'CommittedTransactionFee', 5000 , '2019-04-01 00:00:00', '2019-08-01 00:00:00', 'USD');

select BusinessRefId 
  , cast(ys.y as varchar(4)) + '-' + cast(ys.y + 1 as varchar(4))  Period
  , GoalType, Amount
  , dateadd(year, nmbs.n, tbl.StartDateUtc) StartDateUtc
  , case when ys.NextDate > tbl.EndDateUtc then tbl.EndDateUtc else ys.NextDate end EndDateUtc
  , Currency
from @BusinessGoal tbl
join 
(values (0),(1),(2)
 ) nmbs(n)
on dateadd(year, nmbs.n, tbl.StartDateUtc) <= getdate() 
  and (EndDateUtc is null or EndDateUtc >= datefromparts(Year(tbl.StartDateUtc) + nmbs.n + 1, 1, 1))
cross apply (select Year(tbl.StartDateUtc) + nmbs.n y, dateadd(year, nmbs.n + 1,tbl.StartDateUtc) NextDate) ys
我必须通过对BusinessGoal表期间列(即
如果BusinessGoal.Period='Year',如果BusinessGoal.Period='Month'

这是如何编写Caius Jard在评论中提出的递归CTE:

-- Create a Test Table
select '2019-07-05' as StartDateUtc, '2019-09-19' as EndDateUtc
into #test;

-- Recursive CTE that returns the months between StartDateUtc and EndDateUtc
with months as (
  -- initial values of the recursive CTE
  select datefromparts(year(StartDateUtc), month(StartDateUtc), 1) as StartPeriod,
         dateadd(month, 1, datefromparts(year(StartDateUtc), month(StartDateUtc), 1)) as EndPeriod,
         t.StartDateUtc, t.EndDateUtc
  from #test t
  union all
  -- we recursively add 1 month until we reach EndDateUtc
  select dateadd(month, 1, StartPeriod) as StartPeriod,
         dateadd(month, 1, EndPeriod) as EndPeriod,
         months.StartDateUtc, months.EndDateUtc
  from months 
  where dateadd(month, 1, StartPeriod) <= coalesce(EndDateUtc, StartDateUtc)  -- If EndDateUtc is null then we use StartDateUtc, so only the first month is returned
)
select * from months;

-- Drop Test Table
drop table #test;

创建一个递归CTE,该CTE将生成从0开始的递增整数序列,将其加入到数据中,并将递增整数添加到起始日期,以月为间隔。coalescendDate,getutcdate使结束日期为当前日期(如果为空)。使用where子句查找所需日期之间的行。这几乎就是你所拥有的,除了它每隔几个月而不是几年工作,并且产生更多rows@CaiusJard我必须将其集成到我在上述问题中提到的现有查询中。好的,同样,也要做月份表单——制作你已经检查过的where子句,看看是否传入了“年”,然后做where子句或另一个类似的where子句,看看是否传入了月份,dateaddmonths而不是years。您可能会发现执行两个查询比较容易,一个查询执行年份,并且只在business goal=year的位置工作,然后合并另一个查询,该查询只执行月份和businessgoal=months@CaiusJard我不知道如何创建递归CTE。