我有一个查询(有效)但是,我希望能够这样做,所以我不需要重新运行查询来更改日期范围。
我所拥有的是提取客户名称和金额并将其总结。我需要按财政年度按月分解,所以我要做的就是更改年份并重新运行,但我希望提高查询效率,以便将来不需要更改(结束日期除外)对于一个新的风云)所以在它需要每个月(7月到6月)的总和后,我希望它显示风云。因此,2014年至2015年的日期范围应显示一个名为FY的列,并在列中显示2015。我很确定我在正确的轨道但不在那里。我只展示了我为第一个案例所做的工作(将在其他情况下复制)
这可能只是一个IF语句循环而不是另一个case语句吗?任何有关方向的帮助都可以帮助我学习。我做到了这一点,但只是想让代码更有效地使用
Declare @StartDate datetime
Declare @EndDate datetime
set @StartDate = convert(datetime, '07/01/2014')
set @EndDate = convert(datetime, '06/30/2017')
select
d.CUSTNMBR Customer_ID,
d.CUSTNAME Customer_Name,
'A' as Company,
sum(case when month(d.DOCDATE) = 7
then d.SALES else 0 end) July,
case when datetime between '07/01/2016' and '06/30/2017' as '2017'
when datetime between '07/01/2015' and '06/30/2016' as '2016'
when datetime between '07/01/2014' and '06/30/2015' as '2015'
END
sum(case when month(d.DOCDATE) = 8
then d.SALES else 0 end) August,
sum(case when month(d.DOCDATE) = 9
then d.SALES else 0 end) September,
sum(case when month(d.DOCDATE) = 10
then d.SALES else 0 end) October,
sum(case when month(d.DOCDATE) = 11
then d.SALES else 0 end) November,
sum(case when month(d.DOCDATE) = 12
then d.SALES else 0 end) December,
sum(case when month(d.DOCDATE) = 1
then d.SALES else 0 end) January,
sum(case when month(d.DOCDATE) = 2
then d.SALES else 0 end) February,
sum(case when month(d.DOCDATE) = 3
then d.SALES else 0 end) March,
sum(case when month(d.DOCDATE) = 4
then d.SALES else 0 end) April,
sum(case when month(d.DOCDATE) = 5
then d.SALES else 0 end) May,
sum(case when month(d.DOCDATE) = 6
then d.SALES else 0 end) June,
sum(d.SALES) 'Year to Date'
from
(select s.DOCDATE, s.CUSTNMBR, c.CUSTNAME,
case s.SOPTYPE
when 3 then s.DOCAMNT
when 4 then s.DOCAMNT*-1
end SALES
from a1.dbo.S200 s
left outer join a1.dbo.RM1 c
on s.CUSTNMBR = c.CUSTNMBR
where s.VOIDSTTS = 0
and s.SOPTYPE in (3,4) and
s.DOCDATE between @StartDate and @EndDate -- Fiscal Year
) d
group by d.CUSTNMBR, d.CUSTNAME
答案 0 :(得分:2)
考虑一个递归CTE,它遍历每个会计年度,然后在现有派生表上运行CROSS JOIN...WHERE
(CROSS APPLY
也可以工作)。 WHERE
条件DOCDate
到会计年度的开始和结束范围。然后,只需更改每个会计年度的申报行。实际上,您可以设置@end INT = 2020
来预测未来的数据!
DECLARE @start INT = 2014;
DECLARE @end INT = 2016;
WITH fiscalyears AS (
SELECT @start + 1 AS FY,
CONVERT(datetime, cast(1 as varchar)+'/'+cast(7 as varchar)+'/'+cast(@start as varchar), 103) As StartRng,
CONVERT(datetime, cast(30 as varchar)+'/'+cast(6 as varchar)+'/'+cast(@start + 1 as varchar), 103) As EndRng
UNION ALL
SELECT FY + 1,
CONVERT(datetime, cast(1 as varchar)+'/'+cast(7 as varchar)+'/'+cast(FY + 1 as varchar), 103),
CONVERT(datetime, cast(30 as varchar)+'/'+cast(6 as varchar)+'/'+cast(FY + 2 as varchar), 103)
FROM fiscalyears
WHERE FY < @end
)
-- FY StartRng EndRng
-- 2015 2014-07-01 00:00:00.000 2015-06-30 00:00:00.000
-- 2016 2015-07-01 00:00:00.000 2016-06-30 00:00:00.000
---2017 2016-07-01 00:00:00.000 2017-06-30 00:00:00.000
select
d.CUSTNMBR Customer_ID,
d.CUSTNAME Customer_Name,
'A' as Company,
d.FY As FY,
sum(case when month(d.DOCDATE) = 7 then d.SALES else 0 end) AS July,
sum(case when month(d.DOCDATE) = 8 then d.SALES else 0 end) AS August,
sum(case when month(d.DOCDATE) = 9 then d.SALES else 0 end) AS September,
sum(case when month(d.DOCDATE) = 10 then d.SALES else 0 end) AS October,
sum(case when month(d.DOCDATE) = 11 then d.SALES else 0 end) AS November,
sum(case when month(d.DOCDATE) = 12 then d.SALES else 0 end) AS December,
sum(case when month(d.DOCDATE) = 1 then d.SALES else 0 end) AS January,
sum(case when month(d.DOCDATE) = 2 then d.SALES else 0 end) AS February,
sum(case when month(d.DOCDATE) = 3 then d.SALES else 0 end) AS March,
sum(case when month(d.DOCDATE) = 4 then d.SALES else 0 end) AS April,
sum(case when month(d.DOCDATE) = 5 then d.SALES else 0 end) AS May,
sum(case when month(d.DOCDATE) = 6 then d.SALES else 0 end) AS June,
sum(d.SALES) 'Year to Date'
from
(select f.FY, s.DOCDATE, s.CUSTNMBR, c.CUSTNAME,
case s.SOPTYPE
when 3 then s.DOCAMNT
when 4 then s.DOCAMNT*-1
end SALES
from a1.dbo.S200 s
left outer join a1.dbo.RM1 c
on s.CUSTNMBR = c.CUSTNMBR
cross join fiscalyears f
where s.VOIDSTTS = 0
and s.SOPTYPE in (3,4)
and s.DOCDATE between f.StartRng and f.EndRng) d
group by d.CUSTNMBR,
d.CUSTNAME,
d.FY
答案 1 :(得分:0)
您是否有权创建功能?如果是这样,为FY创建一个(可重用的)标量函数。 E.g:
A
然后使用SELECT ...中的功能
CREATE FUNCTION dbo.FY (input_date as smalldatetime)
RETURNS int
BEGIN
DECLARE @return int
SET @return = year(input_date)
IF month(input_date) <= 6
@return = @return + 1
RETURN @return
END
否则,您可以内联函数 - 例如:
SELECT
...,
FY(d.DOCDATE),
...
FROM
...
另外值得一提 - 看起来你正在艰难地命名你的月份。
请改为尝试:
SELECT
...,
CASE WHEN Month(d.DOCDATE) <= 6 THEN 1 ELSE 0 END + year(d.DOCDATE) as FY
...
也...
建议将查询的数据和布局分开一些(例如,您为几个月创建水平布局的地方) - 您可能会喜欢PIVOT(https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx)可以为您做什么。
如果这样做,您可以保持查询数据更清晰 - 然后在其他查询中使用它的输出。更多可重用性=为您减少工作量! : - )
答案 2 :(得分:0)
我建议S200表将计算列作为帮助器,如下所示:
create table S200
(
CUSTNMBR varchar(10) null,
DOCDATE date null,
SOPTYPE int null,
DOCAMNT money null,
FISCALYEAR as datepart(year, DOCDATE) +
case when datepart(month, DOCDATE) >= 7 then 1 else 0 end,
FISCALMONTHNAME as (datename(month, DOCDATE))
)
然后我们可以简单地PIVOT
:
select
*,
isnull([January], 0) +
isnull([February], 0) +
isnull([March], 0) +
isnull([April], 0) +
isnull([May], 0) +
isnull([June], 0) +
isnull([July], 0) +
isnull([August], 0) +
isnull([September], 0) +
isnull([October], 0) +
isnull([November], 0) +
isnull([December], 0) as YearToDate
from
(
select
s.CUSTNMBR,
s.FISCALYEAR,
FISCALMONTHNAME,
case s.SOPTYPE
when 3 then s.DOCAMNT
when 4 then -s.DOCAMNT
end as SALES
from
S200 as s
)
as d
pivot
(
sum
(
d.SALES
)
for d.FISCALMONTHNAME in
(
[January],
[February],
[March],
[April],
[May],
[June],
[July],
[August],
[September],
[October],
[November],
[December]
)
)
as p
order by 2, 1
如果您有一个Tally表,您可以从2014年开始为3位客户模拟填充S200 3年:
truncate table S200
insert
S200
select
101 + cast(3 * rand(checksum(newid())) as int),
dateadd(day, cast(3 * 365 * rand(checksum(newid())) as int),
datefromparts(2014, 1, 1)),
case when rand(checksum(newid())) > .6 then 4 else 3 end,
1 + cast(100 * rand(checksum(newid())) as int)
from
Tally
where
Id <= 1000
您可能会得到以下结果:
| CUSTNMBR | FISCALYEAR | January | February | March | April | May | June | July | August | September | October | November | December | YearToDate |
|----------|------------|---------|----------|---------|--------|---------|---------|---------|---------|-----------|---------|----------|----------|------------|
| 101 | 2014 | 160.00 | 143.00 | 139.00 | 28.00 | 247.00 | 28.00 | NULL | NULL | NULL | NULL | NULL | NULL | 745.00 |
| 102 | 2014 | 24.00 | 158.00 | -244.00 | -85.00 | 103.00 | 20.00 | NULL | NULL | NULL | NULL | NULL | NULL | -24.00 |
| 103 | 2014 | 123.00 | -167.00 | -6.00 | -30.00 | -53.00 | 15.00 | NULL | NULL | NULL | NULL | NULL | NULL | -118.00 |
| 101 | 2015 | 14.00 | 200.00 | 304.00 | 137.00 | 236.00 | -245.00 | 289.00 | 258.00 | 192.00 | -13.00 | 275.00 | 9.00 | 1656.00 |
| 102 | 2015 | -40.00 | 115.00 | -36.00 | 142.00 | -18.00 | 48.00 | -262.00 | -71.00 | 24.00 | 189.00 | -166.00 | -49.00 | -124.00 |
| 103 | 2015 | 265.00 | -103.00 | 73.00 | -50.00 | 61.00 | -268.00 | -20.00 | -214.00 | -21.00 | 50.00 | -48.00 | -204.00 | -479.00 |
| 101 | 2016 | 207.00 | -201.00 | 34.00 | 397.00 | -156.00 | 267.00 | -272.00 | -156.00 | -61.00 | -98.00 | 575.00 | 107.00 | 643.00 |
| 102 | 2016 | 27.00 | 20.00 | 199.00 | 328.00 | 44.00 | 55.00 | 447.00 | 188.00 | -57.00 | -118.00 | -1.00 | 74.00 | 1206.00 |
| 103 | 2016 | -114.00 | 333.00 | 299.00 | 145.00 | 80.00 | -8.00 | 58.00 | -151.00 | 44.00 | 799.00 | 218.00 | 14.00 | 1717.00 |
| 101 | 2017 | NULL | NULL | NULL | NULL | NULL | NULL | -154.00 | -56.00 | 192.00 | -283.00 | 371.00 | 155.00 | 225.00 |
| 102 | 2017 | NULL | NULL | NULL | NULL | NULL | NULL | 11.00 | -50.00 | 82.00 | 8.00 | 562.00 | -26.00 | 587.00 |
| 103 | 2017 | NULL | NULL | NULL | NULL | NULL | NULL | 294.00 | -93.00 | -51.00 | 29.00 | 322.00 | 392.00 | 893.00 |
也许对于那些计算列上的某些索引,它会提供更好的性能。