即使缺少对应的销售值为空的月份,我也需要获取显示的全部24个月。这就是我想出的。 您可以看到我们缺少ID和客户名称。我需要将sales设为空的id和客户名称,如下面的屏幕截图所示
select CUSTNAME, reportdate, sales, mth
from ( select add_months(date '2017-01-01', level - 1) as mth
from dual
connect by level <= 24)mo
left outer join oracle_tbl dc on mo.mth = trunc(reportdate, 'MM')
order by mth
我也尝试了以下方法,但似乎没有任何效果(例如,为客户名和ID缺少日期提供了空值
WITH mydates AS (
select LAST_DAY(add_months(date '2017-01-01', level - 1)) as mth, min_id,min_custname
from (
select min(id) as min_id, min(CUSTNAME) as min_custname
from my_oracle_tbl
)
connect by level <= 24)
select
nvl(t.id, a.min_id)id,
nvl(t.CUSTNAME,a.min_custname)CUSTNAME, a.mth, t.sales
from mydates a left join my_oracle_tbl t on a.mth= LAST_DAY(t.reporttdate)
where
t.id=12345;
select CUSTNAME, reportdate, sales, mth
from( SELECT CUSTNAME, reportdate, sales, mth FROM my_oracle_tbl
WHERE id=123 )
myTotals
right outer join
(select LAST_DAY(date '2017-01-01' + numtoyminterval(level-1,'month')) MonthName
from dual
connect by level <= 24) ALLMONTHS
on( myTotals.mm = allmonths.MonthName )
[![这就是我得到的方式。缺少ID和客户名称] [1]] [1]
[![这就是我需要的] [2]] [2]
答案 0 :(得分:1)
您还没有确切地说出问题所在,但您是按字符串值进行订购的,所以您将得到2017年1月,然后是2018年1月,然后是2017年2月...
保留日期作为实际日期,直到您需要以固定格式显示它们(或让您的客户这样做)为止。包括进行比较。
select dc.CUSTNAME, dc.reportdate, dc.sales, mo.mth
from (
select add_months(date '2017-01-01', level - 1) as mth
from dual
connect by level <= 24
) mo
left outer join oracle_tbl dc on mo.mth = trunc(dc.reportdate, 'MM')
order by mo.mth
其中trunc(reportdate, 'MM')
将报告日期截断为该月的第一天;或具有日期范围(更便于索引):
select dc.CUSTNAME, dc.reportdate, dc.sales, mo.mth
from (
select add_months(date '2017-01-01', level - 1) as mth
from dual
connect by level <= 24
) mo
left outer join oracle_tbl dc
on dc.reportdate >= mo.mth
and dc.reportdate < add_months(mo.mth, 1)
order by mo.mth
无论哪种方式,您都将获得mth
作为日期,然后可以格式化该日期(如果您真的想显示它的话)。
答案 1 :(得分:0)
假设我们有以下表格:{1}日期,包含您需要的所有月份的最后一天;以及{2}销售,包含针对客户的销售(不是每个月)。
create table dates ( month_end_date )
as
select add_months(date '2017-01-01', level - 1) - 1
from dual
connect by level <= 24 ;
create table sales (customerid, custname, sales, date_of_sale )
as
select *
from (
select
case when mod( level, 3 ) = 0 then 1 end as customerid
, case when mod( level, 3 ) = 0 then 'test' end
, case when mod( level, 3 ) = 0 then trunc( dbms_random.value() * 10000 ) end
, case when mod( level, 3 ) = 0 then add_months(date '2017-01-01', level - 1) end
from dual connect by level <= 24
)
where customerid is not null ;
销售表
-- SALES colum: random values!
-- sales values recorded every third month
SQL> select * from sales ;
CUSTOMERID CUST SALES DATE_OF_S
---------- ---- ---------- ---------
1 test 5764 01-MAR-17
1 test 3937 01-JUN-17
1 test 9926 01-SEP-17
1 test 3045 01-DEC-17
1 test 598 01-MAR-18
1 test 325 01-JUN-18
1 test 2590 01-SEP-18
1 test 5803 01-DEC-18
8 rows selected.
DATES表
SQL> select * from dates ;
MONTH_END
---------
31-DEC-16
31-JAN-17
28-FEB-17
31-MAR-17
30-APR-17
...
31-JUL-18
31-AUG-18
30-SEP-18
31-OCT-18
30-NOV-18
24 rows selected.
以下查询应为您提供一些有用的工作... CROSS JOIN为您提供所有组合 客户编号+客户名称和month_end_dates。 LEFT JOIN输出您需要的所有NULL值。 (请注意,我们在联接条件下正在调用LAST_DAY()。)您还可以使用“ SELECT ... CONNECT BY ...”来生成所有MONTH_END_DATE(就像您在自己的查询中所做的那样)
select CM.customerid, CM.custname, S.sales, CM.month_end_date
from (
select *
from (
( select unique customerid, custname from sales )
cross join
( select month_end_date from dates ) -- <- data could be "generated"
)
) CM left join sales S on CM.month_end_date = last_day( S.date_of_sale )
order by CM.month_end_date
;
结果
CUSTOMERID CUST SALES MONTH_END
---------- ---- ---------- ---------
1 test NULL 31-DEC-16
1 test NULL 31-JAN-17
1 test NULL 28-FEB-17
1 test 5764 31-MAR-17
1 test NULL 30-APR-17
1 test NULL 31-MAY-17
1 test 3937 30-JUN-17
1 test NULL 31-JUL-17
1 test NULL 31-AUG-17
1 test 9926 30-SEP-17
1 test NULL 31-OCT-17
1 test NULL 30-NOV-17
1 test 3045 31-DEC-17
1 test NULL 31-JAN-18
1 test NULL 28-FEB-18
1 test 598 31-MAR-18
1 test NULL 30-APR-18
1 test NULL 31-MAY-18
1 test 325 30-JUN-18
1 test NULL 31-JUL-18
1 test NULL 31-AUG-18
1 test 2590 30-SEP-18
1 test NULL 31-OCT-18
1 test NULL 30-NOV-18
-- caution: sale for 01-DEC-18 "chopped off"
24 rows selected.
编辑(限制日期范围,按客户过滤)
要与一个以上的客户打交道,并缩小(结果集的)日期范围,请在LEFT JOIN的ON子句中添加一个条件,然后在WHERE子句中添加更多条件,例如
销售(测试)表CTAS
-- New SALES table for testing
-- 5 customers, 1 sale every 5 months (per customer)
create table sales (customerid, custname, sales, date_of_sale )
as
select *
from (
select
mod( level, 5 ) + 1
, 'test' || to_char( mod( level, 5 ) + 1 )
, trunc( dbms_random.value() * 10000 )
, add_months(date '2017-01-01', level - 1)
from dual connect by level <= 24
)
;
销售数据
SQL> select * from sales;
CUSTOMERID CUSTNAME SALES DATE_OF_SALE
2 test2 5594 01-JAN-17
3 test3 6398 01-FEB-17
4 test4 2072 01-MAR-17
5 test5 4269 01-APR-17
1 test1 9435 01-MAY-17
2 test2 6984 01-JUN-17
3 test3 5735 01-JUL-17
4 test4 9549 01-AUG-17
5 test5 9686 01-SEP-17
1 test1 9193 01-OCT-17
2 test2 1702 01-NOV-17
3 test3 8277 01-DEC-17
4 test4 8235 01-JAN-18
5 test5 7596 01-FEB-18
1 test1 5507 01-MAR-18
2 test2 6267 01-APR-18
3 test3 5708 01-MAY-18
4 test4 755 01-JUN-18
5 test5 3966 01-JUL-18
1 test1 5167 01-AUG-18
2 test2 6819 01-SEP-18
3 test3 9268 01-OCT-18
4 test4 1844 01-NOV-18
5 test5 1085 01-DEC-18
24 rows selected.
查询
-- sales for customer (id) 3, between 30 Apr 2018 and 31 Dec 2018
select CM.customerid, CM.custname, S.sales, CM.month_end_date
from (
select *
from (
( select unique customerid, custname from sales )
cross join
( select month_end_date from dates )
)
) CM
left join sales S
on CM.month_end_date = last_day( S.date_of_sale )
and CM.customerid = S.customerid
where CM.customerid = 3
and CM.month_end_date > date '2018-04-30'
and CM.month_end_date < date '2018-12-31'
order by CM.month_end_date
;
-- result
CUSTOMERID CUSTNAME SALES MONTH_END_DATE
3 test3 5708 31-MAY-18
3 test3 NULL 30-JUN-18
3 test3 NULL 31-JUL-18
3 test3 NULL 31-AUG-18
3 test3 NULL 30-SEP-18
3 test3 9268 31-OCT-18
3 test3 NULL 30-NOV-18