Oracle - looping though a list of date ranges with CONNECT BY LEVEL - sql

I am trying to expand upon another article to reach my needs. I am trying to build out a calendar based on our fiscal periods and seem to be creating an infinite loop, or rather one soo large SQL is squashing the query. A procedural solution will not work in the environment that I am trying to build this into, I am only able to use built-in features of the software otherwise I am in breach of my support agreement.
I will break down some of the output so you can see the raw data.
select distinct ap.accounting_year, ap.accounting_period, ap.date_from, ap.date_until
from accounting_period ap
where ap.accounting_period not in (0,13) and ap.accounting_year = :FY
order by ap.accounting_year, ap.accounting_period
This will output the following
2018 1 01-OCT-17 28-OCT-17
2018 2 29-OCT-17 25-NOV-17
2018 3 26-NOV-17 30-DEC-17
2018 4 31-DEC-17 27-JAN-18
2018 5 28-JAN-18 24-FEB-18
2018 6 25-FEB-18 31-MAR-18
2018 7 01-APR-18 28-APR-18
2018 8 29-APR-18 26-MAY-18
2018 9 27-MAY-18 30-JUN-18
2018 10 01-JUL-18 28-JUL-18
2018 11 29-JUL-18 25-AUG-18
2018 12 26-AUG-18 29-SEP-18
Now when I run the following query which I added an additional prompt for the period to limit the above result to 1-row and things work as intended.
WITH
fiscal as (
select distinct ap.accounting_year, ap.accounting_period, ap.date_from, ap.date_until
from accounting_period ap
where ap.accounting_period not in (0,13) and ap.accounting_year = :FY and ap.accounting_period = :FP
order by ap.accounting_year, ap.accounting_period
),
calendar AS (
SELECT f.accounting_year, f.accounting_period, f.date_from + ROWNUM -1 fiscal_day
FROM dual, fiscal f
CONNECT BY LEVEL <= f.date_until - f.date_from + 1
)
select * from calendar;
Output;
2018 9 27-MAY-18
2018 9 28-MAY-18
2018 9 29-MAY-18
2018 9 30-MAY-18
2018 9 31-MAY-18
2018 9 01-JUN-18
2018 9 02-JUN-18
2018 9 03-JUN-18
2018 9 04-JUN-18
2018 9 05-JUN-18
2018 9 06-JUN-18
2018 9 07-JUN-18
2018 9 08-JUN-18
2018 9 09-JUN-18
2018 9 10-JUN-18
2018 9 11-JUN-18
2018 9 12-JUN-18
2018 9 13-JUN-18
2018 9 14-JUN-18
2018 9 15-JUN-18
2018 9 16-JUN-18
2018 9 17-JUN-18
2018 9 18-JUN-18
2018 9 19-JUN-18
2018 9 20-JUN-18
2018 9 21-JUN-18
2018 9 22-JUN-18
2018 9 23-JUN-18
2018 9 24-JUN-18
2018 9 25-JUN-18
2018 9 26-JUN-18
2018 9 27-JUN-18
2018 9 28-JUN-18
2018 9 29-JUN-18
2018 9 30-JUN-18
In the end, I would like to be able to run this to output the records for all 12 periods and create a fiscal year calendar since this view does not exist in the current database.
I can post my entire query if requested, but this is where I am stuck, I was able to build the rest of my script by adding prompts to select the fiscal year and period in the WITH clause, but when I implement this into the end report I will have to create a view where the prompt will not be available within the WITH.
Thank You

If I understand well your need, this could be what you need:
select accounting_year, accounting_period, date_from, date_until, date_from + level -1 as calendare_date
from yourResult
connect by date_from + level -1 <= date_until
and prior accounting_year = accounting_year
and prior accounting_period = accounting_period
and prior sys_guid() is not null
order by accounting_year, accounting_period
For example, with a reduced set of data:
with yourResult(accounting_year, accounting_period, date_from, date_until) as (
select 2018, 1 , to_date('01-OCT-17', 'dd-mon-yy'), to_date('05-OCT-17', 'dd-mon-yy') from dual union all
select 2018, 2 , to_date('06-OCT-17', 'dd-mon-yy'), to_date('07-OCT-17', 'dd-mon-yy') from dual union all
select 2018, 3 , to_date('08-OCT-17', 'dd-mon-yy'), to_date('10-oct-17', 'dd-mon-yy') from dual
)
select accounting_year, accounting_period, date_from, date_until,
date_from + level -1 as calendare_date
from yourResult
connect by date_from + level -1 <= date_until
and prior accounting_year = accounting_year
and prior accounting_period = accounting_period
and prior sys_guid() is not null
order by accounting_year, accounting_period;
you have:
ACCOUNTING_YEAR ACCOUNTING_PERIOD DATE_FROM DATE_UNTI CALENDARE
--------------- ----------------- --------- --------- ---------
2018 1 01-OCT-17 05-OCT-17 01-OCT-17
2018 1 01-OCT-17 05-OCT-17 02-OCT-17
2018 1 01-OCT-17 05-OCT-17 03-OCT-17
2018 1 01-OCT-17 05-OCT-17 04-OCT-17
2018 1 01-OCT-17 05-OCT-17 05-OCT-17
2018 2 06-OCT-17 07-OCT-17 06-OCT-17
2018 2 06-OCT-17 07-OCT-17 07-OCT-17
2018 3 08-OCT-17 10-OCT-17 08-OCT-17
2018 3 08-OCT-17 10-OCT-17 09-OCT-17
2018 3 08-OCT-17 10-OCT-17 10-OCT-17

Related

Count records and group by different field while showing max value

id
year
1
2014
10
2015
10
2019
102
2015
102
2019
104
2015
104
2017
104
2019
104
2021
The output I want in postgres is below. The max year is populated based on the id and the count should also count based on id. If id = 10 then it should show the max date within id 10 and also count how many records have the id as 10.
id
year
max year
count
1
2014
2014
1
10
2015
2017
2
10
2017
2017
2
102
2015
2019
2
102
2019
2019
2
104
2015
2021
4
104
2017
2021
4
104
2019
2021
4
104
2021
2021
4
SELECT aa.id,
aa.year,
aa.max_year,
count(aa.id)
from (SELECT id,MAX(year) AS year FROM table
GROUP BY id) aa
FULL JOIN table2 b ON aa.id = b.id
You can use window functions:
select id,
year,
max(year) over (partition by id) as max_year,
count(*) over (partition by id)
from the_table

Custom SQL for quarter count starting from previous month

I need to create a custom quarter calculator to start always from previous month no matter month, year we are at and count back to get quarter. Previous year wuarters are to be numbered 5, 6 etc
So the goal is to move quarter grouping one month back.
Assume we run query on December 11th, result should be:
YEAR MNTH QTR QTR_ALT
2017 1 1 12
2017 2 1 12
2017 3 1 11
2017 4 2 11
2017 5 2 11
2017 6 2 10
2017 7 3 10
2017 8 3 10
2017 9 3 9
2017 10 4 9
2017 11 4 9
2017 12 4 8
2018 1 1 8
2018 2 1 8
2018 3 1 7
2018 4 2 7
2018 5 2 7
2018 6 2 6
2018 7 3 6
2018 8 3 6
2018 9 3 5
2018 10 4 5
2018 11 4 5
2018 12 4 1
2019 1 1 1
2019 2 1 1
2019 3 1 2
2019 4 2 2
2019 5 2 2
2019 6 2 3
2019 7 3 3
2019 8 3 3
2019 9 3 4
2019 10 4 4
2019 11 4 4
2019 12 4 THIS IS SKIPPED
Starting point is eliminating current_date so data end at previous month's last day
SELECT DISTINCT
YEAR,
MNTH,
QTR
FROM TABLE
WHERE DATA BETWEEN
(SELECT DATE_TRUNC(YEAR,ADD_MONTHS(CURRENT_DATE, -24))) AND
(SELECT DATE_TRUNC(MONTH,CURRENT_DATE)-1)
ORDER BY YEAR, MNTH, QTR
The following gets you all the dates you need, with the extra columns.
select to_char(add_months(a.dt, -b.y), 'YYYY') as year,
to_char(add_months(a.dt, -b.y), 'MM') as month,
ceil(to_number(to_char(add_months(a.dt, -b.y), 'MM')) / 3) as qtr,
ceil(b.y/3) as alt_qtr
from
(select trunc(sysdate, 'MONTH') as dt from dual) a,
(select rownum as y from dual connect by level <= 24) b;

multiple sub-conditions in WHERE clause SQL

I have the following example of a table from which I want all rows where Year is '2016' and '2017' but want to exclude CustID 'AB17' and 'AB18' from Year '2017'. In total I should get 12 rows. See this fiddle
Example:
SQL:
SELECT * FROM testing
WHERE Year In ('2016','2017')
AND (CustID NOT In ('AB17','AB18') AND Year = '2017');
Table:
Year CustID Revenue
2016 AB12 10
2016 AB13 11
2016 AB14 12
2016 AB15 13
2016 AB16 14
2016 AB17 15
2016 AB18 16
2017 AB12 10
2017 AB13 11
2017 AB14 12
2017 AB15 13
2017 AB16 14
2017 AB17 15
2017 AB18 16
2018 AB12 17
2018 AB13 18
2018 AB14 19
2018 AB15 20
2018 AB16 21
2018 AB17 22
2018 AB18 23
Any suggestions?
This should work:
WHERE
Year = '2016'
OR (Year = '2017' AND CustID NOT In ('AB17','AB18'))
A pretty direct translation of:
Year is '2016' and '2017' but want to exclude CustID 'AB17' and 'AB18' from Year '2017'.
is:
where year in (2016, 2017) and
not (year = 2017 and custID in ('AB17', 'AB18'))

Add column value to next column in SQL

My sql table is
Week Year Applications
1 2017 0
2 2017 10
3 2017 20
4 2017 50
5 2017 0
1 2018 10
2 2018 0
3 2018 40
4 2018 50
5 2018 10
And I want SQL query which give below output
Week Year Applications
1 2017 0
2 2017 10
3 2017 30
4 2017 80
5 2017 80
1 2018 10
2 2018 10
3 2018 50
4 2018 100
5 2018 110
Can anyone help me to write below query?
You could use SUM() OVER to get cumulative sum:
SELECT *, SUM(Applications) OVER(PARTITION BY Year ORDER BY Week)
FROM tab
It looks like you want a cumulative sum:
select week, year,
sum(applications) over (partition by year order by week) as cumulative_applications
from t;

oracle SQL convert some columns to rows [duplicate]

This question already has an answer here:
Oracle 11g - Unpivot
(1 answer)
Closed 5 years ago.
I have a table like below and i am trying to find the best query to convert only the months to rows.
**CODE YEAR JAN FEB MAR**
aa 2017 1 2 3
bb 2017 4 5 6
cc 2017 7 8 9
So that the result is:
**CODE YEAR MONTH value**
aa 2017 JAN 1
aa 2017 FEB 2
aa 2017 MAR 3
bb 2017 JAN 4
bb 2017 FEB 5
bb 2017 MAR 6
cc 2017 JAN 7
cc 2017 FEB 8
cc 2017 MAR 9
Could you please help
Setup table with data:
Select * into #tmpTbl from (
Select 'aa' as Code,2017 as Yr, 1 as Jan,2 as Feb,3 as Mar UNION ALL
Select 'bb' as Code,2017 as Yr, 4 as Jan,5 as Feb,6 as Mar UNION ALL
Select 'cc' as Code,2017 as Yr, 7 as Jan,8 as Feb,9 as Mar) z
Transform query to produce flattened results:
SELECT Code, Yr, CrossApplied.Fld, CrossApplied.Val as Value
FROM #tmpTbl
CROSS APPLY (VALUES (JAN,'JAN'),
(FEB,'FEB'),
(MAR,'MAR'))
CrossApplied (Val,Fld)
The structure of your data might be better reworked to make the data more inline with how you want it represented. This works but its a lot of work around to get there from here.