Running Total in Oracle SQL - insert missing rows - sql

Let's assume I have following set of data in Oracle SQL database:
Product Year Month Revenue
A 2016 1 7
A 2016 5 15
After creating running totals with following code
select Product, Year, Month, Revenue,
sum(Revenue) over (partition by Product, Year order by Month) Revenue_Running
from exemplary_table
I receive following result:
Product Year Month Revenue Revenue_Running
A 2016 1 7 7
A 2016 5 15 22
Is there any way that I can get this:
Product Year Month Revenue Revenue_Running
A 2016 1 7 7
A 2016 2 (null) 7
A 2016 2 (null) 7
A 2016 4 (null) 7
A 2016 5 15 22

You need a calendar table and Left join with your exemplary_table
SELECT p.product,
c.year,
c.month,
COALESCE(revenue, 0),
Sum(revenue)OVER (partition BY p.product, c.year ORDER BY c.month) Revenue_Running
FROM calendar_table c
CROSS JOIN (SELECT DISTINCT product
FROM exemplary_table) p
LEFT JOIN exemplary_table e
ON c.year = e.year
AND e.month = c.month
WHERE c.dates >= --your start date
AND c.dates <= --your end date

Related

SQL get year-on-year quarter-to-date revenue

Having the table below:
Year Quarter Month Revenue
2005 Q1 1 13
2006 Q1 1 10
2006 Q1 2 15
2006 Q1 3 35
2006 Q2 4 11
2006 Q2 5 15
2006 Q2 6 9
2007 Q1 1 6
2007 Q1 2 14
2007 Q1 3 7
2007 Q2 4 20
2007 Q2 5 6
2007 Q2 6 6
I need a query to calculate the year-on-year comparison of quarter-to-date revenue as below:
Year Quarter Month CUrrentQTDRevenue PreviousQTDRevenue
2005 Q1 1 13
2006 Q1 1 10 13
2006 Q1 2 25 13
2006 Q1 3 60 13
2006 Q2 4 11
2006 Q2 5 26
2006 Q2 6 35
2007 Q1 1 6 10
2007 Q1 2 20 25
2007 Q1 3 27 60
2007 Q2 4 20 11
2007 Q2 5 26 26
2007 Q2 6 32 35
I've managed to get the current year quarter-to-date revenue
SELECT Year, Quarter, Month
, SUM(Revenue) OVER (PARTITION BY Year, Quarter ORDER BY Year, Quarter, Month)
AS CurrentYearQuarterToDateRevenue
FROM revenue
but how do I get to the second part? Note that I can't simply join quarters and months since, for example, 2005 has only one month for Q1, so Q1 for 2006 will have 13 for every month.
In the example the prior year revenue is inconsistently applied. If the YQM revenue were cumulative by Quarter in 2007 vs 2006 as well as 2006 vs 2005, then the value of 13 would carry forward into month 2 and 3 of Q1. Something like this
with yqm_ytd_cte(Year, Quarter, Month, YQM_YTD_Revenue) as (
select Year, Quarter, Month,
sum(Revenue) over (partition by Year, Quarter order by Year, Quarter, Month)
from revenue)
select yy.*, isnull(yy_lag.YQM_YTD_Revenue, 0) as Prior_Year_YQM_YTD_Revenue
from yqm_ytd_cte yy
left join yqm_ytd_cte yy_lag on yy.Year=yy_lag.Year-1
and yy.Quarter=yy_lag.Quarter
and yy.Month=yy_lag.Month;
I think I would expand the data out and use window functions:
with yyyymm as (
select t.year, m.month, m.qtr, t.revenue, t.quarter
from (select distinct year from t) y cross join
(values (1, 1), (2, 1), . . . (12, 4)) m(month, qtr) left join
t
on t.year = y.year and t.month = m.month
)
select ym.*
from (select ym.*, lag(currentQTD, 12) over (order by year, month) as prevQTD
from (select ym.*,
sum(revenue) over (partition by year, qtr order by month) as currentQTD
from yyyymm ym
) ym
) ym
where quarter is null;
You can also use apply:
select t.*,
sum(revenue) over (partition by year, quarter order by month) as currentQTD,
tt.prevQTD
from t outer apply
(select sum(revenue) as prevQTD
from t tt
where tt.year = t.year - 1 and
tt.quarter = t.quarter and
tt.month <= t.month
) tt;

How to get Fiscal Year to only show the last 3 years

This question is probably a duplicate but I couldn't find it after 10 mins of research. Here is the question:
I am trying to get the last 3 Fiscal years to show up in my query: so for me it would be 2018, 2019, and 2020.
SELECT distinct E.FISCALYEAR
FROM EMPLOYEES as E
INNER JOIN HR_PERIODS as H ON E.PERIOD = H.PERIOD
WHERE
E.FISCALYEAR <= year(getdate()) + 1
and E.RECORDSTATUS = 1
ORDER BY E.FISCALYEAR
The query I currently have does:
2015
2016
2017
2018
2019
2020
Also our HR Fiscal Year populates from 2015 to Present fiscal year.
You can use top (3):
SELECT distinct TOP (3) E.FISCALYEAR
FROM RPT_EMPLOYEECENSUS_ASOF E INNER JOIN
HR_PERIODS H
ON E.PERIODNUMBER = H.PERIODNUMBER
WHERE E.FISCALYEAR <= year(getdate()) + 1 AND
E.EOM_RECORDSTATUS_EFF = 1
ORDER BY E.FISCALYEAR DESC

Multiple Group by in SQL

I have a table like this.
Year Month TenDays Pay
========================================
2015 8 2 12
2016 8 1 43
2016 8 2 11
2016 9 1 22
2016 9 2 33
2016 9 3 4
2016 9 3 25
I want to have SQL query that calculate sum of 'Pay' as 'TotalTenDays' group by 'year' and 'Month' and 'TenDays'
and also calculate sum of 'Pay' as 'TotalMonth' group by 'year' and 'Month'.
I can do that with "union all" but I am searching for a way without using union and 'with cte as()'.
Is it Possible?
Expected table must be like this:
Year Month TenDays TotalTenDays TotalMonth
====================================================================
2015 8 2 12 12
2016 8 1 43 54
2016 8 2 11 54
2016 9 1 22 84
2016 9 2 33 84
2016 9 3 29 84
The answer depends on the database dialect.
The first 4 columns are standard SQL GROUP BY logic, i.e. GROUP BY Year, Month, TenDays with a SUM(Pay) AS TotalTenDays result column.
The TotalMonth column is best done with a windowing function using the OVER clause, but that's only if the SQL dialect supports it.
E.g. for SQL Server, you can do this:
SELECT Year, Month, TenDays
, SUM(Pay) AS TotalTenDays
, SUM(SUM(Pay)) OVER (PARTITION BY Year, Month) AS TotalMonth
FROM MyTable
GROUP BY Year, Month, TenDays
ORDER BY Year, Month, TenDays
See SQL Fiddle for running query using MS SQL Server 2017.
If the SQL dialect doesn't support windowing functions, then suggestion in comment by Jonathan Leffler is a good alternative:
You need to create two sub-queries that do the aggregations, and then join the results of those two sub-queries. Each sub-query will have a different GROUP BY clause.
SELECT a.Year, a.Month, a.TenDays, a.TotalTenDays, b.TotalMonth
FROM ( SELECT Year, Month, TenDays
, SUM(Pay) AS TotalTenDays
FROM MyTable
GROUP BY Year, Month, TenDays
) a
JOIN ( SELECT Year, Month
, SUM(Pay) AS TotalMonth
FROM MyTable
GROUP BY Year, Month
) b ON b.Year = a.Year
AND b.Month = a.Month
ORDER BY a.Year, a.Month, a.TenDays
See SQL Fiddle for running query using MySQL 5.6.

SQL: add missing months from different years

SQL SERVER
[CreatedOn] - DATETIME
I get this table:
Year Month Count
2009 7 1
2009 9 1
2010 1 2
2010 3 13
From query:
SELECT
YEAR ([CreatedOn]) AS 'Year',
MONTH ([CreatedOn]) AS 'Month',
COUNT ([CreatedOn]) AS 'Count'
FROM xxx
GROUP BY YEAR ([CreatedOn]), MONTH ([CreatedOn])
How can I get table like this (with missed months and Count 0):
Year Month Count
2009 7 1
2009 8 0
2009 9 1
2009 10 0
2009 11 0
2009 12 0
2010 1 2
2010 2 0
2010 3 13
Syntax says you are using MSSQL. Use Recursive CTE to generate the calender table then do a Left outer join with XXX table
DECLARE #maxdate DATE = (SELECT Max([CreatedOn])
FROM xxx);
WITH calender
AS (SELECT Min([CreatedOn]) dates,
FROM xxx
UNION ALL
SELECT Dateadd(mm, 1, dates)
FROM cte
WHERE dates < #maxdate)
SELECT Year(dates) [YEAR],
Month(dates) [month],
Count ([CreatedOn]) AS 'Count'
FROM calender a
LEFT OUTER JOIN xxx b
ON Year(dates) = Year ([CreatedOn])
AND Month(dates) = Month ([CreatedOn])
GROUP BY Year(dates),
Month(dates)
Note : Instead of Recursive CTE create a physical calender table
This will use a build in table to create the calendar:
;WITH limits as
(
SELECT min([CreatedOn]) mi, max([CreatedOn]) ma
FROM xxx
), months as(
SELECT
dateadd(mm, number, mi) m
FROM
master..spt_values v
JOIN
limits l
ON
number between 0 and datediff(mm, l.mi, l.ma)
WHERE
v.type = 'P'
)
SELECT
year(months.m) year,
month(months.m) month,
count(qry.[CreatedOn]) cnt
FROM
xxx qry
RIGHT JOIN
months
ON
months.m = dateadd(mm, datediff(mm, 0, qry.[CreatedOn]), 0)
GROUP BY
year(months.m),
month(months.m)

How to get month and year in single column and grouping the data for all the years and months?

For the below query (sdate is column name and table name is storedata)
Collapse
WITH TotalMonths AS (SELECT T1.[Month], T2.[Year]
FROM ((SELECT DISTINCT Number AS [Month]
FROM MASTER.dbo.spt_values WHERE [Type] = 'p' AND Number BETWEEN 1 AND 12) T1 CROSS JOIN
(SELECT DISTINCT DATEPART(year, sdate) AS [Year]
FROM storedata) T2))
SELECT CTE.[Year], CTE.[Month], ISNULL(T3.[Sum], 0) areasum
FROM TotalMonths CTE LEFT OUTER JOIN (
SELECT SUM(areasft) [Sum], DATEPART(YEAR, sdate) [Year], DATEPART(MONTH, sdate) [Month]
FROM storedata
GROUP BY DATEPART(YEAR, sdate) ,DATEPART(MONTH, sdate)) T3
ON CTE.[Year] = T3.[Year] AND CTE.[Month] = T3.[Month] WHERE CTE.[Year]>'2007'
ORDER BY CTE.[Year], CTE.[Month]
I am getting result set like below.
YEAR MONTH AREASUM
2008 1 0
2008 2 1193
2008 3 4230
2008 4 350
2008 5 2200
2008 6 4660
2008 7 0
2008 8 6685
2008 9 0
2008 10 3051
2008 11 7795
2008 12 2940
2009 1 1650
2009 2 3235
2009 3 2850
2009 4 6894
2009 5 3800
2009 6 2250
2009 7 1000
2009 8 1800
2009 9 1550
2009 10 2350
2009 11 0
2009 12 1800
But I have to combine both month and year in single column. The reult set should like below.
JAN/08 O
FEB/08 1193
.. ..
.. ..
DEC/O9 1800
How can I modify my query? (I should display for all the years and months even if there is no area for a month)
Regards,
N.SRIRAM
Try:
SELECT CONVERT(VARCHAR(3), DATENAME(MONTH, CTE.Month), 7) + '/' + RIGHT(CTE.Year, 2)
instead of using your first 2 columns from your SELECT.
You seem to be saying that you're getting the right data from your original query, but the wrong format. So
Make a view out of the query you originally posted.
Build a SELECT query based on that view to give you the format you want.
Let's say you do this:
CREATE VIEW wibble AS <your original query goes here>
Then you can just query wibble to correct the formatting.
select
case
when month = 1 then 'Jan/'
when month = 2 then 'Feb/'
when month = 3 then 'Mar/'
when month = 4 then 'Apr/'
when month = 5 then 'May/'
when month = 6 then 'Jun/'
when month = 7 then 'Jul/'
when month = 8 then 'Aug/'
when month = 9 then 'Sep/'
when month = 10 then 'Oct/'
when month = 11 then 'Nov/'
when month = 12 then 'Dec/'
else 'Err'
end || substring(cast(year as CHAR(4)), 3, 2) as yearmonth,
areasum from wibble;