我使用以下表格: [http://sqlfiddle.com/#!4/eb1b79/1]
表公司:| ID | CNAME | COUNTRY | CLASS |
|----|-------|---------|-------|
| 1 | ABC | Russia | A |
| 2 | DEF | Russia | B |
表格值:
| ID | VALUE1 | VALUE2 | YEAR |
|----|--------|--------|------|
| 1 | 100 | 20 | 2005 |
| 1 | 200 | 40 | 2006 |
| 1 | 400 | 81 | 2007 |
| 1 | 101 | 16 | 2008 |
| 2 | 300 | 22 | 1999 |
| 2 | 900 | 30 | 2001 |
| 2 | 600 | 10 | 2002 |
我想做的是:
结果应该是:
| COUNTRY | CLASS | AMOUNT | PERCENTAGE1 | PERCENTAGE2 |
|---------|-------|--------|-------------|-------------|
| Russia | A | 3 | 0.75 | 0.428 |
| Russia | B | 0 | 0 | 0.428 |
有人能给我一个方法吗?
答案 0 :(得分:0)
LAG()或LEAD()分析函数可以为您提供上一年/明年的值,以便直接比较"今年与去年",或者您也可以这样做基于" a.year = b.year - 1"的联接。我会对两者进行基准测试,以确定哪种方法最适合您的数据量和分发。
然后,您将允许应用CASE语句将值变化范围分类为小于或大于2%。
然后,您可以根据该分类聚合数据以获取所需的值 - Ratio_to_Report分析函数可能会有所帮助。
答案 1 :(得分:0)
您可以使用分析 LEAD 功能来完成此操作。其余的是简单的数学和计算。
要根据年份获取每个 ID 的VALUE1/VALUE2
百分比更改,您可以执行以下操作:
lead(val) OVER(PARTITION BY ID ORDER BY ID, YEAR)
其中 VAL 为VALUE1/VALUE2
。
让我们来看一个测试用例:
设置
SQL> SELECT * FROM companies;
ID CNA COUNTR C
---------- --- ------ -
1 ABC Russia A
2 DEF Russia B
SQL>
SQL> SELECT * FROM vals;
ID VALUE1 VALUE2 YEAR
---------- ---------- ---------- ----------
1 100 20 2005
1 200 40 2006
1 400 81 2007
1 101 16 2008
2 300 22 1999
2 900 30 2001
2 600 10 2002
7 rows selected.
SQL>
现在,实现上述逻辑会给我们:
SQL> WITH data1 AS
2 ( SELECT t.*, ROUND(value1/value2, 2) val FROM vals t ORDER BY YEAR
3 ),
4 data2 AS
5 (SELECT t.*,
6 lead(val) OVER(PARTITION BY ID ORDER BY ID, YEAR) prev
7 FROM data1 t
8 )
9 SELECT t.*, ROUND(((val - prev)/val)* 100, 2) percentage FROM data2 t;
ID VALUE1 VALUE2 YEAR VAL PREV PERCENTAGE
---------- ---------- ---------- ---------- ---------- ---------- ----------
1 100 20 2005 5 5 0
1 200 40 2006 5 4.94 1.2
1 400 81 2007 4.94 6.31 -27.73
1 101 16 2008 6.31
2 300 22 1999 13.64 30 -119.94
2 900 30 2001 30 60 -100
2 600 10 2002 60
7 rows selected.
SQL>
答案 2 :(得分:0)
从你的话“2006年到2007年间是1.23%(2006年价值1 /价值2 = 5和2007年价值1 /价值2 = 4.938)”我总结道,
年度变化的公式为1 - current (v1/v2)/previous (v1/v2)
。看来,这些行具有未知的先前值
不应包括在进一步的计算中。如果不是这样,请删除过滤器where lvv is not null
。
应该删除value1或value2等于0的所有行,因为在当前或后续步骤中它们可以生成
除以零,但我没有在这里过滤它们,因为我不确定在这种情况下你想做什么。
并且不太清楚“谁在下一个特定年份之间没有变化超过2%”是什么意思。
我为此使用了条件abs(1-vv/lvv) <= .02
,但您可能希望将其更改为1-vv/lvv < .02
。
最终结果与你的不同,我怀疑你刚刚展示了结果应该是什么样的(例如,百分比2中的最后一个值是0.428,数量是0 - 这是不一致的)。 如果这不是您想要的,请编辑您的帖子,添加一些匹配输入的示例和所需输出,这样我们就可以验证: - )
with
step1 as (select id, year, cname, country, class, round(value1/value2, 8) vv,
round(lag(value1/value2) over (partition by id order by year), 8) lvv
from vals v join companies c using (id) where value2<>0 ),
step2 as (select step1.*, round(1-vv/lvv, 8) change_value,
case when abs(1-vv/lvv) <= .02 then 1 end as change,
count(1) over (partition by country) cc,
count(1) over (partition by country, class) ccc
from step1 where lvv is not null )
select country, class, count(change) amount,
round(count(change) / max(cc), 4) percentage1,
round(count(change) / max(ccc), 4) percentage2
from step2 group by country, class order by country, class
输出(我在其他国家增加了一些公司):
COUNTRY CLASS AMOUNT PERCENTAGE1 PERCENTAGE2
------- ----- ------ ----------- -----------
Brazil A 1 1 1
Canada A 1 0,25 0,5
Canada B 2 0,5 1
Russia A 2 0,4 0,6667
Russia B 0 0 0