MySQL - Compare total this week against same week last year - mysql

How would I get a sum of sales totals for the current week against the same week last year?
There are two possible scenarios related to how the dates are stored, as below:
Scenario 1
**Sales**
Date Sales
-----------------------
2012-08-10 11040.00
2012-08-09 11500.00
2012-08-08 14060.00
2012-08-07 93000.00
2012-08-06 11200.00
...
2011-08-10 11040.00
2011-08-09 11500.00
2011-08-08 14060.00
2011-08-07 93000.00
2011-08-06 11200.00
Scenario 2
**Sales**
year month day Sales
---------------------------------------------
2012 08 10 11040.00
2012 08 09 11500.00
2012 08 08 14060.00
2012 08 07 23000.00
2012 08 06 11200.00
...
2011 08 10 13040.00
2011 08 09 11500.00
2011 08 08 12060.00
2011 08 07 33000.00
2011 08 06 11250.00

For your first scenario, join against the same table on the WEEKOFYEAR() and one added to last year's YEAR():
SELECT
YEARWEEK(thisyear.Date) AS `YearWeek`
SUM(lastyear.Sales) AS LastYearSales
SUM(thisyear.Sales) AS ThisYearSales
FROM
Sales thisyear
LEFT JOIN Sales lastyear ON
WEEKOFYEAR(thisyear.Date) = WEEKOFYEAR(lastyear.Date)
AND YEAR(thisyear.Date) = (YEAR(lastyear.Date) + 1)
GROUP BY `YearWeek`
The second scenario requires building a date out of the 3 separate values. I think this will work:
SELECT
YEARWEEK(CONCAT_WS('-', thisyear.year, thisyear.month, thisyear.day)) AS `YearWeek`,
SUM(lastyear.Sales) AS LastYearSales,
SUM(thisyear.Sales) AS ThisYearSales
FROM
Sales thisyear
LEFT JOIN Sales lastyear ON
WEEKOFYEAR(CONCAT_WS('-', thisyear.year, thisyear.month, thisyear.day)) = WEEKOFYEAR(CONCAT_WS('-', lastyear.year + 1, lastyear.month, lastyear.day))
GROUP BY `YearWeek`

Related

ORDER BY MONTH(1) after GROUP_CONCAT as names?

If I don't use GROUP_CONCAT() then there is no difficulty to the group and order the rows according to date-month-year
Following code:
SELECT FROM_UNIXTIME(orders.date_time,'%d %m %Y') AS date,
SUM(orders.net_amount) AS total_sales,
COUNT(FROM_UNIXTIME(orders.date_time,'%D %b %Y')) AS total_orders
FROM orders
JOIN users ON orders.user_id = users.id
WHERE FROM_UNIXTIME(orders.date_time,'%d %m %Y') != DATE_FORMAT(users.reg_date_time, '%d %m %Y')
GROUP BY date
ORDER BY Month(1)
O/P:
21 12 2019 1092 1 pinky
04 01 2020 1050 1 harshit
30 12 2019 21 1 robin
05 01 2020 987 2 chetan
31 12 2019 1239 2 rahul
30 11 2019 157.5 1 rahul
01 01 2020 651 1 rahul
15 12 2019 1575 1 isha
03 01 2020 598.5 1 manvi
SEE the names are not concating
But as soon as I add this line:
GROUP_CONCAT(users.firstname SEPARATOR '-')) AS names
like this:
SELECT FROM_UNIXTIME(orders.date_time,'%d %m %Y') AS date,
SUM(orders.net_amount) AS total_sales,
GROUP_CONCAT(users.firstname SEPARATOR '-') AS names,
COUNT(FROM_UNIXTIME(orders.date_time,'%D %b %Y')) AS total_orders
FROM orders
JOIN users ON orders.user_id = users.id
WHERE FROM_UNIXTIME(orders.date_time,'%d %m %Y') != DATE_FORMAT(users.reg_date_time, '%d %m %Y')
GROUP BY date
ORDER BY Month(1)
O/P:
01 01 2020 651 1 rahul
03 01 2020 598.5 1 manvi
04 01 2020 1050 1 harshit
05 01 2020 987 2 chetan-saurabh
15 12 2019 1575 1 isha
21 12 2019 1092 1 pinky
30 11 2019 157.5 1 rahul
30 12 2019 21 1 robin
31 12 2019 1239 2 rahul-manvi
then the order changed by day-order(without proper month and year order) but the grouping is correct.
Am I doing something wrong?
Use ORDER BY MONTH(orders.date_time). The problem is that your date column is not formatted as a valid MySQL date, so it's not extracting the month correctly.

How to add rows for missing combination of data and impute corresponding fields with 0

I have combination of domain and month with their total orders in corresponding month. I would like to impute missing combination with 0 values. What's the least expensive aggregation commands that can be used in Pyspark to achieve this ?
I have following input table:
domain month year total_orders
google.com 01 2017 20
yahoo.com 02 2017 30
google.com 03 2017 30
yahoo.com 03 2017 40
a.com 04 2017 50
a.com 05 2017 50
a.com 06 2017 50
Expected Output:
domain month year total_orders
google.com 01 2017 20
yahoo.com 02 2017 30
google.com 03 2017 30
yahoo.com 03 2017 40
a.com 04 2017 50
a.com 05 2017 50
a.com 06 2017 50
google.com 02 2017 0
google.com 04 2017 0
yahoo.com 04 2017 0
google.com 05 2017 0
yahoo.com 05 2017 0
google.com 06 2017 0
yahoo.com 06 2017 0
Here Expected order of output does not really matter.
The simplest method is to combine all months and years for each domain:
select my.year, my.month, d.domain, coalesce(t.total_orders, 0) as total_orders
from (select distinct month, year from input) my cross join
(select distinct domain from input) d left join
t
on t.month = my.month and t.year = my.year and t.domain = d.domain;
Note: This assumes that each year/month combination occurs at least once, somewhere in the data.
Getting values within a range is a pain because you have split the date into multiple columns. Let me assume the years are all the same, as in your example:
select my.year, my.month, d.domain, coalesce(t.total_orders, 0) as total_orders
from (select distinct month, year from input) my join
(select domain, min(month) as min_month, max(month) as max_month
from input
) d
on my.month >= d.min_month and my.month <= d.max_month left join
t
on t.month = my.month and t.year = my.year and t.domain = d.domain

SQL sum and show row with non-existent sum values

i have 2 tables : dt_user and dt_invoice.
**dt_members :**
id firstname
3 Salim
5 Sara
8 Julie
**dt_invoice**
user_id amount_ht period month year
3 4950 04 2018 04 2018
3 7200 10 2018 10 2018
8 11000 10 2018 10 2018
8 5500 11 2018 11 2018
3 6750 11 2018 11 2018
3 8700 12 2018 12 2018
3 8800 01 2019 01 2019
8 7500 01 2019 01 2019
3 4950 02 2019 02 2019
3 7550 03 2019 03 2019
I want to create a query joining the two table, but i want to show each user_id for PERIOD that there is in table dt_invoice.
**Expected results :**
user_id amount_ht period month year
3 4950 04 2018 04 2018
5 0 04 2018 04 2018 //non-existent record in dt_invoice
8 0 04 2018 04 2018 //non-existent record in dt_invoice
3 7200 10 2018 10 2018
5 0 10 2018 10 2018 //non-existent record in dt_invoice
8 11000 10 2018 10 2018
8 5500 11 2018 11 2018
5 0 11 2018 11 2018 //etc ...
3 6750 11 2018 11 2018
3 8700 12 2018 12 2018
5 0 12 2018 12 2018
8 0 12 2018 12 2018
3 8800 01 2019 01 2019
5 0 01 2019 01 2019
8 7500 01 2019 01 2019
3 4950 02 2019 02 2019
5 0 02 2019 02 2018
8 0 02 2019 02 2018
3 7550 03 2019 03 2019
5 0 03 2019 03 2018
8 0 03 2019 03 2018
Thanks in advance for your help, i'm totally stuck ..
SQL datas available here : https://rextester.com/live/LBSEY76360
also in sqlfiddle : http://sqlfiddle.com/#!9/728af3/1
Use a cross join to generate the rows and left join to bring in the values:
select m.user_id, p.period, p.month, p.year,
coalesce(t.amount_ht, 0) as amount_ht
from dt_members m cross join
(select distinct period, month, year from dt_invoice) p left join
dt_invoice t
on t.user_id = m.id and t.period = p.period;
Maybe this would help.
SELECT user_id, amount_ht, period, month, year
FROM dt_invoice
LEFT JOIN dt_members ON user_id = id

adding two column values in mysql

I have two mysql tables
suppose table one name 'marks'
no A B C D
1 10 05 01 04
2 08 07 10 05
3 09 05 07 10
4 07 05 04 10
5 04 07 06 09
6 05 09 07 07
7 09 05 10 06
8 09 06 06 08
9 08 06 10 07
10 08 07 04 06
suppose table two name 'results'
in second table I want to put total marks and average marks based on above table.(import data from 'marks' table,process it and save it in 'results' table)
So once it filled it must be like this.
I want add column A,B,C,D in 'marks' table and put total value in column 'Total' in table 'results' and average by dividing 'Total' column by 4.
no Total Average
1 20 5.00
2 30 7.50
3 31 7.75
4 26 6.50
5 26 6.50
6 28 7.00
7 30 7.50
8 29 7.25
9 31 7.75
10 25 6.25
So how can I fill the 'result' table using mysql query?
Is it possible to do in mysql?
Thank you
Try something like:
INSERT INTO result (no, total, average)
SELECT no, A+B+C+D, (A+B+C+D)/4
FROM marks

To display missing values [date] as range from Date Column

I have output as below
ID Date
Null 2012-10-01
1 2012-10-02
2 2012-10-03
NULL 2012-10-04
3 2012-10-05
NULL 2012-10-06
4 2012-10-07
NULL 2012-10-08
5 2012-10-10
NULL 2012-10-11
NULL 2012-10-12
6 2012-10-13
NULL 2012-10-16
As it has missing dates with value as NULL. I need to show final output as
2012-10-01 - 2012-10-01 (1 day )
2012-10-04 - 2012-10-04(1 day )
2012-10-06 - 2012-10-06(1 day )
2012-10-08 - 2012-10-08(1 day )
2012-10-11 - 2012-10-12(2 day )
2012-10-14 - 2012-10-14(1 day )
You can generate the date ranges using the following query:
select
min(date) as start,
max(date) as end,
datediff(max(date), min(date)) + 1 as numDays
from
(select #curRow := #curRow + 1 AS row_number, id, date
from Table1 join (SELECT #curRow := 0) r where ID is null) T
group by
datediff(date, '2012-10-01 00:00:00') - row_number;
The logic is based on a clever trick for grouping consecutive ranges. First, we filter and number the rows in the subquery. Then, the rows that are grouped together are found by comparing the number of days after 2012-10-01 to the row number. If any rows share this value, then they must be consecutive, otherwise there would be a "jump" between two rows and the expression datediff(date, '2012-10-01 00:00:00') - row_number would no longer match.
Sample output (DEMO):
START END NUMDAYS
October, 01 2012 00:00:00+0000 October, 01 2012 00:00:00+0000 1
October, 04 2012 00:00:00+0000 October, 04 2012 00:00:00+0000 1
October, 06 2012 00:00:00+0000 October, 06 2012 00:00:00+0000 1
October, 08 2012 00:00:00+0000 October, 08 2012 00:00:00+0000 1
October, 11 2012 00:00:00+0000 October, 12 2012 00:00:00+0000 2
October, 16 2012 00:00:00+0000 October, 16 2012 00:00:00+0000 1
From there I think it should be pretty trivial for you to get the exact output you are looking for.