MySQL - select max value with of sum over year - mysql

I have table like:
v | day | month | year
1 1 1 1950
2 2 1 1950
3 3 1 1950
1 1 2 1950
1 1 2 1951
2 1 2 1952
I have used this query to select MINs
SELECT SUM(v) AS sum_val, year, month
FROM `d`
GROUP BY year, month
This will result in
sum_val | year | month
6 1950 1
1 1950 2
1 1951 2
2 1952 2
How can I select max of sum_val with assigned year grouped by month?
I have tried
SELECT (MAX(f.sum_val)) AS max_sum, f.year, f.month
FROM (
SELECT SUM(v) AS sum_val, year, month
FROM `d`
GROUP BY year, month
) AS f
GROUP BY month
but this incorrectly assign year to value
max_sum | year | month
6 1950 1
2 1950 2 <--- should be 1952
SqlFiddle: http://sqlfiddle.com/#!9/ab23b4/6/0

You could use some subquery baset on sum_val in join
select t2.sum_val, t2.year, t2.month
from (
SELECT SUM(v) AS sum_val, year, month
FROM `d`
GROUP BY year, month
) t2
INNER JOIN (
select max(sum_val) max_val, year
from (
SELECT SUM(v) AS sum_val, year, month
FROM `d`
GROUP BY year, month
) t
group by year
) t3 on t3.max_val = t2.sum_val and t3.year = t2.year
NB in ths way if you have two rows that match max val the query return two rows

Related

get total amount of expenses per month in MySQL

I am currently working with 2 tables, expenses and income. To keep the structure simple and can see it, this is the fiddle: http://sqlfiddle.com/#!9/256cd64/2
The result I need from my query is the total amount for each month of the current year, for this and tried something like this:
select sum(e.amount) as expense, DATE_FORMAT(e.date,'%m') as month
from expenses e
where year(e.date) = 2019
group by month
My problem with this is that it only takes me the months where there was registration and I would like it to take 12 months whether or not they have a registration, in the case that they did not return 0 as a total amount.
At the moment I am working with the table of expenses but I would like to have a single query that returns the monthly expenses and income, this is an example of the final output that I would like to obtain:
| Month | Expense| Incomes |
|---------|--------|---------|
| 01| 0 | 0 |
| 02| 3000 | 4000 |
| 03| 1500 | 5430 |
| 04| 2430 | 2000 |
| 05| 2430 | 1000 |
| 06| 2430 | 1340 |
| 07| 0 | 5500 |
| 08| 2430 | 2000 |
| 09| 1230 | 2000 |
| 10| 8730 | 2000 |
| 11| 2430 | 2000 |
| 12| 6540 | 2000 |
You need to generate the month values and then use left join to match to expenses:
select coalesce(sum(e.amount), 0) as expense, m.month
from (select '01' as month union all
select '02' as month union all
select '03' as month union all
select '04' as month union all
select '05' as month union all
select '06' as month union all
select '07' as month union all
select '08' as month union all
select '09' as month union all
select '10' as month union all
select '11' as month union all
select '12' as month
) m left join
expenses e
on year(e.date) = 2019 and
DATE_FORMAT(e.date,'%m') = m.month
group by m.month;
Here is a db<>fiddle.
As for income, you should ask another question about that.
You can use MONTH to get month value from your date column and then GROUP BY them to get your desired output as below-
SELECT SUM(e.amount) AS expense,
MONTH(e.date) AS month
FROM expenses e
WHERE YEAR(e.date) = 2019
GROUP BY MONTH(e.date)
Try changing your sum(e.amount) as expense to: COALESCE(sum(e.amount),0) as expense
The COALESCE function returns the first non NULL value.
SELECT
t1.month,
COALESCE(t2.amount, 0) AS expenses,
COALESCE(t3.amount, 0) AS incomes
FROM
(
SELECT 1 AS month UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9 UNION ALL
SELECT 10 UNION ALL
SELECT 11 UNION ALL
SELECT 12
) t1
LEFT JOIN
(
SELECT MONTH(date) AS month, SUM(amount) AS amount
FROM expenses
GROUP BY MONTH(date)
) t2
ON t1.month = t2.month
LEFT JOIN
(
SELECT MONTH(date) AS month, SUM(amount) AS amount
FROM incomes
GROUP BY MONTH(date)
) t3
ON t1.month = t3.month
ORDER BY
t1.month;

mysql - How to query for items sold within 12 months of each other

I've got a table of sales transactions and I've been asked to report only on items that have two sales within a 12 month period. For example:
id | Item | Sale Date
---------------------
1 | A | 2017-02-03
2 | C | 2016-05-04
3 | A | 2016-08-23
4 | B | 2016-03-25
5 | D | 2015-07-30
6 | A | 2013-04-19
7 | E | 2011-03-12
8 | B | 2017-05-20
9 | E | 2011-05-04
Item A has three sales records, but only transactions 1 & 3 should be returned as transaction 6 is more than 12 months from transaction 3.
Item B has two sales, but greater than 12 months apart so should be excluded.
Item E has two sales within 12 months of each other so should be included.
I'm using this to find entries with multiple sales:
SELECT * FROM salesdata.sales
INNER JOIN
(SELECT Item_Code, COUNT(*) c from salesdata.sales
GROUP BY Item_Code HAVING c > 1) as vals
ON sales.Item_Code = vals.Item_Code;
But can't figure out how to test if the two sales for an item are within 12 months of each other.
SELECT DISTINCT x.*
FROM my_table x
JOIN my_table y
ON y.id <> x.id
AND y.item = x.item
AND DATEDIFF(GREATEST(y.sale_date,x.sale_date),LEAST(y.sale_date,x.sale_date)) < 365;
You can get a list of items that have had a sale within the previous 12 months:
select s.*
from salesdata.sales s
where exists (select 1
from salesdata s2
where s2.item_code = s.item_code and
s2.sale_date >= s.sale_date - interval 1 year and
s2.sale_date < s.sale_date
);
Your question is unclear what you want to do with this information, but this retrieves all items.
SELECT s.*
from salesdata.sales s
INNER JOIN (
SELECT COUNT(item), item
FROM salesdata.sales
WHERE Sale Date >= DATEADD(year, -1, GETDATE())
GROUP BY item
HAVING COUNT(item) > 1
) b
on s.item = b.item
and s.Sale Date >= DATEADD(year, -1, GETDATE())

Set default value if no result found

I have the following query
SELECT count(*) as count, Month(created_at) as month
FROM products
WHERE marketplace_id=21
and status='counterfeit'
and created_at < Now()
and created_at > DATE_ADD(Now(), INTERVAL - 5 MONTH)
group by month(created_at)
it return result as
+-------+-------+
| count | month |
+-------+-------+
| 410 | 1 |
| 174 | 2 |
| 301 | 3 |
| 329 | 4 |
| 141 | 12 |
+-------+-------+
in case a month does not have values it doesn't returns it at all, but I want the default value 0 to be set for that month.
I have tried this link Return a default value if no rows found
and
Returning a value if no result
I am not sure whether I am not able to implement it correctly or this is not what I want
Try this, seems to be a little stupid, but may help for you;)
SELECT SUM(count) AS count, month
FROM (
SELECT count(*) as count, Month(created_at) as month FROM products WHERE marketplace_id=21
and status='counterfeit' and created_at < Now() and created_at > DATE_ADD(Now(), INTERVAL - 5 MONTH)
group by month(created_at)
UNION
SELECT * FROM (
SELECT 0 AS count, 1 AS month
UNION SELECT 0 AS count, 2 AS month
UNION SELECT 0 AS count, 3 AS month
UNION SELECT 0 AS count, 4 AS month
UNION SELECT 0 AS count, 5 AS month
UNION SELECT 0 AS count, 6 AS month
UNION SELECT 0 AS count, 7 AS month
UNION SELECT 0 AS count, 8 AS month
UNION SELECT 0 AS count, 9 AS month
UNION SELECT 0 AS count, 10 AS month
UNION SELECT 0 AS count, 11 AS month
UNION SELECT 0 AS count, 12 AS month) M
WHERE M.month < Month(Now()) AND M.month > Month(DATE_ADD(Now(), INTERVAL - 5 MONTH)))
) tmp
GROUP BY mouth
ORDER BY month
You could create another table with default values
test_defaults
-----------------
| month | count |
and than just left join it with your table of values so if the value is found within the main table, it will be used, if not value from test_defaults would be used (we will use COALESCE function which returns first non null value):
SELECT t1.month, COALESCE(t2.count, t1.count)
FROM test_defaults t1
LEFT JOIN test_data t2 ON t1.month = t2.month
ORDER BY t1.month;
Here's a working SqlFiddle demo

Daily Report in a month from different tables

I have four Tables with four date coloumns respectively.
Table 1 ---------- Date 1
Table 2 ---------- Date 2
Table 3 ---------- Date 3
Table 4 ---------- Date 4
Now i want to get a day report in a month for all the four tables.if there is no data in any particular table for particular date it should dispaly NULL.How can i achieve it?
Structure:-
Table-1:-
ID Amount1 Date1
1 340 24/04/2013
2 200 04/04/2013
3 1000 15/04/2013
Table-2:-
ID Amount2 Date2
1 2000 22/04/2013
2 200 04/04/2013
3 1500 15/04/2013
Table-3:-
ID Amount3 Date3
1 3400 24/04/2013
2 200 19/04/2013
3 1800 15/04/2013
Table-4:-
ID Amount4 Date4
1 3200 24/04/2013
2 2200 04/04/2013
3 1000 18/04/2013
Now my result should be like
Date Amount1 Amount2 Amount3 Amount4
01/04/2013 Null Null Null Null
|
|
|
04/04/2013 200 200 null 2200
|
|
|
|
15/0402013 1000 1500 1800 null
|
|
|
|
|24/0402013 340 null 3400 3200
|
|
|
|
31/04/2013
Using a subquery to get a range of dates (I am assuming you want every day in April 2013) and then left joining that against the tables of data.
SELECT, dates.aDate, Table-1.Amount1, Table-2.Amount2, Table-3.Amount3, Table-4.Amount4
FROM
(
SELECT DATE_ADD('2013-04-01', INTERVAL (Units.i + Tens.i * 10) DAY) AS aDate
FROM
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) Units,
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) Tens
HAVING aDate <= '2013-04-30'
) dates
LEFT OUTER JOIN Table-1 ON Table-1.Date1 = dates.aDate
LEFT OUTER JOIN Table-2 ON Table-2.Date2 = dates.aDate
LEFT OUTER JOIN Table-3 ON Table-3.Date3 = dates.aDate
LEFT OUTER JOIN Table-4 ON Table-4.Date4 = dates.aDate
This assumes that there are not duplicate dates in any particular table.
You can try the following query
with dates as (
(select date from date1)union(select date from date2)union
(select date from date3)union (select date from date4) order by date asc)
select date,
(select amount from date1 where date=dt.date limit 1),
(select amount from date2 where date=dt.date limit 1),
(select amount from date3 where date=dt.date limit 1),
(select amount from date4 where date=dt.date limit 1)
from dates as dt;
You can add the date constraints on dates.
P.S.: Tested on PgSQL

Not getting the right expected output for my Mysql Query?

I've 4 tables as shown below
doctors
id name
------------
1 Mathew
2 Praveen
3 Rosie
4 Arjun
5 Denis
doctors_appointments
id doctors_id patient_name contact date status
--------------------------------------------------------------------------------------
1 5 Nidhin 9876543210 2012-12-10 15:39:41 Registered
2 5 Sunny 9876543210 2012-12-18 15:39:48 Registered
3 5 Mani 9876543210 2012-12-12 15:39:57 Registered
4 2 John 9876543210 2012-12-24 15:40:09 Registered
5 4 Raj 9876543210 2012-12-05 15:41:57 Registered
6 3 Samuel 9876543210 2012-12-14 15:41:33 Registered
7 2 Louis 9876543210 2012-12-24 15:40:23 Registered
8 1 Federick 9876543210 2012-12-28 15:41:05 Registered
9 2 Sam 9876543210 2012-12-12 15:40:38 Registered
10 4 Sita 9876543210 2012-12-12 15:41:00 Registered
doctors_dutyplan
id doctor_id weeks time no_of_patients
------------------------------------------------------------------
1 1 3,6,7 9:00am-1:00pm 10
2 2 3,4,5 1:00pm-4:00pm 7
3 3 3,6,7 10:00am-2:00pm 10
4 4 3,4,5,6 8:30am-12:30pm 12
5 5 3,4,5,6,7 9:00am-4:00pm 30
emp_leave
id empid leavedate
--------------------------------
1 2 2012-12-05 14:42:36
2 2 2012-12-03 14:42:59
3 3 2012-12-03 14:43:06
4 3 2012-12-06 14:43:14
5 5 2012-12-04 14:43:24
My task is to find all the days in a month in which the doctor is available excluding the leave dates.
My query what is wrote is given below:
SELECT DATE_ADD( '2012-12-01', INTERVAL
ROW DAY ) AS Date,
ROW +1 AS DayOfMonth
FROM (
SELECT #row := #row +1 AS
ROW FROM (
SELECT 0
UNION ALL SELECT 1
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
)t1, (
SELECT 0
UNION ALL SELECT 1
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
)t2, (
SELECT #row := -1
)t3
LIMIT 31
)b
WHERE DATE_ADD( '2012-12-01', INTERVAL
ROW DAY )
BETWEEN '2012-12-01'
AND '2012-12-31'
AND DAYOFWEEK( DATE_ADD( '2012-12-01', INTERVAL
ROW DAY ) ) =2
AND DATE_ADD( '2012-12-01', INTERVAL
ROW DAY ) NOT
IN (
SELECT DATE_FORMAT( l.leavedate, '%Y-%m-%d' ) AS date
FROM doctors_dutyplan d
LEFT JOIN emp_leave AS l ON d.doctor_id = l.empid
WHERE doctor_id =2
)
This works fine for all doctors who took any leave in a particular day in a month (here in the example it is Decemeber 2012). and the result for the above query is shown below:
Date DayOfMonth
-----------------------
2012-12-10 10
2012-12-17 17
2012-12-24 24
2012-12-31 31
But on the other hand for the doctors who didn't took any leave , for that my query is showing empty table, example for the doctor Mathew whose id is 1, my query returns an empty result
can anyone please tell a solution for this problem.
Thanks in advance.
Your query is large, but this part looks fishy:
NOT IN (
SELECT DATE_FORMAT( l.leavedate, '%Y-%m-%d' ) AS date
FROM doctors_dutyplan d
LEFT JOIN emp_leave AS l ON d.doctor_id = l.empid
WHERE doctor_id =2
The left join means a null would be returned for doctor 1. Now, col1 not in (null) does not behave as you may expect. It translates to:
col1 <> null
Which is never true. You could solve this by changing the left join to an inner join, so an empty set instead of null is returned for a doctor without leave.