嵌入式案例陈述

时间:2016-08-28 19:20:50

标签: sql sql-server tsql

我有一个查询(有效)但是,我希望能够这样做,所以我不需要重新运行查询来更改日期范围。

我所拥有的是提取客户名称和金额并将其总结。我需要按财政年度按月分解,所以我要做的就是更改年份并重新运行,但我希望提高查询效率,以便将来不需要更改(结束日期除外)对于一个新的风云)所以在它需要每个月(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

3 个答案:

答案 0 :(得分:2)

考虑一个递归CTE,它遍历每个会计年度,然后在现有派生表上运行CROSS JOIN...WHERECROSS 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     |

也许对于那些计算列上的某些索引,它会提供更好的性能。

相关问题