我想象的结果如下:
Category | Year | sum |
--------- ------ --------
A 2008 200
A 2009 0
B 2008 100
B 2009 5
... ... ...
即。每年和类的交易的总和。
有些情况下,类别一年内没有任何交易。在这些情况下,结果的第二行不会出现。我如何重新编写上述查询以便为每个类别包含2008,2009?
select category, to_char(trans_date, 'YYYY') year, sum(trans_value)
from transaction
group by category, to_char(trans_date, 'YYYY')
order by 1, 2;
答案 0 :(得分:1)
理想情况下,您需要一个类别表和年份表:
select c.category, y.year, nvl(sum(t.trans_value),0)
from categories c
cross join years y
left outer join transaction t
on to_char(t.trans_date, 'YYYY') = y.year
and t.category = c.category
group by c.category, y.year
order by 1, 2;
希望你有一个类别表,但你可能没有多年的表,在这种情况下你可以“伪造”这样的一个:
with years as
( select 2007+rownum year
from dual
connect by rownum < 10) -- returns 2008, 2009, ..., 2017
select c.category, y.year, nvl(sum(t.trans_value),0)
from categories c
cross join years y
left outer join transaction t
on to_char(t.trans_date, 'YYYY') = y.year
and t.category = c.category
group by c.category, y.year
order by 1, 2;
答案 1 :(得分:1)
使用partitioned outer join,您不需要类别表。
我使用了与“dcp”相同的交易表:
SQL> create table transactions
2 ( category varchar(1)
3 , trans_date date
4 , trans_value number(25,8)
5 );
Table created.
SQL> insert into transactions values ('A',to_date('2008-01-01','yyyy-mm-dd'),100.0);
1 row created.
SQL> insert into transactions values ('A',to_date('2008-02-01','yyyy-mm-dd'),100.0);
1 row created.
SQL> insert into transactions values ('B',to_date('2008-01-01','yyyy-mm-dd'),50.0);
1 row created.
SQL> insert into transactions values ('B',to_date('2008-02-01','yyyy-mm-dd'),50.0);
1 row created.
SQL> insert into transactions values ('B',to_date('2009-08-01','yyyy-mm-dd'),5.0);
1 row created.
对于分区外连接,您只需要一组年份来对外连接进行分区。在下面的查询中,我使用了2年(2008年和2009年),但您可以轻松调整该设置。
SQL> with the_years as
2 ( select 2007 + level year
3 , trunc(to_date(2007 + level,'yyyy'),'yy') start_of_year
4 , trunc(to_date(2007 + level + 1,'yyyy'),'yy') - interval '1' second end_of_year
5 from dual
6 connect by level <= 2
7 )
8 select t.category "Category"
9 , y.year "Year"
10 , nvl(sum(t.trans_value),0) "sum"
11 from the_years y
12 left outer join transactions t
13 partition by (t.category)
14 on (t.trans_date between y.start_of_year and y.end_of_year)
15 group by t.category
16 , y.year
17 order by t.category
18 , y.year
19 /
Category Year sum
-------- ---------- ----------
A 2008 200
A 2009 0
B 2008 100
B 2009 5
4 rows selected.
另请注意,我使用了start_of_year和end_of_year,因此如果要对trans_date进行过滤并且您在该列上有索引,则可以使用它。另一个选择是简单地使用trunc(t.trans_date)= y.year作为条件。
希望这有帮助。
的问候,
罗布。
答案 2 :(得分:0)
这是一个完整的,有效的例子:
CREATE TABLE transactions (CATEGORY VARCHAR(1), trans_date DATE, trans_value NUMBER(25,8));
CREATE TABLE YEAR (YEAR NUMBER(4));
CREATE TABLE categories (CATEGORY VARCHAR(1));
INSERT INTO categories VALUES ('A');
INSERT INTO categories VALUES ('B');
INSERT INTO transactions VALUES ('A',to_date('2008-01-01','YYYY-MM-DD'),100.0);
INSERT INTO transactions VALUES ('A',to_date('2008-02-01','YYYY-MM-DD'),100.0);
INSERT INTO transactions VALUES ('B',to_date('2008-01-01','YYYY-MM-DD'),50.0);
INSERT INTO transactions VALUES ('B',to_date('2008-02-01','YYYY-MM-DD'),50.0);
INSERT INTO transactions VALUES ('B',to_date('2009-08-01','YYYY-MM-DD'),5.0);
INSERT INTO YEAR VALUES (2008);
INSERT INTO YEAR VALUES (2009);
SELECT b.category
, b.year
, SUM(nvl(a.trans_value,0))
FROM (SELECT to_char(a.trans_date,'YYYY') YEAR
, CATEGORY
, SUM(NVL(trans_value,0)) trans_value
FROM transactions a
GROUP BY to_char(a.trans_date,'YYYY')
, a.category ) a
, (SELECT
DISTINCT a.category
, b.year
FROM categories a
, YEAR b ) b
WHERE b.year = to_char(a.year(+))
AND b.category = a.category(+)
GROUP BY
b.category
, b.year
ORDER BY 1
,2;
输出:
CATEGORY YEAR SUM(NVL(A.TRANS_VALUE,0))
1 A 2008 200
2 A 2009 0
3 B 2008 100
4 B 2009 5