Custom SQL for quarter count starting from previous month - sql

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;

Related

Transposing multiple related columns

While transposing single columns is pretty straight forward I need to transpose a large amount of data with 3 sets of , 10+ related columns needed to be transposed.
create table test
(month int,year int,po1 int,po2 int,ro1 int,ro2 int,mo1 int,mo2 int, mo3 int);
insert into test
values
(5,2013,100,20,10,1,3,4,5),(4,2014,200,30,20,2,4,5,6),(6,2015,200,80,30,3,5,6,7) ;
select * FROM test;
gives
month
year
po1
po2
ro1
ro2
mo1
mo2
mo3
5
2013
100
20
10
1
3
4
5
4
2014
200
30
20
2
4
5
6
6
2015
200
80
30
3
5
6
7
Transposing using UNPIVOT
select
month, year,
PO, RO, MO
from ( SELECT * from test) src
unpivot
( PO for Description in (po1, po2))unpiv1
unpivot
(RO for Description1 in (ro1, ro2)) unpiv2
unpivot
(MO for Description2 in (mo1, mo2, mo3)) unpiv3
order by year
Gives me this
month
year
PO
RO
MO
5
2013
100
10
3
5
2013
100
10
4
5
2013
100
10
5
5
2013
100
1
3
5
2013
100
1
4
5
2013
100
1
5
5
2013
20
10
3
5
2013
20
10
4
5
2013
20
10
5
5
2013
20
1
3
5
2013
20
1
4
5
2013
20
1
5
4
2014
200
20
4
4
2014
200
20
5
4
2014
200
20
6
4
2014
200
2
4
4
2014
200
2
5
4
2014
200
2
6
4
2014
30
20
4
4
2014
30
20
5
4
2014
30
20
6
4
2014
30
2
4
4
2014
30
2
5
4
2014
30
2
6
6
2015
200
30
5
6
2015
200
30
6
6
2015
200
30
7
6
2015
200
3
5
6
2015
200
3
6
6
2015
200
3
7
6
2015
80
30
5
6
2015
80
30
6
6
2015
80
30
7
6
2015
80
3
5
6
2015
80
3
6
6
2015
80
3
7
I will like to turn it to something like this. Is that possible?
month
year
PO
RO
MO
5
2013
100
10
3
5
2013
20
1
4
5
2013
0
0
5
4
2014
200
20
4
4
2014
30
2
5
4
2014
0
0
6
6
2015
200
30
5
6
2015
80
3
6
6
2015
0
0
7
Maybe use a query like below which creates rows as per your design using CROSS APPLY
select month,year,po,ro,mo from
test cross apply
(values (po1,ro1,mo1), (po2,ro2,mo2),(0,0,mo3))v(po,ro,mo)
see demo here
Unpivot acts similar as union,Use union all in your case
SELECT month,
year,
po1 AS PO,
ro1 AS RO,
mo1 AS MO
FROM test
UNION ALL
SELECT month,
year,
po2,
ro2,
mo2
FROM test
UNION ALL
SELECT month,
year,
0,
0,
mo2
FROM test

SQL query to Find highest value in table and sum the corresponding value

I would like to group Highest values in month column group by year and Sum the value column
value
Year
Month
4
2019
10
1
2019
11
5
2019
11
1
2019
11
1
2019
12
8
2019
12
1
2019
12
1
2020
1
10
2020
1
3
2021
1
2
2021
2
11
2021
2
1
2021
2
3
2021
2
2
2021
3
In above table I would like to extract highest value of month group by year
in year 2019 highest month is 12 so there are 3 rows and sum of value column will be 10
The output should be
value
Year
Month
10
2019
12
11
2020
1
2
2021
3
supposing that the table is called "example_table" you can use the following query:
select sum(example_table.value), example_table.year, example_table.month
from example_table
join (
select year, max(month) "month"
from example_table
group by year
) sub on example_table.year = sub.year and example_table.month = sub.month
group by example_table.year, example_table.month
order by example_table.year

R - get a vector that tells me if a value of another vector is the first appearence or not

I have a data frame of sales with three columns: the code of the customer, the month the customer bought that item, and the year.
A customer can buy something in september and then in december make another purchase, so appear two times. But I'm interested in knowing the absolutely new customoers by month and year.
So I have thought in make an iteration and some checks and use the %in% function and build a boolean vector that tells me if a customer is new or not and then count by month and year with SQL using this new vector.
But I'm wondering if there's a specific function or a better way to do that.
This is an example of the data I would like to have:
date cust month new_customer
1 14975 25 1 TRUE
2 14976 30 1 TRUE
3 14977 22 1 TRUE
4 14978 4 1 TRUE
5 14979 25 1 FALSE
6 14980 11 1 TRUE
7 14981 17 1 TRUE
8 14982 17 1 FALSE
9 14983 18 1 TRUE
10 14984 7 1 TRUE
11 14985 24 1 TRUE
12 14986 22 1 FALSE
So put it more simple: the data frame is sorted by date, and I'm interested in a vector (new_customer) that tells me if the customer purchased something for the first time or not. For example customer 25 bought something the first day, and then four days later bought something again, so is not a new customer. The same can be seen with customer 17 and 22.
I create dummy data my self with id, month of numeric format, and year
dat <-data.frame(
id = c(1,2,3,4,5,6,7,8,1,3,4,5,1,2,2),
month = c(1,6,7,8,2,3,4,8,11,1,10,9,1,12,2),
year = c(2019,2019,2019,2019,2019,2020,2020,2020,2020,2020,2021,2021,2021,2021,2021)
)
id month year
1 1 1 2019
2 2 6 2019
3 3 7 2019
4 4 8 2019
5 5 2 2019
6 6 3 2020
7 7 4 2020
8 8 8 2020
9 1 11 2020
10 3 1 2020
11 4 10 2021
12 5 9 2021
13 1 1 2021
14 2 12 2021
15 2 2 2021
Then, group by id and arrange by year and month (order is meaningful). Then use filter and row_number().
dat %>%
group_by(id) %>%
arrange(year, month) %>%
filter(row_number() == 1)
id month year
<dbl> <dbl> <dbl>
1 1 1 2019
2 5 2 2019
3 2 6 2019
4 3 7 2019
5 4 8 2019
6 6 3 2020
7 7 4 2020
8 8 8 2020
Sample Code
You can change in your code according to this logic:-
Create Table:-
CREATE TABLE PURCHASE(Posting_Date DATE,Customer_Id INT,Customer_Name VARCHAR(15));
Insert Data Into Table
Posting_Date Customer_Id Customer_Name
2018-01-01 C_01 Jack
2018-02-01 C_01 Jack
2018-03-01 C_01 Jack
2018-04-01 C_02 James
2019-04-01 C_01 Jack
2019-05-01 C_01 Jack
2019-05-01 C_03 Gill
2020-01-01 C_02 James
2020-01-01 C_04 Jones
Code
WITH Date_CTE (PostingDate,CustomerID,FirstYear)
AS
(
SELECT MIN(Posting_Date) as [Date],
Customer_Id,
YEAR(MIN(Posting_Date)) as [F_Purchase_Year]
FROM PURCHASE
GROUP BY Customer_Id
)
SELECT T.[ActualYear],(CASE WHEN T.[Customer Status] = 'new' THEN COUNT(T.[Customer Status]) END) AS [New Customer]
FROM (
SELECT DISTINCT YEAR(T2.Posting_Date) AS [ActualYear],
T2.Customer_Id,
(CASE WHEN T1.FirstYear = YEAR(T2.Posting_Date) THEN 'new' ELSE 'old' END) AS [Customer Status]
FROM Date_CTE AS T1
left outer join PURCHASE AS T2 ON T1.CustomerID = T2.Customer_Id
) AS T
GROUP BY T.[ActualYear],T.[Customer Status]
Final Result
ActualYear New Customer
2018 2
2019 1
2020 1
2019 NULL
2020 NULL

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

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

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;