Reputation: 11
Suppose I have some data and doing a query, I got something like this -
-----------------------------
trun(date) | location | sum |
-----------------------------
14-June-11 | B | 5 |
-----------------------------
13-June-11 | B | 5 |
-----------------------------
14-June-11 | C | 5 |
-----------------------------
13-June-11 | C | 5 |
-----------------------------
SELECT TRUNC(DATE_TIME),MIN(LOCATION) AS LOCATION, SUM(CREDIT) AS SUM FROM
(SELECT * FROM TABLE A
WHERE
A.DATE_TIME >= TO_DATE('13/JUN/2011','dd/mon/yyyy')
AND A.DATE_TIME <= TO_DATE('15/JUN/2011','dd/mon/yyyy'))
GROUP BY TRUNC(DATE_TIME), LOCATION
There's another table B where there's a location list
----
A |
----
B |
----
C |
----
I want something like this -
-----------------------------
trun(date) | location | sum |
-----------------------------
14-June-11 | A | 0 |
-----------------------------
14-June-11 | B | 5 |
-----------------------------
14-June-11 | C | 5 |
-----------------------------
13-June-11 | A | 0 |
-----------------------------
13-June-11 | B | 5 |
-----------------------------
13-June-11 | C | 5 |
-----------------------------
I tried to use a right join with the table B, but I can't create 2 separate records for 14-June-11 and 13-June-11. Any advice or help will be greatly appreciated.
Upvotes: 1
Views: 78
Reputation: 17944
There is no need to read tablea
separately to get the distinct date_time
values. Instead, this is a job for the often overlooked partitioned outer join.
Here is your answer using that feature. (The tables and inserts from William Robertson's answer will work to set this up).
select a.date_time
, b.location
, coalesce(a.asum,0) as asum
from ( SELECT trunc(a.date_time) date_time,
a.location,
sum(a.credit) as asum
FROM tablea a
WHERE a.date_time between date '2011-06-13' and date '2011-06-15' or a.date_time is null
GROUP BY trunc(a.date_time), a.location ) a
-- This is the key part here...
PARTITION BY (date_time)
right join tableb b on a.location = b.location
order by 1 desc, 2;
What that PARTITION BY
keyword does is makes the outer join operate separately for each distinct value of date_time
, creating null outer-join rows as needed for each one.
+-----------+----------+------+ | DATE_TIME | LOCATION | ASUM | +-----------+----------+------+ | 14-JUN-11 | A | 0 | | 14-JUN-11 | B | 5 | | 14-JUN-11 | C | 5 | | 13-JUN-11 | A | 0 | | 13-JUN-11 | B | 5 | | 13-JUN-11 | C | 5 | +-----------+----------+------+
Upvotes: 3
Reputation: 16001
How about this:
with dates as
( select distinct trunc(date_time) as date_time from tablea )
select trunc(d.date_time)
, b.location
, coalesce(sum(credit),0) as sum
from dates d
cross join tableb b
left join tablea a
on a.location = b.location
and trunc(a.date_time) = d.date_time
where a.date_time between date '2011-06-13' and date '2011-06-15' or a.date_time is null
group by d.date_time, b.location
order by 1 desc, 2;
Test data:
create table tablea
( date_time date
, location varchar2(1)
, credit number(1,0) );
create table tableb(location varchar2(1));
insert into tablea values (date '2011-06-14' + dbms_random.value, 'B', 2);
insert into tablea values (date '2011-06-14' + dbms_random.value, 'B', 3);
insert into tablea values (date '2011-06-14' + dbms_random.value, 'C', 5);
insert into tablea values (date '2011-06-13' + dbms_random.value, 'B', 1);
insert into tablea values (date '2011-06-13' + dbms_random.value, 'B', 2);
insert into tablea values (date '2011-06-13' + dbms_random.value, 'B', 2);
insert into tablea values (date '2011-06-13' + dbms_random.value, 'C', 1);
insert into tablea values (date '2011-06-13' + dbms_random.value, 'C', 2);
insert into tablea values (date '2011-06-13' + dbms_random.value, 'C', 2);
insert into tableb values('A');
insert into tableb values('B');
insert into tableb values('C');
Upvotes: 1