All years and months between 2 dates SQL - 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

Related

How to group by month and year?

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');

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 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;

SQL - Count number of itemactive within a date rate

I have a dataset of Resources, Projects, StartDate and EndDate.
Each Resource can be utilised by multiple projects.
I want to get a count of the number of projects that are using a resource in each quarter.
So if project starts in Q1 of a particular year and ends in Q3 that year, and project2 starts in Q2 and ends in Q3, I want to get a count of 2 projects for Q2, since during Q1 both project1 and project2 were active.
Here is my dataset:
create table Projects
(Resource_Name varchar(20)
,Project_Name varchar(20)
,StartDate varchar(20)
,EndDate varchar(20)
)
insert into Projects values('Resource 1','Project A','15/01/2013','1/11/2014')
insert into Projects values('Resource 1','Project B','1/03/2013','1/09/2016')
insert into Projects values('Resource 1','Project C','1/04/2013','1/09/2015')
insert into Projects values('Resource 1','Project D','1/06/2013','1/03/2016')
insert into Projects values('Resource 1','Project E','15/01/2013','1/09/2015')
insert into Projects values('Resource 1','Project F','3/06/2013','1/11/2015')
And here is the result I'm looking for:
Resource Name| Year | Quarter|Active Projects
Resource 1 2013 1 2
Resource 1 2013 2 6
Using tally table:
Using the dates from Projects, generate a list of all quarters and their start dates and end dates, in this example, that is CteQuarter(sd, ed). After that, you simply need to JOIN the Projects table to CteQuarter for overlapping dates. Then finally, GROUP BY using the YEAR and Quarter part of the date.
SQL Fiddle
WITH CteYear(yr) AS(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number >= (SELECT MIN(YEAR(CONVERT(DATE, StartDate, 103))) FROM Projects)
AND number <= (SELECT MAX(YEAR(CONVERT(DATE, EndDate, 103))) FROM Projects)
),
CteQuarter(sd, ed) AS(
SELECT
DATEADD(QUARTER, q.n - 1, DATEADD(YEAR, cy.yr - 1900, 0)),
DATEADD(DAY, -1, DATEADD(QUARTER, q.n, DATEADD(YEAR, cy.yr - 1900, 0)))
FROM CteYear AS cy
CROSS JOIN(
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
) AS q(n)
)
SELECT
p.Resource_Name,
[Year] = DATEPART(YEAR, q.sd),
[Quarter] = DATEPART(QUARTER, q.sd),
[Active Projects] = COUNT(*)
FROM Projects p
INNER JOIN CteQuarter q
ON CONVERT(DATE, StartDate, 103) <= q.ed
AND CONVERT(DATE, EndDate, 103) >= q.sd
GROUP BY
p.Resource_Name,
DATEPART(YEAR, q.sd),
DATEPART(QUARTER, q.sd)
ORDER BY
p.Resource_Name,
DATEPART(YEAR, q.sd),
DATEPART(QUARTER, q.sd)
Notes:
Here is a great way to check for overlapping dates.
Some common date routines
RESULT:
| Resource_Name | Year | Quarter | Active Projects |
|---------------|------|---------|-----------------|
| Resource 1 | 2013 | 1 | 3 |
| Resource 1 | 2013 | 2 | 6 |
| Resource 1 | 2013 | 3 | 6 |
| Resource 1 | 2013 | 4 | 6 |
| Resource 1 | 2014 | 1 | 6 |
| Resource 1 | 2014 | 2 | 6 |
| Resource 1 | 2014 | 3 | 6 |
| Resource 1 | 2014 | 4 | 6 |
| Resource 1 | 2015 | 1 | 5 |
| Resource 1 | 2015 | 2 | 5 |
| Resource 1 | 2015 | 3 | 5 |
| Resource 1 | 2015 | 4 | 3 |
| Resource 1 | 2016 | 1 | 2 |
| Resource 1 | 2016 | 2 | 1 |
| Resource 1 | 2016 | 3 | 1 |
You can do this by determining the first and last quarters when a project is active, and then using cumulative sum. In SQL Server 2012+, this looks like
select resource_name, yyyyq,
(sum(sum(s)) over (partition by resource_name order by yyyyq) -
sum(sum(e)) over (partition by resource_name order by yyyyq) +
e
) as activeProjects
from ((select resource_name, datepart(year, startdate) + datepart(quarter, startdate) as yyyyq, 1 as s, 0 as e
from projects
) union all
(select resource_name, datepart(year, enddate) + datepart(quarter, enddate), 0 as s, 1 as e
from projects
)
) yq
group by resource_name, yyyyq;
In earlier versions, you can do something similar with cross apply.

SQL Days before end of the month

i have got table with transactions, looking like:
+----+--------------+----------------+------+
| ID | OrderDate | DeliveryDate | EUR |
+----+--------------+----------------+------+
| 1 | 2015-02-21 | 2015-02-25 | 100 |
| 2 | 2015-03-01 | 2015-03-14 | 110 |
| 3 | 2015-03-01 | 2015-03-17 | 90 |
| 4 | 2015-03-10 | 2015-03-20 | 250 |
| 5 | 2015-03-31 | 2015-03-31 | 350 |
+----+--------------+----------------+------+
ANd I need to get sum of revenue and number of orders (COUNT of IDs) based on Days before the end of the month when order gets delivered.
SELECT datediff(day, OrderDate, CAST(DATEADD(month, DATEDIFF(month,0,getdate()+1,0)-1) as Date) as DBEOM, SUM(EUR) as Rev, COUNT(ID) as NumberOfOrders
FROM transactions
WHERE MONTH(DeliveryDate) = 3 AND YEAR(DeliveryDate) = 2015
GROUP BY datediff(day, OrderDate, CAST(DATEADD(month, DATEDIFF(month,0,getdate()+1,0)-1) as Date) as DBEOM
ORDER BY 1
The result in this case would be like:
+-----+-----+----------------+
|DBEOM| Rev | NumberOfOrders |
+-----+-----+----------------+
| 0 | 350 | 1 |
| 21 | 250 | 1 |
| 30 | 200 | 2 |
+-----+-----+----------------+
This is done in SQL 2008, so I can't simply use EOMONTH. I have tried, what is above, but i am getting
ERROR -
[Microsoft][ODBC SQL Server Driver][SQL Server]The datediff function
requires 3 argument(s).
Many thanks in advance for advice!
The easiest way I've found get the last day of the month with more primitive functions is to get the first day of the next month and then subtract a day.
I'm not a TSQL guy so this syntax likely won't be correct but you need something more like
DATEADD(day, DATEFROMPARTS(DATEPART(year, DATEADD(month,1,getdate()), DATEPART(month, DATEADD(month,1,getdate()), 1), -1)
Try:
SELECT datediff(day,
OrderDate,
dateadd(DAY,
-1,
dateadd(MONTH,
1,
dateadd(DAY,
1-day(DeliveryDate),
DeliveryDate
)
)
)
) as DBEOM, SUM(EUR) as Rev, COUNT(ID) as NumberOfOrders
FROM t
WHERE MONTH(DeliveryDate) = 3 AND YEAR(DeliveryDate) = 2015
GROUP BY datediff(day,
OrderDate,
dateadd(DAY,
-1,
dateadd(MONTH,
1,
dateadd(DAY,
1-day(DeliveryDate),
DeliveryDate
)
)
)
)
ORDER BY 1
sqlfiddle.com