【问题标题】:Return list of financial years between date range返回日期范围之间的财政年度列表
【发布时间】:2014-08-28 13:46:12
【问题描述】:

也许我想多了,但我有点难过。

我正在尝试按月、按财政年度汇总数据,每个财政年度返回一行,每个月有一列。

我可以轻松地每月返回一列,但是尝试将财务年度作为行返回证明是困难的部分。

我的理论是,一旦我将财政年度选为一行,我可以简单地将其加入到按财政年度/月份总结的子查询中,每 1 给我 1。

问题是财政年度从 8 月 1 日开始。查询的日期范围可以从 1 个财政年度到可能跨越 5 年的日期范围。

例如,如果我的日期范围是 01/08/2013-31/07/2014,我希望财政年度返回为:

2013/2014

如果我的日期范围是 01/08/2012-31/07/2014,我希望将以下内容作为财政年度返回:

2012/2013 
2013/2014

如果我的日期范围是 01/01/2012-28/08/2014,我希望将以下内容作为财政年度返回:

2011/2012
2012/2013
2013/2014
2014/2015

这是我迄今为止的工作,但它没有按预期工作。

  DECLARE @DateFrom datetime, @DateTo datetime
SET @DateFrom = '2011-08-01'
set @DateTo = '2014-07-31'


; with  FinYr as
        (
        select  @DateFrom as AllDate, @DAteTo as EndDate, case when datepart(MONTH, @DateFrom) < 8 then convert(varchar(4),datepart(year, @DateFrom)-1)+'/'+convert(varchar(4),datepart(year, @DateFrom)) else convert(varchar(4),datepart(year, @DateFrom))+'/'+convert(varchar(4),datepart(year, @DateFrom)+1) End as FinYear
        union all
        select  dateadd(year,1,AllDate) as AllDate, dateadd(year,1,EndDate) as EndDate,case when datepart(MONTH, dateadd(year,1,AllDate)) < 8 then convert(varchar(4),datepart(year, dateadd(year,1,AllDate))-1)+'/'+convert(varchar(4),datepart(year, dateadd(year,1,AllDate))) else convert(varchar(4),datepart(year, dateadd(year,1,AllDate)))+'/'+convert(varchar(4),datepart(year, dateadd(year,1,AllDate))+1) End as FinYear
        from    FinYr
        where   dateadd(year,-1,EndDate) <= convert(datetime,(convert(varchar(4),year(@Dateto))+'-07-31'))
        )
select  AllDate,EndDate, FinYear
from    FinYr

【问题讨论】:

  • 你能发布 ddl 和 FinYr 的一些示例数据吗?
  • FinYr 不是数据库中的数据,它是一个递归函数。
  • 哦,天哪……我需要更多的咖啡数据!!!

标签: sql-server


【解决方案1】:

您可以使用计数表或数字表来处理此类问题。在我的代码中,我动态创建了计数表。这是一种零读取类型的实现...超级快。

DECLARE @DateFrom datetime, @DateTo datetime;
SET @DateFrom = '2011-08-01';
set @DateTo = '2014-07-31';

WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )

select CAST(N as CHAR(4)) + '/' +  CAST(N + 1 as CHAR(4))
from cteTally
where N >= DATEPART(YEAR, @DateFrom)
and N <= DATEPART(YEAR, @DateTo);

确定更新后的要求,您只需对上述代码稍作调整即可完成此操作。这应该能让你到达那里。

select CAST(N as CHAR(4)) + '/' +  CAST(N + 1 as CHAR(4))
from cteTally
where N >= case when DATEPART(MONTH, @DateFrom) > 6 then DATEPART(YEAR, @DateFrom) else DATEPART(YEAR, DATEADD(YEAR, 1, @DateFrom)) end
and N <= case when DATEPART(MONTH, @DateTo) < 6 then DATEPART(YEAR, @DateTo) else DATEPART(YEAR, DATEADD(YEAR, 1, @DateTo)) end

我想我知道我在那里做错了什么......试试这个。

select CAST(N as CHAR(4)) + '/' +  CAST(N + 1 as CHAR(4))
, case when DATEPART(MONTH, @DateTo) < 8 then DATEPART(YEAR, DATEADD(YEAR, -1, @DateTo)) else DATEPART(YEAR, DATEADD(YEAR, 1, @DateTo)) end
from cteTally
where N >= case when DATEPART(MONTH, @DateFrom) > 6 then DATEPART(YEAR, @DateFrom) else DATEPART(YEAR, DATEADD(YEAR, 1, @DateFrom)) end
and N <= case when DATEPART(MONTH, @DateTo) < 8 then DATEPART(YEAR, DATEADD(YEAR, -1, @DateTo)) else DATEPART(YEAR, DATEADD(YEAR, 1, @DateTo)) end

【讨论】:

  • 它产生的正是你所说的你想要的输出。它有什么不正确的?如果你让我知道什么是不正确的,我可以解决它。
  • 嗯似乎很接近......如果我输入日期范围 '2013-08-01' - '2014-08-20' 然后它会按预期返回 2013/2014 和 2014/2015。如果我输入:'2013-08-01'-'2014-07-30' 它仍然返回 2013/2014 和 2014/2015 在这种情况下,它只应该返回 2013/2014
  • 为什么输出会改变?您的财务年度在 7 月 1 日有变化吗?他们总是在 7 月 1 日改变吗?如果切换日期是可变的,那么您应该使用日历表。
  • 财政年度总是 01/08-31/07 可以输入的日期范围在每次运行报告时都会发生变化,因此有时会报告 5 个财政年度,而其他只是从 1 个财政年度开始的几个月。
  • 我在喝完咖啡后又看了一遍:) 下面的效果很好,完全符合我的需要。非常感谢您的帮助。 select CAST(N as CHAR(4)) + '/' + CAST(N + 1 as CHAR(4)) , case when DATEPART(MONTH, @DateTo) &lt; 8 then DATEPART(YEAR, DATEADD(YEAR, -1, @DateTo)) else DATEPART(YEAR, DATEADD(YEAR, 1, @DateTo)) end from cteTally where N &gt;= case when DATEPART(MONTH, @DateFrom) &lt;= 7 then DATEPART(YEAR, DATEADD(YEAR, -1, @DateFrom)) else DATEPART(YEAR, @DateFrom) End and N &lt; case when DATEPART(MONTH, @DateTo) &gt; 7 then DATEPART(YEAR, DATEADD(YEAR, 1, @DateTo)) else DATEPART(YEAR, @DateTo) end
【解决方案2】:

我相信这会显示您想要的年份列表:

DECLARE 
    @DateFrom datetime, 
    @DateTo   datetime
SET @DateFrom = '2011-01-01'
SET @DateTo = '2014-07-31'


SELECT CAST(YearList AS VARCHAR(4)) + '/' + CAST((YearList +1) AS VARCHAR(4)) AS FiscalYear
FROM
  (
    SELECT 
        DATEPART(YEAR, @DateFrom) - CASE WHEN DATEPART(MONTH, @DateFrom) >= 8 THEN 0 ELSE 1 END + 
        ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY (SELECT NULL)) -1 AS YearList
    FROM sys.all_objects
  ) q
WHERE YearList <= DATEPART(YEAR, @DateTo) - CASE WHEN DATEPART(MONTH, @DateTo) >= 8 THEN 0 ELSE 1 END

【讨论】:

  • 感谢您的回答,但与其他答案一样,我得到的一年太多了。选择截至 31/07/2014 应仅返回 2010/2011、2011/2012、2012/2013 和 2013/2014,因为 31/07/2014 是 2013/2014 财政年度的最后一天。我实际上得到了 2010/2011、2011/2012、2012/2013、2013/2014 和 2014/2015
  • 我为此使用 cte 的原因是因为它可以让您对值进行一些控制。 sys.all_objects 可以是一个很小的数字,它可能没有足够的行。
  • 对不起@OWSam,我的浏览器没有弹出你的消息,我没有及时收到它来处理它。不管它值多少钱,我都编辑过。肖恩,我对 CTE 也有同样的想法,但考虑到 OP 中缺乏 RDBMS 规范以及实际可返还的财政年度数量可能很少,因此选择了简单的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-10
  • 2021-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多