I need to add a new column to my table that will have the difference between sum of revenue of a new quarter over the last one.
My data looks like this:
Website Year Quarter Revenue
cosmo.com 2019 4 10
cosmo.com 2020 1 15
cosmo.com 2020 2 5
fashion.com 2019 4 10
fashion.com 2020 1 5
fashion.com 2020 2 20
The desired output is:
Website Year Quarter Revenue Difference
cosmo.com 2019 4 10 +5
cosmo.com 2020 1 15 +5
cosmo.com 2020 2 5 -10
fashion.com 2019 4 10 +10
fashion.com 2020 1 5 -5
fashion.com 2020 2 20 +15
I have tried to see the yearly difference, to begin with, but got a syntax error
select *,
`Revenue` - lag(`Revenue`) over(order by `Year`) as difference
from table`
From what I can tell, you want the difference from the previous quarter, not year. That would be:
select t.*,
(t.Revenue - lag(t.Revenue) over (partition by website order by Year, quarter)) as difference
from table t;
Note the use of partition by for the website.
Related
I have a MySQL requirement to select data from a table based on a start date and end date and group it by weekly also selecting the data in reverse order by date. Assume that, I have chosen the start date as 1st November and the end date as 04 December. Now, I would like to fetch the data as 04 December to 28 November, 27 November to 20 November, 19 November to 12 November and so on and sum the value count for that week.
Given an example table,
id
value
created_at
1
10
2021-10-11
2
13
2021-10-17
3
11
2021-10-25
4
8
2021-11-01
5
1
2021-11-10
6
4
2021-11-18
7
34
2021-11-25
8
17
2021-12-04
Now the result should be like 2021-12-04 to 2021-11-28 as one week, following the same in reverse order and summing the column value data for that week. I have tried in the query to add the interval of 7 days after the end date but it didn't work.
SELECT count(value) AS total, MIN(R.created_at)
FROM data_table AS D
WHERE D.created_at BETWEEN '2021-11-01' AND '2021-12-04' - INTERVAL 7 DAY ORDER BY D.created_at;
And it's also possible to have the last week may have lesser than 7 days.
Expected output:
end_interval
start_interval
total
2021-12-04
2021-11-27
17
2021-11-27
2021-11-20
34
2021-11-20
2021-11-13
4
2021-11-13
2021-11-06
1
2021-11-06
2021-10-30
8
2021-10-30
2021-10-25
11
Note that the last week is only 5 days depending upon the selected from and end dates.
One option to address this problem is to
generate a calendar of all your intervals, beginning from last date till first date, with a split of your choice, using a recursive query
joining back the calendar with the original table
capping start_interval at your start_date value
aggregating values for each interval
You can have three variables to be set, to customize your date intervals and position:
SET #start_date = DATE('2021-10-25');
SET #end_date = DATE('2021-12-04');
SET #interval_days = 7;
Then use the following query, as already described:
WITH RECURSIVE cte AS (
SELECT #end_date AS end_interval,
DATE_SUB(#end_date, INTERVAL #interval_days DAY) AS start_interval
UNION ALL
SELECT start_interval AS end_interval,
GREATEST(DATE(#start_date), DATE_SUB(start_interval, INTERVAL #interval_days DAY)) AS start_interval
FROM cte
WHERE start_interval > #start_date
)
SELECT end_interval, start_interval, SUM(_value) AS total
FROM cte
LEFT JOIN tab
ON tab.created_at BETWEEN start_interval AND end_interval
GROUP BY end_interval, start_interval
Check the demo here.
I want to add the missing months to the table. If the current row having missing month then it should check the previous row and the name of the month in that row and add the next month in the current row.
For eg: the current month is null, it should check the month name in previous row, if the previous row having January then the current month should replace null with February,
for eg. if the current month is null, it should check the month name in previous row having August then next null month name should be replaced with September.
Code for the creating table:
CREATE TABLE IF NOT EXISTS missing_months (
`Cust_id` INT,
`Month` VARCHAR(9) CHARACTER SET utf8,
`Sales_value` INT
);
INSERT INTO missing_months VALUES
(1,'Janurary',224),
(2,'February',224),
(3,NULL,239),
(4,'April',205),
(5,NULL,218),
(6,'June',201),
(7,NULL,205),
(8,'August',246),
(9,NULL,218),
(10,NULL,211),
(11,'November',223),
(12,'December',211);
output is:
Cust_id Month Sales_value
1 Janurary 224
2 February 224
3 null 239
4 April 205
5 null 218
6 June 201
7 null 205
8 August 246
9 null 218
10 null 211
11 November 223
12 December 211
BUT I WANT THE OUTPUT LIKE:
Cust_id Month Sales_value
1 Janurary 224
2 Febrauary 224
3 March 239
4 April 205
5 May 218
6 June 201
7 July 205
8 August 246
9 September 218
10 October 211
11 November 223
12 December 211
update missing_months m
join missing_months prev on prev.Cust_id=m.Cust_id-1
set m.Month=date_format(str_to_date(concat(prev.Month,'-1970-01'),'%M-%Y-%d') + interval 1 month,'%M')
where m.Month is null
order by m.Cust_id
But relying on an identifier field for order is bad; if your data is ordered, you should have some other column indicating what the order is.
select Cust_id, monthname(STR_TO_DATE(rn, '%m')) as Month_Name,
Sales_value
from
(Select Cust_id, Month, row_number() over() as rn,
Sales_value
from missing_month) x;
I have table with 2 columns: Year And Month.
Example:
Year | Month
1. 2020 9
2. 2020 8
3. 2020 7
4. 2020 5
5. 2020 4
I don,t have record for 06.2020, so as a result i want to get only all the results before the break: 1,2,3
Example 2:
1. 2020 12
2. 2020 11
3. 2020 10
4. 2020 09
5. 2020 08
6. 2020 07
7. 2020 05
8. 2020 04
9. 2020 02
I want to get as result: 1,2,3,4,5,6
One method is:
select t.*
from (select t.*,
sum(case when next_yyyymm <> year * 12 + month + 1 then 1 else 0 end) over (order by year desc, month desc) as num_misses
from (select t.*,
lead(year * 12 + month) over (order by year, month) as next_yyyymm
from t
) t
) t
where num_misses = 0;
This adds up the number of misses up to a given year/month combination. It returns the rows with no missing month.
Here is a db<>fiddle showing both examples.
I need to group sum in from previous period in SQL. Here's my data from simplified customer (customer A, B, and C)
Customer Year Month Order
A 2019 5 10
A 2019 4 5
A 2019 3 3
A 2019 2 1
A 2018 12 3
B 2019 5 1
B 2019 4 2
B 2019 3 1
C 2019 5 2
C 2019 4 1
C 2019 2 1
C 2019 1 3
Expected output is sum Order for previous period
For example, Expected output in first row is 12, because it sum in previous period (7 + 4 + 3 + 0) in customer A.
Another example, Expected output in second row is 7 because it sum in previous period (4 + 3 + 0) in customer A. So, table below is the expected output from table above
Customer Year Month Order Output
A 2019 5 10 12
A 2019 4 5 7
A 2019 3 3 4
A 2019 2 1 3
A 2018 12 3 0
B 2019 5 1 3
B 2019 4 2 1
B 2019 3 1 0
C 2019 5 2 5
C 2019 4 1 4
C 2019 2 1 3
C 2019 1 3 0
I need to do this in SQL
First of all, i would change the name of your columns (year, month and order are mysql reserved words or functions). You could do it with a subquery like this:
select customer,
`year`,
`month`,
`order`,
(select sum(output)
from yourtable b
where a.customer=b.customer and (a.year>b.year or (a.year=b.year and a.month>b.month)))
from yourtable a
What you do is you get every row and the last column is the sum of output for all other columns with the same customer and have year lower than the year in your customer or if the year is the same, the month is lower
In MySQL 8+, you should use window functions:
select t.*,
sum(output) over (partition by customer order by year, month)
from t;
Note only is this more concise, but it should have better performance as well.
This can be achieved by Window Functions. Below link provides the example
LAG([,offset[, default_value]]) OVER (
PARTITION BY expr,...
ORDER BY expr [ASC|DESC],...
)
http://www.mysqltutorial.org/mysql-window-functions/mysql-lag-function/
I have an SQL table that contains order data by date. I'm trying to combine the data across years in 4 weeks buckets so that I can compare year on year periods. Luckily the table contains year and week number columns so that I can sum the data to show order totals by week number, for example:
By using SELECT order_year, order_week_number, sum(order_total) from f2l4d1a2ta_237_floodlight_order_data_v1 group by order_week_number ORDER BY order_week_number, order_year
I get:
order_year order_week_number sum(order_total)
2017 1 96.40879041
2017 2 33.34092216
2017 3 97.79772267
2017 4 28.05668819
2017 5 75.79034382
2017 6 41.59171513
2017 7 3.754344347
2017 8 66.27940579
2016 1 65.81290635
2016 2 71.17703765
2016 3 65.95184929
2016 4 90.42108213
2016 5 44.32837015
2016 6 19.9644766
2016 7 53.46359297
2016 8 7.059479081
However what I'm really after is to see the order total for the 4 week period in the year, i.e.
order_year 4 week period sum(order_total)
2017 1 255.6041234
2017 2 187.4158091
2016 1 293.3628754
2016 2 124.8159188
Does anyone know how to group data with SQL in this way?
Thanks,
Matt
Add 3 to the week number then integer divide by 4 (whole number result)
Eg (1+3) DIV 4 = 1, (4+3) DIV 4 = 1
So GROUP BY (weekno + 3) DIV 4