Sql 即使我们错过了几个月,也可以轻松获取2年的月份数据
我需要获取所有显示的24个月,即使缺少相应销售值为空的月份。这就是我想到的。正如你所看到的,我们缺少id和客户名称。我需要id和custname,其中sales为null,如下面的屏幕截图所示 我还尝试了以下方法,但似乎没有任何效果,即为custname和id提供空值,因为它们缺少日期Sql 即使我们错过了几个月,也可以轻松获取2年的月份数据,sql,oracle,Sql,Oracle,我需要获取所有显示的24个月,即使缺少相应销售值为空的月份。这就是我想到的。正如你所看到的,我们缺少id和客户名称。我需要id和custname,其中sales为null,如下面的屏幕截图所示 我还尝试了以下方法,但似乎没有任何效果,即为custname和id提供空值,因为它们缺少日期 WITH mydates AS ( select LAST_DAY(add_months(date '2017-01-01', level - 1)) as mth, min_id,min_custna
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]您没有说确切的错误,但您是按字符串值订购的,因此您将得到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
无论哪种方式,你都会得到一个日期,然后你可以按照你想要的格式来显示它——如果你真的想显示它的话。假设我们有以下表格:{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 ;
日期表
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.
下面的查询应该为您提供一些可以从中工作的内容。。。交叉连接提供所有组合
客户ID+客户名称和月末日期的组合。左连接输出所需的所有空值。请注意,我们在join条件中调用了LAST_DAY。您也可以使用选择。。。通过…连接。。。如您在自己的查询中所做的,用于生成所有月末日期
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
;
编辑限制日期范围,按客户筛选
要处理多个客户,并缩小结果集的日期范围,请在左JOIN的ON子句中添加一个条件,然后在WHERE子句中添加更多条件,例如
销售测试表
-- 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
)
;
质疑
你能提供样本数据和结果吗?@Rika,谢谢。问题是上面的ID也丢失了。我需要24个月的所有属性,缺少的销售月为空。我还尝试为23个月创建一个临时视图,并执行外部连接b/w表和日期视图,但不起作用。我如何获得所有价值,除了丢失月份的重复销售。谢谢。但是上面的PartitionBy导致了错误的结果1它不允许我筛选特定的客户id,2它给出了超出我们日期的所有可用年份tables@sunnybabau-如果无法使分区正常工作,请不要费心。请参见编辑:查询应允许您根据需要筛选结果。@sunnybabau-外部联接(无论是左联接还是右联接)不会生成缺少的日期。这就是为什么我建议将交叉连接与左连接相结合。另一个示例是仅使用SALES表,但没有专用日期表:
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.
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.
-- 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