Mysql query - month - mysql

I am a beginner in Mysql and I have a table like this:
create table purchase
(
purchase_ID INT primary key,
purchase_date DATE,
purchase_price INT
);
Insert into purchase values ('1', '2015-5-30', '10000');
Insert into purchase values ('2', '2016-7-30', '80000');
Insert into purchase values ('3', '2017-8-30', '50000');
Insert into purchase values ('4', '2016-10-30', '90000');
Now the question is: find which month has highest sales for the year 2016.
NOTE: consider purchase price as sales.
To find the answer for this, I tried this SQL statement:
SELECT
MAX(purchase_price) AS sales,
MONTH(purchase_date)
FROM
purchase
WHERE
CAST(purchase_date AS date) BETWEEN '2016-01-01' AND '2016-12-30'
and getting results as
sales month(purchase_date)
----------------------------
90000 7
but I am getting error in month because 10th month had highest sales not 7, can any one advise on this?

For using MAX, SUM, etc u need to do GROUP BY (aggregated query with GROUP BY)
SELECT MAX(purchase_price) as sales, MONTH(purchase_date) as month
from purchase where purchase_date between '2016-01-01' and '2016-12-30'
GROUP BY month
ORDER BY month desc
LIMIT 1
this query should work for you.

find which month has highest sales for the year 2016
SELECT *
FROM purchase
WHERE purchase_date BETWEEN '2016-01-01' AND '2016-12-30'
ORDER BY purchase_price DESC
LIMIT 1

Related

Combine two queries and add a new column

DB-Fiddle
CREATE TABLE sales (
id int auto_increment primary key,
category VARCHAR(255),
event_date DATE,
sent_date DATE,
sales_Product_gross VARCHAR(255),
return_Product_gross VARCHAR(255)
);
INSERT INTO sales
(category, event_date, sent_date,
sales_Product_gross, return_Product_gross
)
VALUES
("CAT_01", "2017-05-30", "2017-05-30", "500", NULL),
("CAT_01", "2017-06-05", "2017-05-30", NULL, "250"),
("CAT_01", "2018-07-08", "2018-07-08", "700", NULL),
("CAT_01", "2018-07-18", "2018-07-08", NULL, "370"),
("CAT_01", "2019-02-15", "2019-02-15", "400", NULL),
("CAT_01", "2019-03-21", "2019-02-15", NULL, "120"),
("CAT_02", "2019-04-24", "2019-04-24", "300", NULL),
("CAT_02", "2019-04-30", "2019-04-24", NULL, "145"),
("CAT_02", "2019-12-14", "2019-12-14", "900", NULL),
("CAT_02", "2019-12-28", "2019-12-14", NULL, "340"),
("CAT_03", "2020-03-09", "2020-03-09", "800", NULL),
("CAT_03", "2020-03-17", "2020-03-09", NULL, "425");
The table displays the sales and returns in different categories.
Now, I want to calculate:
a) the return_rate per month per campaign and store it in a new column called calc_type with the name monthly.
b) the return_rate on a rolling 2 YEAR basis and also store it in the new column calc_type with the name rolling.
The result should look like this:
category calc_type year month return_rate
CAT_01 rolling NULL NULL 0.445
CAT_01 monthly 2017 5 0.500
CAT_01 monthly 2018 7 0.528
CAT_01 monthly 2019 2 0.300
CAT_02 rolling NULL NULL 0.404
CAT_02 monthly 2019 4 0.480
CAT_02 monthly 2019 12 0.377
CAT_03 rolling NULL NULL 0.531
CAT_03 monthly 2020 3 0.531
I have created a query for criteria a) and for criteria b). Separately, those queries work exactly the way I need it.
Now, I tried to combine them using UNION ALL the same way it is done here:
SELECT
category,
'rolling' AS calc_type,
'NULL' AS year,
'NULL' As month,
sum(return_Product_gross) / sum(sales_Product_gross) as return_rate
FROM sales
WHERE sent_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 2 YEAR) AND CURDATE()
GROUP BY 1,2,3,4
ORDER BY 1,2,3,4;
UNION ALL
SELECT
category,
'monthly' AS calc_type,
YEAR(sent_date) AS year,
MONTH(sent_date) AS month,
sum(return_Product_gross) / sum(sales_Product_gross) as return_rate
FROM sales
WHERE sent_date BETWEEN "2017-01-01" AND CURDATE()
GROUP BY 1,2,3,4
ORDER BY 1,2,3,4;
However, now only the values for rolling are displayed in the result.
What do I need to change in my queries to get the expected result?
This query looks worked:
SELECT
category,
'rolling' AS calc_type,
'NULL' AS year,
'NULL' As month,
sum(return_Product_gross) / sum(sales_Product_gross) as return_rate
FROM sales
WHERE sent_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 2 YEAR) AND CURDATE()
GROUP BY category, year, month
UNION ALL
SELECT
category,
'monthly' AS calc_type,
YEAR(sent_date) AS year,
MONTH(sent_date) AS month,
sum(return_Product_gross) / sum(sales_Product_gross) as return_rate
FROM sales
WHERE sent_date BETWEEN "2017-01-01" AND CURDATE()
GROUP BY category, year, month
ORDER BY category, calc_type DESC, year, month;
DBFiddle

SQL: Group by for last 3 months and last 5 months respectively

Based on a table of the sales from different time periods, I am trying to calculate aggregated values from 2 different time periods: (1) Sales where date > '2018-11-26' and (2) sales where date > '2018-09-26'
create table revenue (sales float, date_time datetime)
insert into revenue (sales,date_time) values (300, '2018-09-01')
insert into revenue (sales,date_time) values (200, '2018-10-01')
insert into revenue (sales,date_time) values (300, '2018-11-01')
insert into revenue (sales,date_time) values (400, '2019-01-01')
insert into revenue (sales,date_time) values (500, '2019-02-01')
I've seen other solutions that uses case when for time periods, however the difference in this case is that the time periods are not mutually exclusive.
The query I want should work something like this:
select sum(sales) from revenue
group by date_time where date_time > '2018-11-26',
date_time where date_time > '2018-09-26'
you can use union all
select 'p1' as prd , sum(sales) from revenue
where date_time >= '2018-11-26'
union all
select 'p2', sum(sales) from revenue
where date_time > '2018-09-26'
or you can use case when
select case when date_time >= '2018-11-26' then 'p1'
when date_time > '2018-09-26'
then 'p2' end as period, sum(sales) from revenue
group by case when date_time >= '2018-11-26' then 'p1'
when date_time > '2018-09-26'
then 'p2' end

How to sum columns from two tables if the month match and group by month

Currently I achieved to do it with a single table with this query:
SELECT EXTRACT(MONTH FROM date) as month, SUM(total) as total FROM invoices GROUP BY month ORDER BY month ASC
But now I'm going crazy trying to return the same result from two columns, let's say total1 and total2, and group by month, if there is no invoice in a month in one of the columns the result should be cero.
Tables structure and expected result:
invoices payments
date date
total income
month totalInvoices totalPayments
1 10005 8017
2 756335 5019
3 541005 8017
4 34243 8870
How do I achieve this? Any suggestions?
You need a third element to the query structure which provides a complete list of all relevant years/months. This might be an existing table or a subquery, but the overall query will follow the structure outlined below:
CREATE TABLE invoices
(`id` int, `invdate` datetime, `invtotal` numeric);
INSERT INTO invoices
(`id`, `invdate`, `invtotal`)
VALUES
(1, '2017-01-21 00:00:00', 12.45);
CREATE TABLE payments
(`id` int, `paydate` datetime, `paytotal` numeric);
INSERT INTO payments
(`id`, `paydate`, `paytotal`)
VALUES
(1, '2017-02-21 00:00:00', 12.45);
select
ym.year, ym.month, inv.invtotal, pay.paytotal
from (
SELECT
EXTRACT(YEAR FROM invdate) as year
, EXTRACT(MONTH FROM invdate) as month
FROM invoices
UNION
SELECT
EXTRACT(YEAR FROM paydate) as year
, EXTRACT(MONTH FROM paydate) as month
FROM payments
) ym
left join (
SELECT
EXTRACT(YEAR FROM invdate) as year
, EXTRACT(MONTH FROM invdate) as month
, SUM(invtotal) as invtotal
FROM invoices
GROUP BY year, month
) inv on ym.year = inv.year and ym.month = inv.month
left join (
SELECT
EXTRACT(YEAR FROM paydate) as year
, EXTRACT(MONTH FROM paydate) as month
, SUM(paytotal) as paytotal
FROM payments
GROUP BY year, month
) pay on ym.year = pay.year and ym.month = pay.month;
year | month | invtotal | paytotal
-----|-------|----------|--------|
2017 | 1 | 12 | null |
2017 | 2 | null | 12 |
In my example the "third element" is the subquery ym but this may be too inefficient for your actual query, but it should server to identify how to co-ordinate data over disparate time ranges.
dbfiddle here

Name of customer with highest sale monthwise

I have a sales table from which I select the total sales per month , highest sale , number of sale for all the months in the current year, using
select monthname(date),sum(amt_c),MAX(amt_c)
from sales where year(date)= year(now())
group by monthname(date) ;
I want to also select the customer who has done the highest purchase , i.e the customer correponding to the MAX(amt_c).
amt_c is the purchase done by the customer,
One way is a filtering join:
select filter.mn
, filter.sum_sales
, filter.max_sales
, sales.cust
from (
select monthname(date) as mn
, sum(amt_c) as sum_sales
, max(amt_c) as max_sales
from sales
where year(date) = year(now())
group by
mn
) filter
join sales
on monthname(sales.date) = filter.mn
and sales.amt_c = filter.max_sales
For more approaches, browse the greatest-n-per-group tag.
select v.monthname,
v.sum_amt_c,
v.max_amt_c,
count(s.amt_c) as num_of_amounts,
group_concat(s.cust) as customers
from (select monthname(date) as monthname,
sum(amt_c) as sum_amt_c,
max(amt_c) as max_amt_c
from sales
where date between concat(year(now()), '-01-01') and concat(year(now()), '-12-31')
group by monthname(date)) v
join sales s
on v.max_amt_c = s.amt_c
and v.monthname = monthname(s.date)
and s.date between concat(year(now()), '-01-01') and concat(year(now()), '-12-31')
group by v.monthname, v.sum_amt_c, v.max_amt_c
order by month(s.date)
This is similar to Andomar's answer however it provides the following benefits:
If your DATE field is indexed (it should be) the above query will use that index. You should not have criteria on a date field with a function applied to it. MySQL does not support function based indexes, so it is a given that year(date) is not indexed. date may be indexed, however.
This sorts the results by month # (1-12) but shows the month name.
In the event that the same 2+ customers are tied, this will list all of them, and show only one row for that month. You would otherwise potentially have 2, 3, 4+ rows for a single month in the event of a tie. This is done via MySQL's GROUP_CONCAT function.

Combining multiple columns in 1 resultset

I have a table like
CREATE TABLE sales
(`id` int, `date` date, `amount` int(4))
;
insert into sales values (1, '2012-09-01', 200),
(2, '2012-09-01', 300),
(3, '2012-09-02', 400),
(4, '2012-09-02', 500),
(5, '2012-09-02', 600)
I wish to retrieve a row showing the sales for today, and the sales for yesterday
like
Date Today Total sales Yesterday Sales
2012-09-02 1500 500
Tried using something like
SELECT id, date, sum(amount) FROM sales
GROUP BY date;
But it returns the sales day wise. I understand that can be done programmatically, but is there a better way to directly retrieve it from the DB?
sqlfiddle
SELECT id, date(now()) as `date`,
SUM(IF(date(`date`) = date(now()), `amount`, 0)) as TodayTotalSales,
SUM(IF(date(`date`) < date(now()), `amount`, 0)) as OtherDaySales
FROM sales;
http://sqlfiddle.com/#!2/0ef6a/18
You are getting that because Id is different for each record. You have two option now:
Don't retrieve Id and write query like:
SELECT date, sum(amount) FROM sales
GROUP BY date;
Use a join with subquery
SELECT a.ID, a.date, b.amount
FROM sales a, (SELECT date, sum(amount) amount FROM sales
GROUP BY date) b
WHERE a.date = b.date;
Please Note: In option 2, second and third columns will be repeating with same value for each id within a day.
SELECT date, sum(amount), yestersales
FROM sales AS s1,
(SELECT sum(amount) as yestersales, ADDDATE(date, 1) AS yesterdate
FROM sales GROUP BY date) AS s2
WHERE s1.date = s2.yesterdate
GROUP BY date;
Will do what you want, but it's not really very efficient, I don't think. I would personally do it in code.
Selecting the ID doesn't really make much sense here since you're grouping by date.