使用SQL

时间:2018-10-17 04:27:51

标签: sql-server tsql totals

我有以下代码:

create table #attr( enroll_month datetime ,cncl_mth datetime,
mth int,
tot_orders int,tot_cancel int, active_count int, attr_rate int , retn_rate 
int
)

DECLARE
@enroll_mth datetime ,@cncl_mth datetime, @mth int ,
@tot_orders numeric, @tot_cancel numeric,
@attr_rate numeric(6,2), @retn_rate numeric(6,2),
@active_count int
DECLARE att_cursor CURSOR FOR
SELECT
d.Enroll_Month, d.cncl_mth, d.mth,
s.tot_orders, d.tot_cancel
FROM #Summary s with (nolock),
#Detail d with (nolock)
WHERE
s.Enroll_Month = d.Enroll_Month


OPEN att_cursor
FETCH NEXT FROM att_cursor INTO @enroll_mth, @cncl_mth, @mth, @tot_orders, 
@tot_cancel

DECLARE
@old_enroll_mth datetime,
@old_cncl_mth datetime, @old_mth int, @month datetime ,
@intial varchar(1),
@old_active_cnt int, @old_tot_cancel int,
@old_retn_rate numeric(6,2), @old_attr_rate numeric(6,2),
@counter int

SELECT @old_enroll_mth = ''
SELECT @intial = 'Y'

WHILE @@FETCH_STATUS = 0
BEGIN
IF (@old_enroll_mth <> @enroll_mth)
BEGIN
SELECT @active_count = @active_count - @tot_cancel
SELECT @intial = 'N'
END
ELSE
BEGIN
SELECT @active_count = @tot_orders - @tot_cancel
SELECT @intial = 'Y'
END

SELECT @retn_rate = (@active_count / @tot_orders) * 100
SELECT @attr_rate = 100 - @retn_rate

INSERT INTO #Attr (
 enroll_month, cncl_mth, mth, tot_orders, tot_cancel, 
active_count, attr_rate, retn_rate ) 
VALUES (
@enroll_mth, @cncl_mth, @mth, @tot_orders, @tot_cancel,
@active_count, @attr_rate, @retn_rate)





SELECT @old_enroll_mth = @enroll_mth
SELECT @old_mth = @mth
SELECT @old_retn_rate = @retn_rate
SELECT @old_attr_rate = @attr_rate
SELECT @old_active_cnt = @active_count
SELECT @old_cncl_mth = @cncl_mth
SELECT @old_tot_cancel = @tot_cancel

FETCH NEXT FROM att_cursor INTO @enroll_mth, @cncl_mth, @mth, @tot_orders, 
@tot_cancel
END

CLOSE att_cursor
DEALLOCATE att_cursor

select * from #attr

将返回以下输出。

enroll_month cncl_mth mth tot_orders tot_cancel active_count attr_rate retn_rate
01/01/17    01/01/17    1   390         160        230           41       58
01/01/17   02/01/17     2   390          26        364            6       93
01/01/17    03/01/17    3   390          23         594          -52      152

它正在显示第mth = 1个活动计数的正确值。尽管对于mth = 2来说应该是(230-26 = 204),对于mth = 3来说应该是(204-23 = 181)。

我已经发布了两个脚本,以填充上述脚本中使用的摘要表和明细表。

create table #summary
(
enroll_month datetime,
tot_orders int
)
go
insert into #summary(enroll_month, tot_orders)
values ('2017-01-01 00:00:00.000', 390)

insert into #summary(enroll_month, tot_orders )
values ('2017-02-01 00:00:00.000', 615)
go

drop table #Detail
go
create table #detail
(
enroll_month datetime,
cncl_mnth datetime,
mth int,
tot_cancel int
)
go
insert into #detail(enroll_month,cncl_mnth,mth,tot_cancel)
values ('2017-01-01 00:00:00.000', '2017-01-01 00:00:00.000', 1, 160)

insert into #detail(enroll_month,cncl_mnth,mth,tot_cancel )
values ('2017-01-01 00:00:00.000','2017-02-01 00:00:00.000', 2, 26)

insert into #detail(enroll_month,cncl_mnth,mth,tot_cancel)
values ('2017-01-01 00:00:00.000','2017-03-01 00:00:00.000', 3, 23)
go

可以帮忙吗?

谢谢, 帕姆

3 个答案:

答案 0 :(得分:0)

这有帮助吗??

    create table #summary ( enroll_month datetime, tot_orders int ) 
    insert into #summary(enroll_month, tot_orders) values ('2017-01-01 00:00:00.000', 390)
    insert into #summary(enroll_month, tot_orders ) values ('2017-02-01 00:00:00.000', 615) 


    create table #detail ( enroll_month datetime, cncl_mnth datetime, mth int, tot_cancel int ) 
    insert into #detail(enroll_month,cncl_mnth,mth,tot_cancel) values ('2017-01-01 00:00:00.000', '2017-01-01 00:00:00.000', 1, 160)
    insert into #detail(enroll_month,cncl_mnth,mth,tot_cancel ) values ('2017-01-01 00:00:00.000','2017-02-01 00:00:00.000', 2, 26)
    insert into #detail(enroll_month,cncl_mnth,mth,tot_cancel) values ('2017-01-01 00:00:00.000','2017-03-01 00:00:00.000', 3, 23)



    SELECT
    d.Enroll_Month, d.cncl_mnth, d.mth,
    s.tot_orders, d.tot_cancel
    into #tmp
    FROM #Summary s with (nolock),
    #Detail d with (nolock)
    WHERE
    s.Enroll_Month = d.Enroll_Month

    ;with cte
    As
    (
        Select Enroll_Month,cncl_mnth,mth,tot_orders,tot_cancel,
        tot_orders-tot_cancel as active_count,
        FLOOR(100-(CAST((tot_orders-tot_cancel) AS FLOAT)/CAST(tot_orders AS FLOAT))*100) as attr_rate, 
        FLOOR((CAST((tot_orders-tot_cancel) AS FLOAT)/CAST(tot_orders AS FLOAT))*100) as retn_rate
        from #tmp where mth=1

        Union All

        Select t.Enroll_Month,t.cncl_mnth,t.mth,t.tot_orders,t.tot_cancel,
        c.active_count-t.tot_cancel as active_count,
        FLOOR(100-(CAST((c.active_count-t.tot_cancel) AS FLOAT)/CAST(c.active_count AS FLOAT))*100) as attr_rate,   
        FLOOR((CAST((c.active_count-t.tot_cancel) AS FLOAT)/CAST(c.active_count AS FLOAT))*100) as retn_rate
        from #tmp t
        JOIN cte c on t.mth=c.mth+1
    )

    select * from cte

    Drop Table #tmp
    Drop table #summary
    Drop table #detail

输出为:

Enroll_Month                    cncl_mnth          mth  tot_orders  tot_cancel  active_count    attr_rate   retn_rate
2017-01-01 00:00:00.000  2017-01-01 00:00:00.000    1      390         160         230               41          58
2017-01-01 00:00:00.000  2017-02-01 00:00:00.000    2      390         26          204               11          88
2017-01-01 00:00:00.000  2017-03-01 00:00:00.000    3      390         23          181               11          88

答案 1 :(得分:0)

我将使用common table expression (CTE)并使用SUMOVER子句产生总数。

SQL:

WITH
summary
AS
(
    SELECT tbl.* FROM (VALUES
      ( '01-Jan-2017', 390)
    , ( '01-Feb-2017', 615)
    ) tbl ([enroll_month], [tot_orders]) 
)
, 
details
AS
(
    SELECT tbl.* FROM (VALUES
      ( '01-Jan-2017', '01-Jan-2017', 1, 160)
    , ( '01-Jan-2017', '01-Feb-2017', 2, 26)
    , ( '01-Jan-2017', '01-Mar-2017', 3, 23)
    ) tbl ([enroll_month], [cncl_mnth], [mth], [tot_cancel]) 
)
,
detail_active_count
AS
(
    SELECT
          d.[enroll_month]
        , d.[cncl_mnth]
        , s.[tot_orders]
        , d.[mth]
        , d.[tot_cancel]
        , [active_count] = s.[tot_orders] - SUM(d.[tot_cancel]) OVER (PARTITION BY d.[enroll_month] ORDER BY d.[mth]) 
    FROM 
        summary AS s
        INNER JOIN details as d ON d.[enroll_month] = s.[enroll_month]
)
SELECT
      c.* 
    , [attr_rate] = FLOOR(100 - (CAST((c.[active_count]) AS FLOAT) / CAST(c.[tot_orders] AS FLOAT)) * 100)
    , [retn_rate] = FLOOR((CAST((c.[active_count]) AS FLOAT) / CAST(c.[tot_orders] AS FLOAT)) * 100)
FROM 
    detail_active_count AS c

结果:

screenshot

执行计划示例:

screenshot

答案 2 :(得分:0)

您的问题在这部分:

labix_mgo

您已经颠倒了所需的逻辑;).. 所以你需要像这样:

IF (@old_enroll_mth <> @enroll_mth)
BEGIN
SELECT @active_count = @active_count - @tot_cancel
SELECT @intial = 'N'
END
ELSE
BEGIN
SELECT @active_count = @tot_orders - @tot_cancel
SELECT @intial = 'Y'
END

已更新

样本数据

IF (@old_enroll_mth <> @enroll_mth)
BEGIN
    SELECT @active_count = @tot_orders - @tot_cancel
    SELECT @intial = 'Y'
END
ELSE
BEGIN
    SELECT @active_count = @active_count - @tot_cancel
    SELECT @intial = 'N'
END

使用上面的示例和您的DECLARE @summary TABLE (enroll_month datetime, tot_orders int) DECLARE @detail TABLE (enroll_month datetime, cncl_mnth datetime, mth int, tot_cancel int) DECLARE @attr TABLE (enroll_month datetime ,cncl_mth datetime, mth int, tot_orders int,tot_cancel int, active_count int, attr_rate int , retn_rate int) insert into @summary(enroll_month, tot_orders) values ('2017-01-01 00:00:00.000', 390), ('2017-02-01 00:00:00.000', 615) insert into @detail(enroll_month,cncl_mnth,mth,tot_cancel) values ('2017-01-01 00:00:00.000', '2017-01-01 00:00:00.000', 1, 160), ('2017-01-01 00:00:00.000','2017-02-01 00:00:00.000', 2, 26), ('2017-01-01 00:00:00.000','2017-03-01 00:00:00.000', 3, 23) (修改了上面的逻辑-翻转了):

CURSOR

如果您想采用另一种没有DECLARE @enroll_mth datetime ,@cncl_mth datetime, @mth int , @tot_orders numeric, @tot_cancel numeric, @attr_rate numeric(6,2), @retn_rate numeric(6,2), @active_count int DECLARE att_cursor CURSOR FOR SELECT d.Enroll_Month, d.cncl_mnth, d.mth, s.tot_orders, d.tot_cancel FROM @summary s, @Detail d WHERE s.Enroll_Month = d.Enroll_Month OPEN att_cursor FETCH NEXT FROM att_cursor INTO @enroll_mth, @cncl_mth, @mth, @tot_orders, @tot_cancel DECLARE @old_enroll_mth datetime, @old_cncl_mth datetime, @old_mth int, @month datetime , @intial varchar(1), @old_active_cnt int, @old_tot_cancel int, @old_retn_rate numeric(6,2), @old_attr_rate numeric(6,2), @counter int SELECT @old_enroll_mth = '' SELECT @intial = 'Y' WHILE @@FETCH_STATUS = 0 BEGIN IF (@old_enroll_mth <> @enroll_mth) BEGIN SELECT @active_count = @tot_orders - @tot_cancel SELECT @intial = 'Y' END ELSE BEGIN SELECT @active_count = @active_count - @tot_cancel SELECT @intial = 'N' END SELECT @retn_rate = (@active_count / @tot_orders) * 100 SELECT @attr_rate = 100 - @retn_rate INSERT INTO @attr (enroll_month, cncl_mth, mth, tot_orders, tot_cancel, active_count, attr_rate, retn_rate ) VALUES (@enroll_mth, @cncl_mth, @mth, @tot_orders, @tot_cancel, @active_count, @attr_rate, @retn_rate) SELECT @old_enroll_mth = @enroll_mth SELECT @old_mth = @mth SELECT @old_retn_rate = @retn_rate SELECT @old_attr_rate = @attr_rate SELECT @old_active_cnt = @active_count SELECT @old_cncl_mth = @cncl_mth SELECT @old_tot_cancel = @tot_cancel FETCH NEXT FROM att_cursor INTO @enroll_mth, @cncl_mth, @mth, @tot_orders, @tot_cancel END CLOSE att_cursor DEALLOCATE att_cursor SELECT * FROM @attr CURSOR的方法,则可以改用此方法:

CTE