从单个列和单个SQL表中的多个值计算年度百分比

从单个列和单个SQL表中的多个值计算年度百分比,sql,sql-server-2008-r2,cursor,percentage,calculation,Sql,Sql Server 2008 R2,Cursor,Percentage,Calculation,一直在寻找有关“从单个SQL表中单个列中的值计算百分比”的帮助 请允许我给你一点提示(如下所示): 1.)我在SQL2008上的测试环境中工作,需要部署SQL2012上的代码 2.)我使用SQL游标,因为我需要逐行处理结果和数据 3.)我使用查询将这些结果放入一个新表中: INSERT INTO tbl_1 (Column_names) SELECT @Column_names_from_cursor_variables 4.)每个id(截至目前)正好有3条记录,如下所示: present

一直在寻找有关“从单个SQL表中单个列中的值计算百分比”的帮助

请允许我给你一点提示(如下所示):

1.)我在SQL2008上的测试环境中工作,需要部署SQL2012上的代码

2.)我使用SQL游标,因为我需要逐行处理结果和数据

3.)我使用查询将这些结果放入一个新表中:

INSERT INTO tbl_1 (Column_names) 
SELECT @Column_names_from_cursor_variables

4.)每个id(截至目前)正好有3条记录,如下所示:

present_year_value (say,MAY2017), 
last_quarter_value (say,MAR2017)
last_year_value (say,MAY2016) 
详情如下:

id     yearValue   salesQty  
-----------------------------
1       052017        9876    
1       032017        5432    
1       052016        1000    
---------------------------    
2       052017        9876    
2       032017        5432    
2       052016        1000    
---------------------------    
3       052017        9876    
3       032017        5432    
3       052016        1000    
---------------------------
等等

我需要计算年百分比(同比)以及 每个id区块的QoQ百分比(季度对季度)如下所示:

QoQ --> ((present_year_value-last_quarter_value)/last_quarter_value)*100

YoY --> ((present_year_value-last_year_value)/last_year_value)*100

但是,不知何故,我无法在SQL游标中获得技巧。(使用SQL游标不是强制性的,但我需要逐行计算结果,因此我更喜欢游标)。

这可能是一个比您想要的更长的答案,但我想谈谈关于表设置的几个重要问题以及它们的重要性。我的解释会有点倒退,但希望很容易理解

您给出的示例数据可能有点混乱,因为每个id都是相同的,所以我将对它们进行一些更改,使其看起来像这样:

Data
+ -- + --------- + -------- + 
| Id | YearValue | SalesQty | 
+ -- + --------- + -------- + 
| 1  | 052017    | 9876     |
| 1  | 032017    | 5432     |  
| 1  | 052016    | 1000     | 
| 2  | 052017    | 6483     |
| 2  | 032017    | 2211     |
| 2  | 052016    | 580      |
| 3  | 052017    | 11316    |
| 3  | 032017    | 1216     |
| 3  | 052016    | 9487     |
+ -- + --------- + -------- +
首先,如果您的桌子看起来像这样,答案将是显而易见的:

Values
+ -- + ----------- + ---------------- + ---------------- + ------------- +
| Id | CurrentDate | PresentYearValue | LastQuarterValue | LastYearValue |
+ -- + ----------- + ---------------- + ---------------- + ------------- +
| 1  | 052017      | 9876             | 5432             | 1000          |
| 2  | 052017      | 6483             | 2211             | 580           |
| 3  | 052017      | 11316            | 1216             | 9487          |
+ -- + ----------- + ---------------- + ---------------- + ------------- +
然后,假设SalesQty字段的数据类型不是十进制,则可以使用以下查询:

select    Id
        , cast((PresentYearValue - LastQuarterValue) as float) / (LastQuarterValue) * 100 as QoQ
        , cast((PresentYearValue - LastYearValue) as float) / (LastYearValue)  * 100 as YoY
    from Values
select *, ROW_NUMBER() over (partition by Id order by YearValue desc) as RN
    from Values
您将得到以下结果:

Results
+ -- + ------ + ------- + 
| Id | QoQ    | YoY     |
+ -- + ------ + ------- +
| 1  | 81.81  | 887.6   |
| 2  | 193.22 | 1017.76 |
| 3  | 830.59 | 19.28   |
+ -- + ------ + ------- + 
非常简单和直接

但是…

在数据库中进行这样的更改可能并不总是可行的。例如,数据可能不仅仅用于这个问题,以您的格式存储数据可能是最好的。在这种情况下,下面是如何转换数据以获得所需结果的演练

为了使数据表看起来像值表,我们需要在Id内进行显式排序。在这种情况下,我们可以在YearValue字段上下单,但前提是它们是实际日期,而不是字符串。考虑下面的查询:

select    Id
        , cast((PresentYearValue - LastQuarterValue) as float) / (LastQuarterValue) * 100 as QoQ
        , cast((PresentYearValue - LastYearValue) as float) / (LastYearValue)  * 100 as YoY
    from Values
select *, ROW_NUMBER() over (partition by Id order by YearValue desc) as RN
    from Values
这为我们提供了一个类似于数据的表格,但有一个新字段:

Data
+ -- + --------- + -------- + -- +
| Id | YearValue | SalesQty | RN |
+ -- + --------- + -------- + -- + 
| 1  | 052017    | 9876     | 1  | -- PresentYearValue
| 1  | 032017    | 5432     | 2  | -- LastQuarterValue
| 1  | 052016    | 1000     | 3  | -- LastYearValue
| 2  | 052017    | 6483     | 1  | -- repeat
| 2  | 032017    | 2211     | 2  |
| 2  | 052016    | 580      | 3  |
| 3  | 052017    | 11316    | 1  |
| 3  | 032017    | 1216     | 2  |
| 3  | 052016    | 9487     | 3  |
+ -- + --------- + -------- + -- +
注意RN和(当前、上一个)(季度、年度)值之间的对应关系。我们可以利用这种对应关系将行“透视”成列

select    a.Id
        , case RN when 1 then a.YearValue end as CurrentDate
        , case RN when 1 then a.SalesQty end as PresentYearValue
        , case RN when 2 then a.SalesQty end as LastQuarterValue
        , case RN when 3 then a.SalesQty end as LastYearValue
        , a.RN as RN
    from (
        select *, ROW_NUMBER() over (partition by id order by SalesQty desc) as RN
            from #Values
    ) a
这给了我们一张像这样的桌子

+ -- + ----------- + ---------------- + ---------------- + ------------- + -- +
| Id | CurrentDate | PresentYearValue | LastQuarterValue | LastYearValue | RN |
+ -- + ----------- + ---------------- + ---------------- + ------------- + -- +
| 1  | 2017-05-01  | 9876             | NULL             | NULL          | 1  |
| 1  | 2017-05-01  | NULL             | 5432             | NULL          | 2  |
| 1  | 2017-05-01  | NULL             | NULL             | 1000          | 3  |
| 2  | 2017-05-01  | 6483             | NULL             | NULL          | 1  |
| 2  | 2017-05-01  | NULL             | 2211             | NULL          | 2  |
| 2  | 2017-05-01  | NULL             | NULL             | 580           | 3  |
| 3  | 2017-05-01  | 11316            | NULL             | NULL          | 1  |
| 3  | 2017-05-01  | NULL             | 9487             | NULL          | 2  |
| 3  | 2017-05-01  | NULL             | NULL             | 1216          | 3  |
+ -- + ----------- + ---------------- + ---------------- + ------------- + -- +
通过快速分组,我们可以折叠此表

select    a.Id
        , max(case RN when 1 then a.YearValue end) as CurrentDate
        , max(case RN when 1 then a.SalesQty end) as PresentYearValue
        , max(case RN when 2 then a.SalesQty end) as LastQuarterValue
        , max(case RN when 3 then a.SalesQty end) as LastYearValue
    from (
        select *, ROW_NUMBER() over (partition by id order by YearValue desc) as RN
            from Data
    ) a
    group by a.Id
这正好给我们提供了值表:

Values
+ -- + ----------- + ---------------- + ---------------- + ------------- +
| Id | CurrentDate | PresentYearValue | LastQuarterValue | LastYearValue |
+ -- + ----------- + ---------------- + ---------------- + ------------- +
| 1  | 052017      | 9876             | 5432             | 1000          |
| 2  | 052017      | 6483             | 2211             | 580           |
| 3  | 052017      | 11316            | 1216             | 9487          |
+ -- + ----------- + ---------------- + ---------------- + ------------- +
最后,将最后一个查询塞入CTE,并将其与第一个查询组合,以获得所需的值:

; with
    Values as (
        select    a.Id
                , max(case RN when 1 then a.YearValue end) as CurrentDate
                , max(case RN when 1 then a.SalesQty end) as PresentYearValue
                , max(case RN when 2 then a.SalesQty end) as LastQuarterValue
                , max(case RN when 3 then a.SalesQty end) as LastYearValue
            from (
                select *, ROW_NUMBER() over (partition by id order by YearValue desc) as RN
                    from Data
            ) a
            group by a.Id
    )
select    Id
        , cast((PresentYearValue - LastQuarterValue) as float) / (LastQuarterValue) * 100 as QoQ
        , cast((PresentYearValue - LastYearValue) as float) / (LastYearValue)  * 100 as YoY
    from Values

在from子句之前添加所需的任何其他字段和into子句。希望这有帮助

这张桌子上的id是什么?(如产品id或与另一个表相关的任何唯一id?)您好,Samanvitha,该id是表中的主键,并且它(准确地)有3条记录,每一条记录有什么问题?你得到的结果中有什么是不正确的?哦,天哪@KindaTechy,我已经阅读了这篇教程的回复,但是从外观上看,我认为这是可行的(尽管我仍然需要尝试整个过程)。请给我一些时间来思考一下这段代码,并进行一些小的修改。我一定会给你回复的。再次感谢你!提前,一切归功于你_KindaTechy@E.Hunt我希望这对你有用。如果没有,请告诉我,也许我们可以找出原因:)是的,它是有效的,在您的逻辑帮助下,我能够修改它,非常感谢您的指导。从你的辛勤工作中学到了很多。@E.Hunt,很高兴听到这个消息。请随意将此标记为答案。