How to group by month and year? - sql

I have a table PURCHASE with a date column PURCHASEDATE which is in DATE format. I'm trying to get the purchases grouped by month and year. To do so, I try with:
SELECT
TO_CHAR(PURCHASEDATE, 'MM YYYY') AS MONTHYEAR
FROM PURCHASE
GROUP BY TO_CHAR(PURCHASEDATE, 'MM YYYY');
I have also tryied with GROUP BY EXTRACT(MONTH FROM PURCHASEDATE), EXTRACT(YEAR FROM PURCHASEDATE) but neither worked.
I'm rusty with SQL querys :S.
EDIT
Table cloumns
Thanks ahead!

If you have the sample data:
CREATE TABLE purchase ( purchasedate ) AS
SELECT DATE '2019-01-01' + LEVEL - 1 FROM DUAL CONNECT BY LEVEL <= 5 UNION ALL
SELECT DATE '2019-02-01' + LEVEL - 1 FROM DUAL CONNECT BY LEVEL <= 3 UNION ALL
SELECT DATE '2020-01-01' + LEVEL - 1 FROM DUAL CONNECT BY LEVEL <= 3 UNION ALL
SELECT DATE '2020-02-01' + LEVEL - 1 FROM DUAL CONNECT BY LEVEL <= 2 UNION ALL
SELECT DATE '2020-03-01' + LEVEL - 1 FROM DUAL CONNECT BY LEVEL <= 4 UNION ALL
SELECT DATE '2020-04-01' + LEVEL - 1 FROM DUAL CONNECT BY LEVEL <= 1;
Then, you can use your query:
SELECT TO_CHAR(PURCHASEDATE, 'MM YYYY') AS monthyear,
COUNT(*) AS frequency
FROM PURCHASE
GROUP BY
TO_CHAR(PURCHASEDATE, 'MM YYYY');
Which outputs:
MONTHYEAR | FREQUENCY
:-------- | --------:
03 2020 | 4
01 2019 | 5
01 2020 | 3
02 2020 | 2
02 2019 | 3
04 2020 | 1
Or, you can use TRUNC:
SELECT TRUNC(PURCHASEDATE,'MM') AS monthyear,
COUNT(*) AS frequency
FROM PURCHASE
GROUP BY
TRUNC(PURCHASEDATE,'MM');
Which outputs:
MONTHYEAR | FREQUENCY
:------------------ | --------:
2020-03-01 00:00:00 | 4
2020-04-01 00:00:00 | 1
2020-02-01 00:00:00 | 2
2020-01-01 00:00:00 | 3
2019-01-01 00:00:00 | 5
2019-02-01 00:00:00 | 3
Or, you can use EXTRACT:
SELECT EXTRACT( YEAR FROM PURCHASEDATE) AS year,
EXTRACT( MONTH FROM PURCHASEDATE) AS month,
COUNT(*) AS frequency
FROM PURCHASE
GROUP BY
EXTRACT( YEAR FROM PURCHASEDATE),
EXTRACT( MONTH FROM PURCHASEDATE);
Which outputs:
YEAR | MONTH | FREQUENCY
---: | ----: | --------:
2019 | 1 | 5
2020 | 1 | 3
2020 | 2 | 2
2020 | 4 | 1
2019 | 2 | 3
2020 | 3 | 4
db<>fiddle here

Is this what you want?
SELECT
TO_CHAR(PURCHASEDATE, 'MM YYYY') AS MONTHYEAR,
SUM(TOTAL) AS TOTAL
FROM PURCHASE
GROUP BY
TO_CHAR(PURCHASEDATE, 'MM YYYY');

Related

Assigning a week number to a series of dates in Oracle SQL Developer [duplicate]

This question already has answers here:
How to extract week number in sql
(4 answers)
Closed 3 years ago.
I have a table called Sales_Table which stores all the sales amongst our branches. The columns Sale_Date & Day_Number both record the day a transaction occurs in, as a date and a number respectively. I am in need of a query which assigns a week number, in a column titled something like Week_Number, to each of the dates. This needs to be done so that I can begin to investigate weekly sales. I am not particularly worried about whether the Sales_Date is used to fill in the Week_Number column or if you want to use the numbers in the Day_Number column to do it.
Thank you for taking the time to read this problem, it is greatly appreciated.
An ISO week is always Monday-Sunday and the first week of the iso-year is always counted as the first week that has the majority of its days in the year (so will always contain the 4th January as it will have at least 4 days of the year in the week). You can use the IW format model to get the ISO week and IYYY to get the iso-year.
If you want the week to always correspond to the calendar year then you can use the WW format model and the week will start from whatever day 1st January is.
Oracle Setup:
CREATE TABLE your_table ( sale_date ) AS
SELECT DATE '2019-12-29' FROM DUAL UNION ALL
SELECT DATE '2019-12-30' FROM DUAL UNION ALL
SELECT DATE '2019-12-31' FROM DUAL UNION ALL
SELECT DATE '2020-01-01' FROM DUAL UNION ALL
SELECT DATE '2020-01-04' FROM DUAL UNION ALL
SELECT DATE '2020-01-05' FROM DUAL UNION ALL
SELECT DATE '2020-01-06' FROM DUAL UNION ALL
SELECT DATE '2020-01-07' FROM DUAL UNION ALL
SELECT DATE '2020-01-08' FROM DUAL UNION ALL
SELECT DATE '2020-01-17' FROM DUAL;
Query:
SELECT sale_date,
TO_CHAR( sale_date, 'IW' ) AS iso_week_number,
TO_CHAR( sale_date, 'IYYY' ) AS iso_year,
TO_CHAR( sale_date, 'WW' ) AS week_number,
TO_CHAR( sale_date, 'DY' ) AS day_of_week
FROM your_table
Output:
SALE_DATE | ISO_WEEK_NUMBER | ISO_YEAR | WEEK_NUMBER | DAY_OF_WEEK
:-------- | :-------------- | :------- | :---------- | :----------
29-DEC-19 | 52 | 2019 | 52 | SUN
30-DEC-19 | 01 | 2020 | 52 | MON
31-DEC-19 | 01 | 2020 | 53 | TUE
01-JAN-20 | 01 | 2020 | 01 | WED
04-JAN-20 | 01 | 2020 | 01 | SAT
05-JAN-20 | 01 | 2020 | 01 | SUN
06-JAN-20 | 02 | 2020 | 01 | MON
07-JAN-20 | 02 | 2020 | 01 | TUE
08-JAN-20 | 02 | 2020 | 02 | WED
17-JAN-20 | 03 | 2020 | 03 | FRI
db<>fiddle here

How to insert a Calender Items into Oracle DB records? [duplicate]

This question already has answers here:
How to populate calendar table in Oracle?
(3 answers)
Calendar table in SQL
(3 answers)
Closed 3 years ago.
I'm trying to insert a full year Calender into an ORACLE DB records
MY Columns are
----------------------------------------------------------------
| [FULL_DATE] | [DAY] | [MONTH_NAME] | [MONTH_NUMBER] | [YEAR] |
----------------------------------------------------------------
Function
(
#DATEFROM AS DATE
#DATETO AS DATE
) RETURNS DATE
AS
BEGIN
set #datefrom = '01/01/1995'
set #dateto = '31/12/1996'
while(#datefrom < #dateto)
BEGIN set #datefrom = DATEADD(day , 1 , #datefrom)
insert into SHEMA.DIM_TIME_TABLE ( FULL_DATE , DAY , MONTH , YEAR ) select DAY(GETDATE(#datefrom)) , DATENAME(MONTH , #datefrom), MONTH(GETDATE(#datefrom)) , YEAR(GETDATE(#datefrom))
END
RETURN
END
EXPECTED :
---------------------------------------------------------------
01 / 01 /1995 | 01 | JAN | 01 | 1995
---------------------------------------------------------------
02 / 01 /1995 | 02 | JAN | 01 | 1995
---------------------------------------------------------------
03 / 01 /1996 | 03 | JAN | 01 | 1995
In Oracle, you can use a recursive query to generate the date series, and then generate the expected columns in the outer query:
create table dim_time_table as
select
dt full_date,
extract(day from dt) day,
to_char(dt, 'month') month_name,
extract(month from dt) month_number,
extract(year from dt) year
from (
select to_date('1995-01-01', 'yyyy-mm-dd') + level - 1 as dt
from dual
connect by
to_date('1995-01-01', 'yyyy-mm-dd') + level
<= to_date('1997-01-01', 'yyyy-mm-dd')
)
Demo on DB Fiddle:
FULL_DATE | DAY | MONTH_NAME | MONTH_NUMBER | YEAR
:-------- | --: | :--------- | -----------: | ---:
01-JAN-95 | 1 | january | 1 | 1995
02-JAN-95 | 2 | january | 1 | 1995
03-JAN-95 | 3 | january | 1 | 1995
04-JAN-95 | 4 | january | 1 | 1995
05-JAN-95 | 5 | january | 1 | 1995
06-JAN-95 | 6 | january | 1 | 1995
07-JAN-95 | 7 | january | 1 | 1995
...

postgresql - cumul. sum active customers by month (removing churn)

I want to create a query to get the cumulative sum by month of our active customers. The tricky thing here is that (unfortunately) some customers churn and so I need to remove them from the cumulative sum on the month they leave us.
Here is a sample of my customers table :
customer_id | begin_date | end_date
-----------------------------------------
1 | 15/09/2017 |
2 | 15/09/2017 |
3 | 19/09/2017 |
4 | 23/09/2017 |
5 | 27/09/2017 |
6 | 28/09/2017 | 15/10/2017
7 | 29/09/2017 | 16/10/2017
8 | 04/10/2017 |
9 | 04/10/2017 |
10 | 05/10/2017 |
11 | 07/10/2017 |
12 | 09/10/2017 |
13 | 11/10/2017 |
14 | 12/10/2017 |
15 | 14/10/2017 |
Here is what I am looking to achieve :
month | active customers
-----------------------------------------
2017-09 | 7
2017-10 | 6
I've managed to achieve it with the following query ... However, I'd like to know if there are a better way.
select
"begin_date" as "date",
sum((new_customers.new_customers-COALESCE(churn_customers.churn_customers,0))) OVER (ORDER BY new_customers."begin_date") as active_customers
FROM (
select
date_trunc('month',begin_date)::date as "begin_date",
count(id) as new_customers
from customers
group by 1
) as new_customers
LEFT JOIN(
select
date_trunc('month',end_date)::date as "end_date",
count(id) as churn_customers
from customers
where
end_date is not null
group by 1
) as churn_customers on new_customers."begin_date" = churn_customers."end_date"
order by 1
;
You may use a CTE to compute the total end_dates and then subtract it from the counts of start dates by using a left join
SQL Fiddle
Query 1:
WITH edt
AS (
SELECT to_char(end_date, 'yyyy-mm') AS mon
,count(*) AS ct
FROM customers
WHERE end_date IS NOT NULL
GROUP BY to_char(end_date, 'yyyy-mm')
)
SELECT to_char(c.begin_date, 'yyyy-mm') as month
,COUNT(*) - MAX(COALESCE(ct, 0)) AS active_customers
FROM customers c
LEFT JOIN edt ON to_char(c.begin_date, 'yyyy-mm') = edt.mon
GROUP BY to_char(begin_date, 'yyyy-mm')
ORDER BY month;
Results:
| month | active_customers |
|---------|------------------|
| 2017-09 | 7 |
| 2017-10 | 6 |

All years and months between 2 dates SQL

I have a little question I have a table called project that looks like this:
---------------------------------------
ProjectId | StartDate | EndDate |
---------------------------------------
1 | 01/01/2015 | 31/12/2017|
Is it posible to get all months and years between those dates like this:
--------------------
| Month | Year |
--------------------
1 | 2015 |
2 | 2015 |
3 | 2015 |
4 | 2015 |
5 | 2015 |
6 | 2015 |
7 | 2015 |
8 | 2015 |
9 | 2015 |
10 | 2015 |
11 | 2015 |
12 | 2015 |
1 | 2016 |
2 | 2016 |
3 | 2016 |
4 | 2016 |
. | . |
. | . |
. | . |
12 | 2017 |
Here's a method using PostgreSQL functions generate_series and extract:
SELECT extract(month FROM date) AS month, extract(year FROM date) AS year
FROM (
SELECT generate_series('2015-01-01'::date, '2017-12-31'::date, '1 month'::interval) AS date
) AS date_range
https://www.postgresql.org/docs/current/static/functions-srf.html
https://www.postgresql.org/docs/current/static/functions-datetime.html
You'd need to modify this to use the dates from your table:
SELECT extract(month FROM range) AS month, extract(year FROM range) AS year
FROM (
SELECT generate_series(StartDate, EndDate, '1 month'::interval) AS range
FROM project
WHERE ProjectId = 1
) AS date_range
If your database is sql server, you can run the following code to get the result.
DECLARE #DateStart DATETIME = '2015-01-01'
DECLARE #DateEnd DATETIME = ' 2017-12-31';
WITH Dates AS
(
SELECT DATEADD(DAY, -(DAY(#DateStart) - 1), #DateStart) AS [Date]
UNION ALL
SELECT DATEADD(MONTH, 1, [Date])
FROM Dates
WHERE [Date] < DATEADD(DAY, -(DAY(#DateEnd) - 1), #DateEnd)
)
SELECT
MONTH([Date]) AS [Month],
YEAR([Date]) AS [Year]
FROM Dates;
Hope it will help. If you need more help, you can look at the following link
https://blog.sqlauthority.com/2014/12/22/sql-server-list-the-name-of-the-months-between-date-ranges-part-2/
In Sql server, query for your date type
;with datecte (date)
AS
(
SELECT Convert(date,'01/01/2015',105)
UNION ALL
SELECT DATEADD(month,1,date)
from datecte
where DATEADD(month,1,date)<= (Select Convert(date,'31/12/2017',105))
)
select month(date),YEAR(date) from datecte

Postgresql query to get count per months within one year

In MySQL
SELECT y, m, Count(users.created_date)
FROM (
SELECT y, m
FROM
(SELECT YEAR(CURDATE()) y UNION ALL SELECT YEAR(CURDATE())-1) years,
(SELECT 1 m UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8
UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12) months) ym
LEFT JOIN users
ON ym.y = YEAR(FROM_UNIXTIME(users.created_date))
AND ym.m = MONTH(FROM_UNIXTIME(users.created_date))
WHERE
(y=YEAR(CURDATE()) AND m<=MONTH(CURDATE()))
OR
(y<YEAR(CURDATE()) AND m>MONTH(CURDATE()))
GROUP BY y, m;
Mysql Output
+------+----+----------------------+
| y | m | Count(users.created) |
+------+----+----------------------+
| 2012 | 5 | 5595 |
| 2012 | 6 | 4431 |
| 2012 | 7 | 3299 |
| 2012 | 8 | 429 |
| 2012 | 9 | 0 |
| 2012 | 10 | 3698 |
| 2012 | 11 | 6208 |
| 2012 | 12 | 5142 |
| 2013 | 1 | 1196 |
| 2013 | 2 | 10 |
| 2013 | 3 | 0 |
| 2013 | 4 | 0 |
+------+----+----------------------+
** IN POSTGRESQL QUERY**
SELECT to_char(created_date, 'MM'),
count(id)
FROM users
WHERE created_date >
date_trunc('month', CURRENT_DATE) - INTERVAL '1 year'
GROUP BY 1
POSTGRESQL OUTPUT
postgresql output
May I know how to get postgresql output as like mysql output. Need to get results for current month within one year data.
I'm assuming what you're looking for is the rows where count is 0. If that is the case you can use generate_series and a left join on your table with data:
SELECT to_char(i, 'YY'), to_char(i, 'MM'),
count(id)
FROM generate_series(now() - INTERVAL '1 year', now(), '1 month') as i
left join users on (to_char(i, 'YY') = to_char(created_date, 'YY')
and to_char(i, 'MM') = to_char(created_date, 'MM') and login_type = 1)
GROUP BY 1,2;