一直在寻找一些关于"从单个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)。
答案 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子句之前添加所需的任何其他字段,并将添加到子句中。希望这有帮助!