Weekly/monthly/quarterly grouping in query - sql

Lets say I have table with following columns
1. Client - string.
2. Profit - integer.
3. Deal_Date - date.
I need query that will retrieve sum of profit breakdown by week/month/quater etc.
Expected output for weeks
1 row, sum (profit) of all deals that registered from (03.19.2012 - 03.12.2012).
2 row, sum (profit) of all deals that registered from (03.12.2012 - 03.05.2012).
...
n row, sum (profit) of all deals that registered from (05.17.2011 - 05.10.2011).
NOTE (dates set just for example)
The same for month, years, etc.
Could someone help me with such query?
Btw performance is very important.

This query uses simple date formats to extract the various elements you want to track and analytics to get the sums.
select client
, yr
, qtr
, wk
, sum ( profit ) over ( partition by client, yr) as yr_profit
, sum ( profit ) over ( partition by client, yr, qtr) as qtr_profit
, sum ( profit ) over ( partition by client, yr, wk) as wk_profit
from (
select client
, profit
, to_char(deal_date, 'yyyy') as yr
, to_char(deal_date, 'q') as qt
, to_char(deal_date, 'ww') as wk
from your_table )
/
This will produce one row for each row in the current table. So you probebly will want to wrap it in a further outer query which only returns only distinct rows.
A variant would be to use rollup instead. I'm not sure how well that works when the grouping criteria aren't perfectly hierarchical (weeks don't fit neatly into quarters).
select client
, yr
, qtr
, wk
, sum ( profit ) as profit
from (
select client
, profit
, to_char(deal_date, 'yyyy') as yr
, to_char(deal_date, 'q') as qt
, to_char(deal_date, 'ww') as wk
from your_table )
group by rollup ( client, yr, qtr, wk )
/

Just make an SP and loop the code for each week or month or year as you wish.

Related

Looking to Aggregate 3 Counts of Data as columns by distinct account number in a given list. All of my data is in the same table

Here is the basic of what I am trying to do in pseudo code. All of my data I need is in the same table.
SELECT DISTINCT ACCOUNT_NUMBER
, COUNT(INVOICES FOR INV_DATE WITHN 2022)
, COUNT(INVOICES FOR INV_DATE WITHIN 2021)
, COUNT(INVOICES FOR INV_DATE WITHIN 2020)
FROM SALES_DATA
WHERE ACCOUNT_NUMBER IN ('987987','98845','966554').
I can easily get the first columns, but joining the additional years I am struggling.
You can use PIVOT after collapsing the invoices to just the account number and year:
; -- previous statement terminator sqlblog.org/cte
WITH cte AS
(
SELECT ACCOUNT_NUMBER, y = DATEPART(YEAR, INV_DATE)
FROM dbo.SALES_DATA
WHERE INV_DATE >= '20200101'
-- AND ACCOUNT_NUMBER IN (some,list)
)
SELECT * FROM cte
PIVOT
(
COUNT(y) FOR y IN ([2020],[2021],[2022])
) AS p;
Example db<>fiddle

SQL - lag variable creation using window function

I have daily city level data with some counts. I have to aggregate this data at monthly level(1st day of each month) and then create lag variables based on last 1 week from 1st day of month.
I have used following code to create lag variables for last 1 month using (after aggregating data at monthly level ( with 1st date of month)
sum(count) over (partition by City order by month_date rows between 1 preceding and 1 preceding) as last_1_month_count
Is there a way to aggregate data at monthly level and create lag variables based on last 7,14,21,28 days using window function?
you can use this L
select
CITY
, month(Date)
, year(date)
, sum(count)
from table1
where date < Datediff(days , 7 , getdate())
group by
City
, month(Date)
, year(date)
I think you're looking for something like this. The first cte summarizes city counts to the day, week, month, year. The second summarizes the counts to the week, month, year. To group sales by weeks starting from the 1st day it uses the DAY function along with YEAR and MONTH. Since DAY returns and integer, groups of distinct weeks can be created by dividing by 7, i.e. DAY(day_dt)/7.
One way to get the prior week sales would be to join the week sales summary cte to itself where the week is offset by -1. Since the prior week might possible have 0 sales it seems safer to LEFT JOIN than to use LAG imo
with
day_sales_cte(city, day_dt, yr, mo, wk, sum_count) as (
select city, day_dt, year(day_dt), month(day_cte), day(day_dt)/7, sum([count]) sum_counts
from city_level_data
group by city, day_dt, year(day_dt), month(day_cte), day(day_dt)/7)
wk_sales_cte(city, yr, mo, wk, sum_count) as (
select city, yr, mo, wk, sum(sum_counts) sum_counts
from sales_cte
group by city, yr, mo, wk)
select ws.*, ws2.sum_sales prior_wk_sales
from wk_sales_cte ws
left join wk_sales_cte ws2 on ws.city=ws2.city
and ws.yr=ws2.yr
and ws.mo=ws2.mo
and ws.wk=ws.wk-1;

Creating a fix table with common time period across 1 year period

I need to create a table with common time interval across a year, with the percentage completion variable as well as the serial number, using SQL query:
S/N Percentage Month
1 8% June
2 17% July
3 25% August
...
...
12 100% May
I would like to ask if there is a more cleaner/ efficient way of doing it.
My original approach is to first create the time interval and the serial number using a recursive CTE, following by creating the percentage attribute next.
Thank you!
Alternate solution for DB2 Z/OS
SELECT
rownum "S/N" ,
100*( DAYS(stdt + (rownum-1) MONTH ) - DAYS(stdt -1 MONTH ) ) /365 "Percentage" ,
VARCHAR_FORMAT(stdt + (rownum-1) MONTH,'Month') "Month"
FROM (
SELECT ROW_NUMBER() OVER() , DATE('2018-06-01')
FROM SYSIBM.SYSCOLUMNS
) T(rownum,stdt)
WHERE rownum <=12
You can use syscat.columns table to generate months and row_number() function to get percentage
Here is the Query:-
SELECT rn "S/N",
ROUND((rn /count(1) over())*100,0)|| '%' "Percentage",
my_month "Month" from (
-- #startdate '04/01/2017' (MM/DD/YYYY) format
SELECT VARCHAR_FORMAT(DATE(#startdate) + (ROW_NUMBER()OVER() - 1) MONTH,'MON') my_month,
ROW_NUMBER()OVER() rn
FROM SYSCAT.COLUMNS where rownum <=12
)

Day level Calculation in oracle sql

I have two year static data .I have column name as stats_date,P2P_volume .Initially i created following query for single day in oracle sql developer
select '1' as KPI_ID, 'P2P' as KPI_DESC,'22-MAR-17' as dates,
(sum(case when STATS_DATE between add_months('22-MAR-17',0)-13
and add_months('22-MAR-17',0)-7 then P2P_VOLUME else 0 end )) LAST_WEEK_Volume,
(sum(case when STATS_DATE between add_months('22-MAR-17',0)-6
and add_months('22-MAR-17',0) then P2P_VOLUME else 0 end )) THIS_WEEK_Volume from table
my problem is i want create dynamic query which will give me Last_week_volume,and this_week_volume Date wise for two years.rather than single day
In the absence of a complete set of sample data and requirements here are my assumptions:
There is one row per day per KPI
The definition of current week, previous week can be satisfied
by using the 'IW' date format mask
This solution uses a subquery to calculate the sum of the measures for each week. This feeds into the main query which uses an analytic lag() function to show the totals for the current week and the previous week.
with cte as (
select kpi
, to_char(static_date, 'YYYY') as yr
, to_char(static_date, 'IW') as wk
, sum(volume) as wk_volume
, sum(value) as wk_value
, sum(revenue) as wk_revenue
from t23
group by kpi,to_char(static_date, 'YYYY'), to_char(static_date, 'IW')
)
select kpi
, yr||'-'||wk as year_wk
, wk_volume as curr_wk_volume
, lag(wk_volume) over (order by yr, wk) as prev_wk_volume
, wk_value as curr_wk_value
, lag(wk_value) over (order by yr, wk) as prev_wk_value
, wk_revenue as curr_wk_revenue
, lag(wk_revenue) over (order by yr, wk) as prev_wk_revenue
from cte
order by 1, 2
/
There is a SQL Fiddle demo here.

getting data for individual months using single query

Im having 3 tables as per below picture (im giving just sample data but actual tables having data for all months). My SALES table will contain the data both for future(which were sold in future) and past dates.
select item_id as agg from item_category f JOIN
sales t ON f.item_id=t.item_id where t.selling_date
BETWEEN sysdate AND sysdate+21 and f.item_type='medicine';
and now my query returns ITEMS which were sold for next 21 days. Now i want to get the profit of these ITEMS for past one year
For example i want the profit for last one year as Jan:2000,feb:3000,mar:1000.......
To get the output in rows:
SELECT -- s.item_id, -- Not sure if you want it total or per item
TRUNC( s.sold_date, 'MM' ) AS sold_month,
SUM( r.profit ) AS total_profit
FROM sales s
INNER JOIN
revenue_table r
ON ( s.item_id = r.item_id )
GROUP BY -- s.item_id, -- Not sure if you want it total or per item
TRUNC( s.sold_date, 'MM' )
To PIVOT the rows into columns:
SELECT *
FROM (
SELECT -- s.item_id, -- Not sure if you want it total or per item
TRUNC( s.sold_date, 'MM' ) AS sold_month,
r.profit
FROM sales s
INNER JOIN
revenue_table r
ON ( s.item_id = r.item_id )
)
PIVOT ( SUM( profit ) FOR sold_month IN (
DATE '2017-05-01' AS May2017,
DATE '2017-04-01' AS Apr2017,
DATE '2017-03-01' AS Mar2017,
DATE '2017-02-01' AS Feb2017,
DATE '2017-01-01' AS Jan2017,
DATE '2016-12-01' AS Dec2016,
DATE '2016-11-01' AS Nov2016,
DATE '2016-10-01' AS Oct2016
) )
You could group items by date of sale and aggregate this profit.
SELECT
YEAR(sold_date) AS `Year`,
MONTH(sold_date) AS `Month`,
SUM(profit) AS Profit
FROM sales JOIN Reventue_Table ON sales.item_id=Reventue_Table.item_id
GROUP BY `Year`, `Month`;
If you want to get result for specific year, use HAVING clause. For SQL use DATEPART() function. For oracle use EXTRACT().