I received business task to prepare orders/sales report:
1) First, I will create separate table, for the report results:
create table sales_report (
order_id NUMBER,
order_tms DATE,
customer_id NUMBER,
contact_form_id NUMBER,
contact_date DATE,
full_name VARCHAR2(100),
email_address VARCHAR2(100),
source VARCHAR2(100),
CONSTRAINT sales_report_pk PRIMARY KEY (order_id)
);
2) Second, I want to update email address (in order table) into 4 customers (with biggest amount of orders), in order to connect orders table with contact_form table
ALTER TABLE orders ADD email_address VARCHAR2(100);
/
MERGE INTO orders
USING (
--retriving 4 customers (with biggest amount of orders)
select e.*, f.email_address
from (
select d.*,
ROWNUM as intConncetion
from (
select o.customer_id,
min(o.order_tms) as min_order_tms,
max(o.order_tms) as max_order_tms,
EXTRACT(DAY FROM (round(max(o.order_tms) - min(o.order_tms)))) as diff_tms,
c.order_amount
from orders o
--filtering 4 csutomers with biggest amount of orders;
join (
select b.*
from (
select a.*,
ROW_NUMBER() OVER(ORDER BY a.order_amount DESC) AS rankOrder_amount
from (
select customer_id, count(*) as order_amount
from orders
group by customer_id
order by 2 desc
) a
) b
where b.rankOrder_amount <= 4
) c
on o.customer_id = c.customer_id
group by o.customer_id, c.order_amount
) d
) e
join (
select a.*, ROWNUM as intConncetion
from (
select distinct email_address
from contact_form
) a
) f
on e.intConncetion = f.intConncetion
order by order_amount desc
) email
ON (orders.customer_id = email.customer_id)
WHEN MATCHED THEN
UPDATE SET orders.email_address = email.email_address;
/
COMMIT;
results =>
select * from orders where email_address is not null;
3) I'm creating procedure to insert new rows into destination table: sales_report
CREATE OR REPLACE PROCEDURE p_sales_report IS
BEGIN
INSERT INTO sales_report (order_id, order_tms, customer_id, contact_form_id, contact_date, full_name, email_address, source)
SELECT a.order_id, a.order_tms, a.customer_id, a.contact_form_id, a.contact_date, a.full_name, a.email_address, a.source
from (
select o.*, c.CONTACT_FORM_ID, c.CONTACT_DATE, c.FULL_NAME, c.SOURCE,
--best contact_form will have:
--1) contact date maximum 30 days before order date (it represent new client)
--2) source - only www
(CASE
WHEN ((to_date(to_char(o.order_tms,'yy/mm/dd'),'yy/mm/dd') - c.contact_date) between 0 and 31)
THEN ROW_NUMBER() OVER(PARTITION BY o.order_id, (CASE WHEN ((to_date(to_char(o.order_tms,'yy/mm/dd'),'yy/mm/dd') - c.contact_date) between 0 and 31) THEN 1 ELSE 0 END)
ORDER BY c.contact_date ASC)
END) AS best_www_lead
from orders o
join contact_form c
on o.email_address = c.email_address
and o.email_address is not null
ORDER BY o.order_id, c.contact_date ASC
) a
--only new rows
left outer join sales_report sales
on a.order_id = sales.order_id
where a.best_www_lead = 1 --sales requirements
and a.SOURCE = 'WWW'
and sales.order_id is null; --only new rows
COMMIT;
END;
4) run procedure - we inserted 16 rows, and count results =>
BEGIN
p_sales_report;
END;
/
select count(*) from sales_report;
5) Below I will present some logic behind the scenes =>
query =>
select a.*
from (
select o.order_id, o.order_tms, o.customer_id, c.*,
--best contact_form will have:
--1) contact date maximum 30 days before order date (it represent new client)
--2) source - only www
(CASE
WHEN ((to_date(to_char(o.order_tms,'yy/mm/dd'),'yy/mm/dd') - c.contact_date) between 0 and 31)
THEN ROW_NUMBER() OVER(PARTITION BY o.order_id, (CASE WHEN ((to_date(to_char(o.order_tms,'yy/mm/dd'),'yy/mm/dd') - c.contact_date) between 0 and 31) THEN 1 ELSE 0 END)
ORDER BY c.contact_date ASC)
END) AS best_www_lead
from orders o
join contact_form c
on o.email_address = c.email_address
and o.email_address is not null
and o.order_id in (515, 1280)
ORDER BY o.order_id, c.contact_date ASC
) a
where a.best_www_lead <= 3;
click to zoom in =>
Order_id 515 is rejected, because first contact within 30 days is from wrong source (CALL-CENTER)
Order_id 1280 is accepted to sales report, because first contact happened within 30 days, and demanded source (WWW)
6) Test results (if new sale appear?), after insert new row into orders table =>
INSERT INTO orders (order_tms, customer_id, order_status, store_id, email_address)
values ('21/09/01', 166, 'COMPLETE', 1, 'PRZEMEK@GOOGLE.PL');
/
COMMIT;
/
BEGIN
p_sales_report;
END;
/
select count(*) from sales_report;
7) Great, everything works perfect. Now, optional you can make job - to repeat procedure execution everyday =>
BEGIN
dbms_scheduler.create_job (
job_name => 'job_p_sales_report',
job_type => 'STORED_PROCEDURE',
job_action => 'p_sales_report',
start_date => CURRENT_TIMESTAMP,
enabled => true,
repeat_interval => 'FREQ=DAILY;INTERVAL=1; byhour=11; byminute=26;'
);
END;