How to convert this MYSQL SQL to HIVE SQL? - sql

The table ProductOrder columns include:
id shopid starttime endtime
1 123 2018-04-27 2018-04-28
2 234 2018-04-23 2018-04-30
3 189 2018-05-01 2018-05-30
4 321 2018-05-01 2018-05-29
I wan't to query for valid shop counts between two days and count by each day of latest month,the valid shop counts means the starttime<= $curDate <= endtime,and curDate is a variable of the each day of the leatest month.
Today is 2018-04-27,so the query result should be:
day count
2018-04-27 2
2018-04-26 1
2018-04-25 1
2018-04-24 1
2018-04-23 1
2018-04-22 0
2018-04-21 0
……………………………………
2018-03-26 0
I achieve this requirement in MYSQL.This SQL can work well in MYSQL.How can I convert to Hive Sql?
SELECT
DATE_SUB(DATE(NOW()), INTERVAL days_ago.days DAY) day,
COUNT(distinct(shopID)) count
FROM
(SELECT 0 days UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION
SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14 UNION
SELECT 15 UNION SELECT 16 UNION SELECT 17 UNION SELECT 18 UNION SELECT 19 UNION
SELECT 20 UNION SELECT 21 UNION SELECT 22 UNION SELECT 23 UNION SELECT 24 UNION
SELECT 25 UNION SELECT 26 UNION SELECT 27 UNION SELECT 28 UNION SELECT 29)
AS days_ago
LEFT JOIN ProductOrder
ON DATE_SUB(DATE(NOW()), INTERVAL days_ago.days DAY) <= ProductOrder.endtime
AND DATE_SUB(DATE(NOW()), INTERVAL days_ago.days DAY) >= ProductOrder.starttime
AND status = 2
GROUP BY days_ago.days;

Hive does not support Non equi join conditions, they can be placed to the WHERE clause instead. Use STACK instead of many UNION subqueries.
select DATE_SUB(CURRENT_DATE, days_ago.days) day,
COUNT(DISTINCT(shopID)) count
from
(
select stack(30, --the number of elements
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29) as (days)
) days_ago
LEFT JOIN ProductOrder po ON status = 2
WHERE (DATE_SUB(CURRENT_DATE, days_ago.days) <= po.endtime
AND DATE_SUB(CURRENT_DATE, days_ago.days) >= po.starttime)
OR po.shopID is NULL --allow nulls
GROUP BY DATE_SUB(CURRENT_DATE, days_ago.days);

SELECT DATE_SUB(CURRENT_DATE, days_ago.days),
COUNT(DISTINCT(shopID)) count
FROM
(
SELECT explode(array(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29)) as days
) days_ago
LEFT JOIN ProductOrder po ON
(
DATE_SUB(CURRENT_DATE, days_ago.days) <= po.endtime
AND DATE_SUB(CURRENT_DATE, days_ago.days) >= po.starttime
AND status = 2
)
GROUP BY days_ago.days;

Related

how to use windows function during merge in sql

I am working in oracle sql. I have two table which is linked to each other by one column - company_id (see on the picture); I want to merge table 1 to table 2 and calculate 6 month average (6 month before period from table 2) of income for each company_id and each date of table2. I appreciate any code/idea how to solve this task.
You can use an analytic range window to calculate the averages for table1 and then JOIN the result to table2:
SELECT t2.*,
t1.avg_income_6,
t1.avg_income_12
FROM table2 t2
LEFT OUTER JOIN (
SELECT company_id,
dt,
ROUND(AVG(income) OVER (
PARTITION BY company_id
ORDER BY dt
RANGE BETWEEN INTERVAL '5' MONTH PRECEDING
AND INTERVAL '0' MONTH FOLLOWING
), 2) AS avg_income_6,
ROUND(AVG(income) OVER (
PARTITION BY company_id
ORDER BY dt
RANGE BETWEEN INTERVAL '11' MONTH PRECEDING
AND INTERVAL '0' MONTH FOLLOWING
), 2) AS avg_income_12
FROM table1
) t1
ON (t2.company_id = t1.company_id AND t2.dt = t1.dt);
Which, for the sample data:
CREATE TABLE table1 (company_id, dt, income) AS
SELECT 1, date '2019-01-01', 65 FROM DUAL UNION ALL
SELECT 1, date '2019-02-01', 58 FROM DUAL UNION ALL
SELECT 1, date '2019-03-01', 12 FROM DUAL UNION ALL
SELECT 1, date '2019-04-01', 81 FROM DUAL UNION ALL
SELECT 1, date '2019-05-01', 38 FROM DUAL UNION ALL
SELECT 1, date '2019-06-01', 81 FROM DUAL UNION ALL
SELECT 1, date '2019-07-01', 38 FROM DUAL UNION ALL
SELECT 1, date '2019-08-01', 69 FROM DUAL UNION ALL
SELECT 1, date '2019-09-01', 54 FROM DUAL UNION ALL
SELECT 1, date '2019-10-01', 90 FROM DUAL UNION ALL
SELECT 1, date '2019-11-01', 10 FROM DUAL UNION ALL
SELECT 1, date '2019-12-01', 12 FROM DUAL UNION ALL
SELECT 1, date '2020-01-01', 11 FROM DUAL UNION ALL
SELECT 1, date '2020-02-01', 83 FROM DUAL UNION ALL
SELECT 1, date '2020-03-01', 18 FROM DUAL UNION ALL
SELECT 1, date '2020-04-01', 28 FROM DUAL UNION ALL
SELECT 1, date '2020-05-01', 52 FROM DUAL UNION ALL
SELECT 1, date '2020-06-01', 21 FROM DUAL UNION ALL
SELECT 1, date '2020-07-01', 54 FROM DUAL UNION ALL
SELECT 1, date '2020-08-01', 30 FROM DUAL UNION ALL
SELECT 1, date '2020-09-01', 12 FROM DUAL UNION ALL
SELECT 1, date '2020-10-01', 25 FROM DUAL UNION ALL
SELECT 1, date '2020-11-01', 86 FROM DUAL UNION ALL
SELECT 1, date '2020-12-01', 4 FROM DUAL UNION ALL
SELECT 1, date '2021-01-01', 10 FROM DUAL UNION ALL
SELECT 1, date '2021-02-01', 72 FROM DUAL UNION ALL
SELECT 1, date '2021-03-01', 65 FROM DUAL UNION ALL
SELECT 1, date '2021-04-01', 25 FROM DUAL;
CREATE TABLE table2 (company_id, dt) AS
SELECT 1, date '2019-06-01' FROM DUAL UNION ALL
SELECT 1, date '2019-09-01' FROM DUAL UNION ALL
SELECT 1, date '2019-12-01' FROM DUAL UNION ALL
SELECT 1, date '2020-01-01' FROM DUAL UNION ALL
SELECT 1, date '2020-07-01' FROM DUAL UNION ALL
SELECT 1, date '2020-08-01' FROM DUAL UNION ALL
SELECT 1, date '2021-03-01' FROM DUAL UNION ALL
SELECT 1, date '2021-04-01' FROM DUAL;
Outputs:
COMPANY_ID
DT
AVG_INCOME_6
AVG_INCOME_12
1
2019-06-01 00:00:00
55.83
55.83
1
2019-09-01 00:00:00
60.17
55.11
1
2019-12-01 00:00:00
45.5
50.67
1
2020-01-01 00:00:00
41
46.17
1
2020-07-01 00:00:00
42.67
41.83
1
2020-08-01 00:00:00
33.83
38.58
1
2021-03-01 00:00:00
43.67
38.25
1
2021-04-01 00:00:00
43.67
38
db<>fiddle here
I don't think you need any window function here (if you were thinking of analytic functions); ordinary avg with appropriate join conditions should do the job.
Sample data:
SQL> with
2 table1 (company_id, datum, income) as
3 (select 1, date '2019-01-01', 65 from dual union all
4 select 1, date '2019-02-01', 58 from dual union all
5 select 1, date '2019-03-01', 12 from dual union all
6 select 1, date '2019-04-01', 81 from dual union all
7 select 1, date '2019-05-01', 38 from dual union all
8 select 1, date '2019-06-01', 81 from dual union all
9 select 1, date '2019-07-01', 38 from dual union all
10 select 1, date '2019-08-01', 69 from dual union all
11 select 1, date '2019-09-01', 54 from dual union all
12 select 1, date '2019-10-01', 90 from dual union all
13 select 1, date '2019-11-01', 10 from dual union all
14 select 1, date '2019-12-01', 12 from dual
15 ),
16 table2 (company_id, datum) as
17 (select 1, date '2019-06-01' from dual union all
18 select 1, date '2019-09-01' from dual union all
19 select 1, date '2019-12-01' from dual union all
20 select 1, date '2020-01-01' from dual union all
21 select 1, date '2020-07-01' from dual
22 )
Query begins here:
23 select b.company_id,
24 b.datum ,
25 round(avg(a.income), 2) result
26 from table1 a join table2 b on a.company_id = b.company_id
27 and a.datum > add_months(b.datum, -6)
28 and a.datum <= b.datum
29 group by b.company_id, b.datum;
COMPANY_ID DATUM RESULT
---------- -------- ----------
1 01.06.19 55,83
1 01.09.19 60,17
1 01.12.19 45,5
1 01.01.20 47
SQL>

How to group sales by month, quarter and year in the same row using case?

I'm trying to return the total number of sales for every month, every quarter, for the year 2016. I want to display annual sales on the first month row, and not on the other rows. Plus, I want to display the quarter sales on the first month of each quarter, and not on the others.
To further explain this, here's what I want to achieve:
MONTH MONTH_SALES QUARTER_SALES YEAR_SALES
1 2183 5917 12505
2 1712 - -
3 1972 - -
4 2230 6588 -
5 2250 - -
6 2108 - -
Here's my SQL query so far:
SELECT
Time.month,
SUM(Sales.sales) AS MONTH_SALES, -- display monthly sales.
CASE
WHEN MOD(Time.month, 3) = 1 THEN ( -- first month of quarter
SELECT
SUM(Sales.sales)
FROM
Sales,
Time
WHERE
Sales.Time_id = Time.Time_id
AND Time.year = 2016
GROUP BY
Time.quarter
FETCH FIRST 1 ROW ONLY
)
END AS QUARTER_SALES,
CASE
WHEN Time.month = 1 THEN ( -- display annual sales.
SELECT
SUM(Sales.sales)
FROM
Sales,
Time
WHERE
Sales.Time_id = Time.Time_id
AND Time.year = 2016
GROUP BY
Time.year
)
END AS YEAR_SALES
FROM
Sales,
Time
WHERE
Sales.Time_id = Time.Time_id
AND Time.year = 2016
GROUP BY
Time.month
ORDER BY
Time.month
I'm almost getting the desired output, but I'm getting the same duplicated 6588 value in quarter sales for the first and fourth month (because I'm fetching the first row that comes from first quarter).
MONTH MONTH_SALES QUARTER_SALES YEAR_SALES
1 2183 6588 12505
2 1712 - -
3 1972 - -
4 2230 6588 -
5 2250 - -
6 2108 - -
I even tried to put WHERE Time.quarter = ((Time.month * 4) / 12) but the month value from the outer query doesn't get passed in the subquery.
Unfortunately I don't have enough experience with CASE WHEN expressions to know how to pass the month row. Any tips would be awesome.
How about this?
Sample data:
SQL> with
2 time (time_id, month, quarter, year) as
3 (select 1, 1, 1, 2016 from dual union all
4 select 2, 2, 1, 2016 from dual union all
5 select 3, 3, 1, 2016 from dual union all
6 select 4, 5, 2, 2016 from dual union all
7 select 5, 7, 3, 2016 from dual union all
8 select 6, 8, 3, 2016 from dual union all
9 select 7, 9, 3, 2016 from dual union all
10 select 8, 10, 4, 2016 from dual union all
11 select 9, 11, 4, 2016 from dual
12 ),
13 sales (time_id, sales) as
14 (select 1, 100 from dual union all
15 select 1, 100 from dual union all
16 select 2, 200 from dual union all
17 select 3, 300 from dual union all
18 select 4, 400 from dual union all
19 select 5, 500 from dual union all
20 select 6, 600 from dual union all
21 select 7, 700 from dual union all
22 select 8, 800 from dual union all
23 select 9, 900 from dual
24 ),
Query begins here; it uses sum aggregate in its analytic form; partition by clause says what to compute. row_number, similarly, sorts rows in each quarter/year - it is later used in CASE expression to decide whether to show quarterly/yearly total or not.
25 temp as
26 (select t.month, t.quarter, t.year, sum(s.sales) month_sales
27 from time t join sales s on s.time_id = t.time_id
28 where t.year = 2016
29 group by t.month, t.quarter, t.year
30 ),
31 temp2 as
32 (select month, quarter, month_sales,
33 sum(month_sales) over (partition by quarter) quarter_sales,
34 sum(month_sales) over (partition by year ) year_sales,
35 row_number() over (partition by quarter order by quarter) rnq,
36 row_number() over (partition by year order by null) rny
37 from temp
38 )
39 select month,
40 month_sales
41 case when rnq = 1 then quarter_sales end month_sales,
42 case when rny = 1 then year_sales end year_sales
43 from temp2
44 order by month;
MONTH MONTH_SALES QUARTER_SALES YEAR_SALES
---------- ---------- ----------- ----------
1 200 700 4600
2 200
3 300
4 400 1500
5 500
6 600
7 700 2400
8 800
9 900
9 rows selected.
SQL>

Recursive calculation in BigQuery [duplicate]

This question already has an answer here:
It's possible to create a rule in preceding rows in sum?
(1 answer)
Closed 2 years ago.
I need to calculate stock as a dinamic and recursive value, as the simple equation:
n value refers to a periodic time (month, day, year, etc)
Always when a stock value is negative, this is replaced by zero.
How can I calculate this in Big Query? Here is a example:
WITH `project.dataset.table` AS (
SELECT 10 entrada, 5 venda, 8 quebra, 8 mes, 2019 ano UNION ALL
SELECT 12, 8 , 3, 9, 2019 UNION ALL
SELECT 20, 15, 2, 10, 2019 UNION ALL
SELECT 30, 12, 2, 11, 2019 UNION ALL
SELECT 20, 10, 5, 12, 2019 UNION ALL
SELECT 30, 12, 2, 1, 2020 UNION ALL
SELECT 30, 12, 2, 2, 2020 UNION ALL
SELECT 30, 12, 2, 3, 2020
)
SELECT entrada, venda, quebra,
variacao,
greatest(coalesce(lag(variacao) over (partition by 'project.dataset.table' order by ano, mes),0) + entrada - venda - quebra, 0) as estoque
FROM (
SELECT *,
entrada - venda - quebra AS variacao
FROM `project.dataset.table`
)
And the expected result would be:
entrada venda quebra variacao estoque
10 5 8 -3 0
12 8 3 1 1
20 15 2 3 4
30 12 2 16 20
20 10 5 5 25
30 12 2 16 41
30 12 2 16 57
30 12 2 16 73
But, the results for the code above is:
entrada venda quebra variacao estoque
10 5 8 -3 0
12 8 3 1 0
20 15 2 3 4
30 12 2 16 19
20 10 5 5 21
30 12 2 16 21
30 12 2 16 32
30 12 2 16 32
Thanks in advance!
BigQuery does not support recursive operations natively. Try array_agg() combined with JavaScript user-defined function, but this approach is not very scalable:
CREATE TEMP FUNCTION special_sum(x ARRAY<INT64>)
RETURNS INT64
LANGUAGE js
AS """
var estoque = 0;
for (const num of x)
{
estoque = Math.max(estoque + parseInt(num), 0);
}
return estoque;
""";
WITH `project.dataset.table` AS (
SELECT 10 entrada, 5 venda, 8 quebra, 8 mes, 2019 ano UNION ALL
SELECT 12, 8 , 3, 9, 2019 UNION ALL
SELECT 20, 15, 2, 10, 2019 UNION ALL
SELECT 30, 12, 2, 11, 2019 UNION ALL
SELECT 20, 10, 5, 12, 2019 UNION ALL
SELECT 30, 12, 2, 1, 2020 UNION ALL
SELECT 30, 12, 2, 2, 2020 UNION ALL
SELECT 30, 12, 2, 3, 2020
)
select *,
special_sum(array_agg(entrada - venda - quebra) over (order by ano, mes rows unbounded preceding)) as estoque
from `project.dataset.table`
Solved using a "internal" sum of all values of stock. Using this:
WITH `project.dataset.table` AS (
SELECT 10 entrada, 5 venda, 8 quebra, 8 mes, 2019 ano UNION ALL
SELECT 12, 8 , 3, 9, 2019 UNION ALL
SELECT 20, 15, 2, 10, 2019 UNION ALL
SELECT 30, 12, 2, 11, 2019 UNION ALL
SELECT 20, 10, 5, 12, 2019 UNION ALL
SELECT 30, 12, 2, 1, 2020 UNION ALL
SELECT 30, 12, 2, 2, 2020 UNION ALL
SELECT 30, 12, 2, 3, 2020
)
SELECT entrada, venda, quebra,
sum(greatest(entrada - venda - quebra,0)) over (partition by 'project.dataset.table' order by ano, mes) as estoque,
mes, ano
FROM `project.dataset.table`

combine Join and not in date query

Here are my 2 tables.
Review_master
id Rev_month Rev_year ...
1 JAN 2017
2 MAR 2017
4 FEB 2017
Review_det
Id Rev_id closed_date (MM/DD/YYYY)
1 1 01/01/2017
2 1 02/01/2017
3 1 01/17/2017
4 2 03/03/2017
5 2 04/03/2017
6 4 02/02/2017
6 4 02/05/2017
Now i need to find out number of reviews which are closed outside that month. Review id "1" is of Jan month, and from review details table review_detail_id 2 is closed on feb month, so it should be counted.
Final output:
Rev_Id #_Closed_outside_month
1 1
2 1
4 0
there two main points :
Inequality of literal value of MON for closed date and rev_month
rev_month != to_char(closed_date,'MON')
Combining two tables with outer join.
So, you can easily use the following :
select m.id "Rev_id", count(closed_date) "#_Closed_outside_month"
from Review_det d right outer join Review_master m on ( d.Rev_id = m.id )
and rev_month != to_char(closed_date,'MON')
group by m.id
order by m.id;
D e m o
Here's one option:
SQL> with review_master (id, rev_month, rev_year) as
2 (select 1, 'jan', '2017' from dual union
3 select 2, 'mar', '2017' from dual union
4 select 4, 'feb', '2017' from dual),
5 review_det (id, rev_id, closed_date) as
6 (select 1, 1, date '2017-01-01' from dual union
7 select 2, 1, date '2017-02-01' from dual union
8 select 3, 1, date '2017-01-17' from dual union
9 select 4, 2, date '2017-03-03' from dual union
10 select 5, 2, date '2017-04-03' from dual union
11 select 6, 4, date '2017-02-02' from dual union
12 select 7, 4, date '2017-02-05' from dual)
13 select m.id,
14 case when to_char(d.closed_date, 'mmyyyy') <>
15 to_char(to_date(m.rev_month||' '||m.rev_year, 'mon yyyy',
16 'nls_date_language = english'), 'mmyyyy')
17 then 1
18 else 0
19 end closed_outside_Month
20 from review_master m, review_det d
21 where m.id = d.rev_id
22 and d.closed_date = (select max(d1.closed_date)
23 from review_Det d1
24 where d1.rev_id = d.rev_id
25 );
ID CLOSED_OUTSIDE_MONTH
---------- --------------------
1 1
2 1
4 0
SQL>

sqHow to get sum values weekly based between two dates?

My table values like ...
Date Amt Cash Money Name
15-Jun 100 10 20 GUL
16-Jun 200 20 40 ABC
20-Jun 300 30 60 GUL
25-Jun 400 40 80 BCA
28-Jun 500 50 10 GUL
3-Jul 600 60 120 ABC
19-Jun 700 70 140 BCA
26-Jun 800 80 160 ABC
7-Jul 900 90 180 GUL
9-Jul 1000 100 200 ABC
I need to return weekly based sum of values between two date in oracle .My expected output.
Date Amt Cash Mony
13 to 19 June 1000 100 200
20 to 26 June 1500 150 300
27 to3 July 1100 110 130
4 to 10 July 1900 190 380
you can achieve this by a case statement:
e.g.
-- test data
with data(dat,
val1,
val2) as
(select sysdate - 7, 12, 13
from dual
union all
select sysdate - 6, 32, 1
from dual
union all
select sysdate - 5, 52, 53
from dual
union all
select sysdate - 4, 2, 16
from dual
union all
select sysdate - 3, 72, 154
from dual)
select -- build up your groups
case
when d.dat < to_date('28.09.2016', 'DD.MM.YYYY') then
'<28.09.'
when d.dat > to_date('30.09.2016', 'DD.MM.YYYY') then
'>30.09.'
else
'28.-30.'
end as grp,
sum(val1),
sum(val2)
from data d
group by case
when d.dat < to_date('28.09.2016', 'DD.MM.YYYY') then
'<28.09.'
when d.dat > to_date('30.09.2016', 'DD.MM.YYYY') then
'>30.09.'
else
'28.-30.'
end;
-- output
grp sum(val1) sum(val2)
28.-30. 84 54
<28.09. 12 13
>30.09. 74 170
To group by calendar week use
-- test data
with data(dat,
val1,
val2) as
(select sysdate - 9, 12, 13
from dual
union all
select sysdate - 6, 32, 1
from dual
union all
select sysdate - 5, 52, 53
from dual
union all
select sysdate - 4, 2, 16
from dual
union all
select sysdate + 3, 72, 154
from dual)
select TRUNC(dat, 'iw') ||'-'|| TRUNC(dat+7, 'iw'),
sum(val1),
sum(val2)
from data
group by TRUNC(dat, 'iw') ||'-'|| TRUNC(dat+7, 'iw');
The query below has the input dates (from and to) in the first factored subquery. Those can be made into bind variables, or whatever mechanism you want to use to pass these inputs to the query. Then I have the test data in the second factored subquery; you don't need that in your final solution. I create all the needed weeks in the "weeks" factored subquery and I use a left outer join, so that weeks with no transactions will show 0 sums. Note that in the main query, where I do a join, the "date" column from the base table is not enclosed within any kind of function; this allows the use of an index on that column, which you should have if the table is very large, or if performance may be a concern for any other reason. Note that the output is different from yours (missing the last row) because I input a to-date before the last row in the table. That is intentional, I wanted to make sure the query works correctly. Also: I didn't use "date" or "week" as column names; that is a very poor practice. Reserved Oracle keywords should not be used as column names. I used "dt" and "wk" instead.
with
user_inputs ( from_dt, to_dt ) as (
select to_date('4-Jun-2016', 'dd-Mon-yyyy'), to_date('3-Jul-2016', 'dd-Mon-yyyy') from dual
),
test_data ( dt, amt, cash, money, name ) as (
select to_date('15-Jun-2016', 'dd-Mon-yyyy'), 100, 10, 20, 'GUL' from dual union all
select to_date('16-Jun-2016', 'dd-Mon-yyyy'), 200, 20, 40, 'ABC' from dual union all
select to_date('20-Jun-2016', 'dd-Mon-yyyy'), 300, 30, 60, 'GUL' from dual union all
select to_date('25-Jun-2016', 'dd-Mon-yyyy'), 400, 40, 80, 'BCA' from dual union all
select to_date('28-Jun-2016', 'dd-Mon-yyyy'), 500, 50, 10, 'GUL' from dual union all
select to_date( '3-Jul-2016', 'dd-Mon-yyyy'), 600, 60, 120, 'ABC' from dual union all
select to_date('19-Jun-2016', 'dd-Mon-yyyy'), 700, 70, 140, 'BCA' from dual union all
select to_date('26-Jun-2016', 'dd-Mon-yyyy'), 800, 80, 160, 'ABC' from dual union all
select to_date( '7-Jul-2016', 'dd-Mon-yyyy'), 900, 90, 180, 'GUL' from dual union all
select to_date( '9-Jul-2016', 'dd-Mon-yyyy'), 1000, 100, 200, 'ABC' from dual
),
weeks ( start_dt ) as (
select trunc(from_dt, 'iw') + 7 * (level - 1)
from user_inputs
connect by level <= 1 + (to_dt - trunc(from_dt, 'iw')) / 7
)
select to_char(w.start_dt, 'dd-Mon-yyyy') || ' - ' ||
to_char(w.start_dt + 6, 'dd-Mon-yyyy') as wk,
nvl(sum(t.amt), 0) as tot_amt, nvl(sum(t.cash), 0) as tot_cash,
nvl(sum(t.money), 0) as tot_money
from weeks w left outer join test_data t
on t.dt >= w.start_dt and t.dt < w.start_dt + 7
group by start_dt
order by start_dt
;
Output:
WK TOT_AMT TOT_CASH TOT_MONEY
-------------------------------------------- ---------- ---------- ----------
30-May-2016 - 05-Jun-2016 0 0 0
06-Jun-2016 - 12-Jun-2016 0 0 0
13-Jun-2016 - 19-Jun-2016 1000 100 200
20-Jun-2016 - 26-Jun-2016 1500 150 300
27-Jun-2016 - 03-Jul-2016 1100 110 130
You can try like below, I chose 13-Jun-2016 as a starting date. You can chose it as per your requirement upto any range of dates.
with t as
(select dt,
min(dt) over (partition by week)||' to '|| max(dt) over (partition by week) week
from (
select to_date('13-Jun-2016','dd-Mon-yyyy')+(level-1) dt,
ceil(level/7) week
from dual
connect by level<=52))
select week,
sum(amt),
sum(cash),
sum(money)
from (
select your_table.*,
t.week
from your_table,t
where trunc(to_date(your_table.dt,'dd-Mon-yyyy'))=trunc(t.dt))
group by week;