从单列和单个SQL表

时间:2017-05-30 05:50:01

标签: sql sql-server-2008-r2 cursor percentage calculation

一直在寻找一些关于"从单个SQL表中单个列中存在的值计算百分比的帮助"。

请允许我给你一个小小的提示(如下所示):

1。)我正在使用SQL2008上的测试环境,需要部署SQL2012上的代码。

2。)我正在使用SQL Cursor,因为我需要逐行处理结果和

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    
---------------------------

等等...

我需要计算Percentage_YoY(同比)以及 每个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 Cursor中获得技巧。 (使用SQL Cursor不是必需的,但我需要逐行计算结果,因此我更喜欢Cursor)。

1 个答案:

答案 0 :(得分:0)

这可能是一个比你想要的更长的答案,但我想解决有关你的表设置及其重要性的几个重要事项。我的解释有点倒退,但希望它很容易理解。

您提供的示例数据可能会有点令人困惑,因为每个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

您将获得以下结果:

Results
+ -- + ------ + ------- + 
| Id | QoQ    | YoY     |
+ -- + ------ + ------- +
| 1  | 81.81  | 887.6   |
| 2  | 193.22 | 1017.76 |
| 3  | 830.59 | 19.28   |
+ -- + ------ + ------- + 

非常简单明了。

<强> BUT ...

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

要使我们的数据表看起来像我们的值表,我们需要在Id中明确排序。在这种情况下,我们可以在YearValue字段上订购,但只有,如果它们是实际日期,而不是字符串。请考虑以下查询:

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与(现在,最后)(季度,年度)值之间的对应关系。我们可以利用这种对应关系&#34; pivot&#34;行成列。

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子句之前添加所需的任何其他字段,并将添加到子句中。希望这有帮助!