财政期间的清单编号顺序
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 |
+---------------------------------------------------------------------------------------------------------------------------------------+
在 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 |
+---------------------------------------------------------------------------------------------------------------------------------------+