财政期间的清单编号顺序

Listing number sequence for financial periods

在 SQL 2016 年,我需要使用财务周期创建一个列表,但只有 from/to 可用 - 它的格式类似于日期,但为 0mmyyyy,因此前 3 个数字是 month/period 和年份的最后 4 位数字。

例如period_from 是“0102017”,period_to 是“0032018”,但要返回一个包含中间值的列表?

0102017, 
0112017, 
0122017, 
0012018,
0022018

此外,前三个字符可以转到 012 或 013,因此需要能够轻松更改其他数据库的代码。

这会有点复杂。首先,我有一个用户定义的 table 值函数,它根据开始日期和结束日期输出日历 table。您需要先创建它...

CREATE FUNCTION dbo.udf_calendar (@datestart smalldatetime, @dateend smalldatetime)
RETURNS @calendar TABLE (
  [day] int,
  [date] smalldatetime
)
AS

BEGIN

  DECLARE @rows int
  DECLARE @i int = 1

  SELECT
    @rows = DATEDIFF(DAY, @datestart, @dateend)

  WHILE (@i <= @rows)
  BEGIN

    INSERT INTO @calendar ([day])
      VALUES (@i)

    SET @i = @i + 1

  END

  UPDATE a
  SET [date] = DATEADD(DAY, [day] - 1, @datestart)
  --select *, DATEADD(day,id-1,@datestart)
  FROM @calendar a

  RETURN
END

然后,下面将为您提供我认为您正在寻找的输出。我已经发表评论试图解释我是如何到达那里的,但它仍然可能有点难以理解......

--Create temp table example with your period from and to.

IF (SELECT
    OBJECT_ID('tempdb..#example'))
  IS NOT NULL
  DROP TABLE #example

SELECT
  '0102017' periodfrom,
  '0032018' periodto INTO #example

/*

This is the difficult part. Basically you're inner joining the calendar
to the temp table where the dates are between the manipulated period from and to.
I've added an extra column formatted to allow ordering correctly by period.

*/

SELECT DISTINCT
  periodfrom,
  periodto,
  RIGHT('00' + CAST(DATEPART(MONTH, [date]) AS varchar(50)), 3) + CAST(DATEPART(YEAR, [date]) AS varchar(50)) datefill,
   CAST(DATEPART(YEAR, [date]) AS varchar(50)) + RIGHT('00' + CAST(DATEPART(MONTH, [date]) AS varchar(50)), 3) datefill2
FROM dbo.udf_calendar('2015-01-01', '2018-12-31') a
INNER JOIN #example b
  ON a.[date] BETWEEN SUBSTRING(periodfrom, 2, 2) + '-01-' + SUBSTRING(periodfrom, 4, 4) AND SUBSTRING(periodto, 2, 2) + '-01-' + SUBSTRING(periodto, 4, 4)
ORDER BY datefill2

我不完全确定您要使用此列表做什么,但您可以借助计数 table 和一些常见的 table 获得所有 period 值] 表达式。

-- Test data
declare @p table(PeriodFrom nvarchar(10),PeriodTo nvarchar(10));
insert into @p values('0102017','0032018'),('0052018','0112018');

-- Specify the additional periods you want to include, use 31st December for correct sorting
declare @e table(ExtraPeriodDate date
                ,ExtraPeriodText nvarchar(10)
                );
insert into @e values('20171231','0132017');

                        -- Convert start and end of periods to dates
with m    as (select cast(min(right(PeriodFrom,4) + substring(PeriodFrom,2,2)) + '01' as date) as MinPeriod
                    ,cast(max(right(PeriodTo,4) + substring(PeriodTo,2,2)) + '01' as date) as MaxPeriod
              from @p
             )          -- Built a tally table of dates to join from
    ,t(t) as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1)
    ,d(d) as (select top (select datediff(month,MinPeriod,MaxPeriod)+1 from m) dateadd(m,row_number() over (order by (select null))-1,m.MinPeriod) from m, t t1, t t2, t t3, t t4, t t5)
                        -- Use the tally table to convert back to your date period text format
    ,p    as (select d.d as PeriodDate
                    ,'0' + right('00' + cast(month(d) as nvarchar(2)),2) + cast(year(d) as nvarchar(4)) as PeriodText
              from d
              union all -- and add in any of the addition '13th' month periods you specified previously
              select ExtraPeriodDate
                      ,ExtraPeriodText
              from @e
             )
select PeriodText
from p
order by PeriodDate;

输出:

+------------+
| PeriodText |
+------------+
|    0102017 |
|    0112017 |
|    0122017 |
|    0132017 |
|    0012018 |
|    0022018 |
|    0032018 |
|    0042018 |
|    0052018 |
|    0062018 |
|    0072018 |
|    0082018 |
|    0092018 |
|    0102018 |
|    0112018 |
+------------+

如果这不是您所需要的,它应该让您走上正确的道路来生成这些值,或者作为函数的结果,或者根据您的评论使用 for xml 将这些值连接到一个列表中通过将最终的 select 语句更改为:

select stuff((select ', ' + PeriodText
              from p
              order by PeriodDate
              for xml path('')
             )
             ,1,2,'') as PeriodTexts;

输出:

+---------------------------------------------------------------------------------------------------------------------------------------+
|                                                              PeriodTexts                                                              |
+---------------------------------------------------------------------------------------------------------------------------------------+
| 0102017, 0112017, 0122017, 0132017, 0012018, 0022018, 0032018, 0042018, 0052018, 0062018, 0072018, 0082018, 0092018, 0102018, 0112018 |
+---------------------------------------------------------------------------------------------------------------------------------------+