I have two tables and want to display the results for MAX of SUM total, group by name and month.
only display maximum data from the total SUM results every month and group by name.
this my table
table t2
+-------+-------+-------+
| month | total | id_t3 |
+-------+-------+-------+
| 1 | 15 | 1 |
| 1 | 20 | 2 |
| 1 | 50 | 1 |
| 2 | 40 | 2 |
| 2 | 20 | 3 |
| 2 | 20 | 1 |
| 3 | 10 | 3 |
+-------+-------+-------+
table t3
+----+--------+
| id | name |
+----+--------+
| 1 | brian |
| 2 | jessi |
| 3 | redy |
+----+---------
i want result
+-------+---------------+
| month | total | name |
+-------+---------------+
| 1 | 65 | brian |
| 2 | 40 | jessi |
| 3 | 10 | redy |
+-------+---------------+
And this my query SQL
select t2.month, MAX(total), t3.name
from (
select t2.month, SUM(t2.total)as total, t3.name
from t2, t3
where t2.idt3 = t3.id
group by t2.month, t3.name
)result
group by t2.month, t3.name
order by total DESC
Hope it will solve your problem. group by month and name
select t2.month, SUM(t2.total), t3.name
from t2
join t3 on t2.id_t3 = t3.id
group by t2.month, t3.name
order by t2.total desc
If you want the maximum name per month, use window functions:
select month, name, total
from (select t2.month, t3.name, sum(t2.total) as total
row_number() over (partition by t2.month order by sum(t2.total) desc) as seqnum
from t2 join
t3
on t2.id_t3 = t3.id
group by t2.month, t3.name
) t
where seqnum = 1
order by month;
Related
I have a table with this structure. For each SID there are different ITEMID
| sid | itemid |
|---| ---------|
| 1 | 20600 |
| 1 | 20598 |
| 1 | 20597 |
| 1 | 20596 |
| 1 | 20595 |
| 1 | 20594 |
...
...
| 2 | 19600 |
| 2 | 19598 |
| 2 | 19597 |
| 2 | 19596 |
| 2 | 19595 |
| 2 | 19594 |
...
...
What I need is to delete all but the last 2 rows with the ITEMIDs sorted in DESCENDING way.
This is the result I want to obtain:
| sid | itemid |
|---| ---------|
| 1 | 20600 |
| 1 | 20598 |
| 2 | 19600 |
| 2 | 19598 |
Thanks
Andrea
DELETE t0
FROM test t0
JOIN ( SELECT t1.sid,
( SELECT itemid
FROM test t2
WHERE t1.sid = t2.sid
ORDER BY itemid DESC LIMIT 1,1 ) itemid
FROM ( SELECT DISTINCT t3.sid
FROM test t3 ) t1 ) t4 USING (sid)
WHERE t0.itemid < t4.itemid;
https://dbfiddle.uk/?rdbms=mysql_5.5&fiddle=c6d67da817ddbb9fb890693564bcd49c
On MySQL 8+, we can try a delete join using ROW_NUMBER:
DELETE t1
FROM yourTable t1
INNER JOIN
(
SELECT sid, itemid,
ROW_NUMBER() OVER (PARTITION BY sid ORDER BY itemid DESC) rn
FROM yourTable
) t2
ON t2.sid = t1.sid AND t2.itemid = t1.itemid
WHERE
t2.rn > 2;
I have following tables:
t1 - Items
| Id | Item |
| 1 | I1 |
| 2 | I2 |
t2 - Item_elements
| Id | Item_id | Element | Our_quantity | Client_quantity |
| 1 | 1 | E11 | 100 | 0 |
| 2 | 1 | E12 | 20 | 300 |
| 3 | 2 | E21 | 300 | 100 |
| 4 | 2 | E22 | 5 | 300 |
t3 - Element_operations
| Id | Element_id | Operations_number |
| 1 | 1 | 100 |
| 2 | 1 | 50 |
| 3 | 2 | 50 |
| 4 | 2 | 50 |
| 5 | 3 | 50 |
| 6 | 3 | 50 |
| 7 | 3 | 50 |
| 8 | 3 | 50 |
| 9 | 4 | 10 |
I need SQL query which return table witch items (t1) AND element row associated with item table which has minimum operations number
Desired Output:
Table should look like
| Id|Item| Id_el |Our_quantity| Client_quantity | Count Operations_number|
| 1| I1 | 2 | 20 | 300 | 100 |
| 2| I2 | 4 | 5 | 300 | 10 |
result
I tried that query
SELECT t2.Id,Item_id,Our_Quantity,Client_Quantity,SUM(Operations_number)
FROM t2 LEFT JOIN t3 ON t2.Id=t3.Id_el GROUP BY t2.Id)
Tried Result:
| Id | Item_id | Our_quantity | Client_quantity |SUM(Operations_number)
| 1 | 1 | 100 | 0 | 150
| 2 | 1 | 20 | 300 | 100
| 3 | 2 | 300 | 100 | 200
| 4 | 2 | 5 | 300 | 10
What should I do next?
Now I have 2 table:
| Element Id | Item_id |Sum operations_number for element |
| 1 | 1 | 150 |
| 2 | 1 | 100 |
| 3 | 2 | 200 |
| 4 | 2 | 10 |
| Item Id | Item |
| 1 | I1 |
| 2 | I2 |
How can I join them to get this table?
Item Element who has minimal sum operations number.
| Item Id | Item | Element_Id | Sum operations_number for element |
| 1 | I1 | 2 | 100 |
| 2 | I2 | 4 | 10 |
You could get desired output using this..
SELECT
t.*,
MIN(t.opsum) AS `Count Operations_number`
FROM
(SELECT
a.*,
b.Id AS `Id_el`,
b.`Our_quantity`,
b.`Client_quantity`,
SUM(c.`Operations_number`) AS opsum
FROM
`t1` AS a
LEFT JOIN `t2` AS b
ON a.`Id` = b.`Item_id`
LEFT JOIN `t3` AS c
ON b.`Id` = c.`Element_id`
GROUP BY a.Id,
b.Id
ORDER BY a.`Id` ASC,
opsum ASC) AS t
GROUP BY t.Id ;
FIDDLE HERE
Maybe if you use the MIN() method in the desired column, as example:
SQL
SELECT t2.Id,Item_id, MIN(Our_Quantity), Client_Quantity, SUM(Operations_number)
FROM t2 LEFT JOIN t3
ON t2.Id=t3.Id_el
GROUP BY t2.Id
You may try this..
For mysql 8+
with cte as (
SELECT t1.id as Item_id, t1.item, t2.id as Ele_Id, t2.Element , t2.Our_quantity , t2.Client_quantity , t3.Operations_number
from Items as t1
inner join Item_elements as t2 on t1.id=t2.Item_id
inner join Item_elements as t3 on t2.id = t3.Element_id
)
, ct as (
select row_number() over ( partition by t1.id order by t2.Our_quantity ) as Slno, * from cte
)
select c.item_id, c.item, c.Ele_id, c.Element, c.our_quantity, c.client_quantity, t.Count_Operations_number
from ct as c
inner join
(
select distinct Element_id , sum(Operation_number) as Count_Operations_number
from Element_operations group by Element_id
) as t
on c.Ele_id=t.Element_id
where c.slno=1
Try the below query, hope this is what you are asking
select t1.Id as 'Id',t1.Item as 'Item',
t.Id as 'Id_el', t.Our_quantity as 'Our_quantity',t.Client_quantity as 'Client_quantity',
sum(t3.Operations_number) as 'Count Operations_number'
from t1 join (select *
from t2 where (Item_id,Our_quantity) in
( select Item_id, min(Our_quantity) from t2 group by Item_id)) t on t1.Id=t.Item_id
join t3 on t.Id=t3.Element_id
group by t1.Id;
Do you want it in the minimum order of SUM(Operations_number)?
Try this
I have updated the answer so this will get the first table also.
SELECT t1.id,
t1.item,
id_el,
our_quantity,
client_quantity,
sum
FROM t1
JOIN (SELECT t2.id AS Id_el,
t2.item_id,
t2.our_quantity AS our_quantity,
t2.client_quantity AS client_quantity,
sum
FROM t2
JOIN (SELECT t3.element_id,
Sum(operations_number) AS sum
FROM t3
GROUP BY element_id) AS b
ON t2.id = b.element_id) AS c
ON t1.id = c.item_id
ORDER BY sum ASC
Output would be:
Problem:
The Employee table holds the salary information in a year.
Write a SQL to get the cumulative sum of an employee's salary over a period of 3 months but exclude the most recent month.
The result should be displayed by 'Id' ascending, and then by 'Month' descending.
Employee table:
| Id | Month | Salary |
|----|-------|--------|
| 1 | 1 | 20 |
| 2 | 1 | 20 |
| 1 | 2 | 30 |
| 2 | 2 | 30 |
| 3 | 2 | 40 |
| 1 | 3 | 40 |
| 3 | 3 | 60 |
| 1 | 4 | 60 |
| 3 | 4 | 70 |
My Code:
SELECT t1.Id, t1.Month,
(SELECT SUM(Salary)
FROM Employee AS t2
WHERE t1.Id = t2.Id
AND t1.Month >= t2.Month) AS Salary
FROM Employee t1
WHERE Month <> (SELECT
MAX(Month)
FROM Employee
GROUP BY t1.Id)
ORDER BY Id, Month DESC;
My Output:
| Id | Month | Salary |
|----|-------|--------|
| 1 | 3 | 90 |
| 1 | 2 | 50 |
| 1 | 1 | 20 |
| 2 | 2 | 50 |
| 2 | 1 | 20 |
| 3 | 3 | 100 |
| 3 | 2 | 40 |
Expected:
| Id | Month | Salary |
|----|-------|--------|
| 1 | 3 | 90 |
| 1 | 2 | 50 |
| 1 | 1 | 20 |
| 2 | 1 | 20 |
| 3 | 3 | 100 |
| 3 | 2 | 40 |
I used MAX() and GROUP BY() functions to exclude the most recent month of each group, but it doesn't work for Id=2.
Is there any advice on how to get rid of the following row?
| 2 | 2 | 50 |
Thanks in advance.
To only get the cumulative sum for the last 3 months, excluding the most recent month per id, you can use
SELECT t1.Id, t1.Month, SUM(t2.Salary)
FROM Employee t1
JOIN Employee t2 ON t1.Id = t2.Id AND t1.Month - t2.Month <= 2 AND t1.Month - t2.Month >= 0
JOIN (SELECT id, MAX(month) as max_mth from Employee GROUP BY id) tmax on tmax.id=t1.id AND tmax.max_mth<>t1.month
GROUP BY t1.Id, t1.Month
ORDER BY t1.Id, t1.Month DESC;
Try this:
SELECT t1.id, t1.month,
(SELECT SUM(salary)
FROM employee t2
WHERE t1.id = t2.id
AND t1.month >= t2.month
AND t1.month - t2.month < 3) AS salary
FROM (
SELECT * FROM employee p
WHERE month <> (select MAX(month)
FROM employee c where c.id = p.id)) t1
ORDER BY id, month desc;
Output is:
+------+-------+--------+
| id | month | salary |
+------+-------+--------+
| 1 | 3 | 90 |
| 1 | 2 | 50 |
| 1 | 1 | 20 |
| 2 | 1 | 20 |
| 3 | 3 | 100 |
| 3 | 2 | 40 |
+------+-------+--------+
The problem you were having was that you were deleting only the last month present across all employees. What I believe you wanted was to delete the last month present for each employee even if that last month was several months back. This solution creates a derived table where the last month is missing for each employee and uses that in place of your t1 employee table.
I think this answer is closest to what you were trying to do in your original query:
SELECT t1.id, t1.month,
(SELECT SUM(salary)
FROM employee t2
WHERE t1.id = t2.id
AND t1.month >= t2.month
AND t1.month - t2.month < 3) AS salary
FROM employee t1
WHERE month <> (SELECT MAX(month)
FROM employee t3
WHERE t3.id = t1.id)
ORDER by id, month desc;
On second look you were actually pretty close. I believe the problem was that the "GROUP BY t1.Id" line doesn't actually group anything because t1.Id is constant for any given subquery as "t1" is defined in the outtermost select statement. Replace it with a where clause and limit the total to 3 months in the SUM() query, and you're there.
Try this query:
SELECT e.Id, e.Month, SUM( e2.Salary ) AS 'Salary'
FROM
Employee AS e
INNER JOIN Employee AS e2
ON e2.Id = e.Id
AND e2.Month <= e.Month
WHERE
e.Month <> ( SELECT MAX( [Month] ) FROM Employee WHERE Id = e.Id )
GROUP BY
e.Id, e.Month
ORDER BY
e.Id, e.Month DESC
Output is:
+----+-------+--------+
| Id | Month | Salary |
+----+-------+--------+
| 1 | 3 | 90 |
| 1 | 2 | 50 |
| 1 | 1 | 20 |
| 2 | 1 | 20 |
| 3 | 3 | 100 |
| 3 | 2 | 40 |
+----+-------+--------+
I have table that looks like this:
| id | user | data |
--------------------
| 1 | 11 | aaa1 |
| 2 | 11 | aaa2 |
| 3 | 11 | aaa3 |
| 4 | 22 | aaa4 |
| 5 | 33 | aaa5 |
| 6 | 33 | aaa6 |
| 7 | 44 | aaa7 |
I want to select all rows, with all data, and I want to add data with max id per user, that should look like this:
| id | user | data | f_id | f_data |
------------------------------------
| 1 | 11 | aaa1 | 3 | aaa3 |
| 2 | 11 | aaa2 | 3 | aaa3 |
| 3 | 11 | aaa3 | 3 | aaa3 |
| 4 | 22 | aaa4 | 4 | aaa4 |
| 5 | 33 | aaa5 | 6 | aaa6 |
| 6 | 33 | aaa6 | 6 | aaa6 |
| 7 | 44 | aaa7 | 7 | aaa7 |
this is my attempt of query:
SELECT t1.*, t2.id AS f_id, t2.data AS f_data
FROM table1 t1
LEFT JOIN table1 t2
ON t1.user=(SELECT MAX(t2.id)
FROM table1 t2
WHERE t2.user = t1.user )
Update:
All the answers are correct, but when I run the Query on table with 80K+ rows, MySQL needs a lot of time to Execute the query. For my project I will add ajax so user could click on it and php would execute query for one row per click.
SQL Fiddle Demo
SELECT t1.*,
t2.id AS f_id,
t2.data AS f_data
FROM table1 t1
JOIN table1 t2
ON t1.user = t2.user
AND t2.id = (SELECT MAX(t2.id)
FROM table1 t3
WHERE t3.user = t1.user)
You can approach this using your logic. Just a few things need to be fixed up:
SELECT t1.*, t2max.id AS f_id, t2max.data AS f_data
FROM table1 t1 JOIN
table1 t2max
ON t1.user = t2max.user AND
t2max.id = (SELECT MAX(t2.id)
FROM table1 t2
WHERE t2.user = t1.user
);
The changes are:
You need a condition between the two tables in the FROM clause, for the user.
The subquery needs to join on the id not on the user.
This will do it.
SELECT t1.*, t3.id AS f_id, concat(SUBSTRING(t1.data, 1, CHAR_LENGTH(t1.data)-1),t3.id) AS f_data
FROM table1 t1
INNER JOIN (select max(t2.id) as id, t2.user as userid from table1 t2 group by t2.user) t3
on t3.userid = t1.user
Sqlfiddle : http://sqlfiddle.com/#!9/a24413/7
I have two tables with some specific data:
users:
+----+------------+
| id | username |
+----+------------+
| 1 | rob |
| 2 | john |
| 3 | jane | <--- jane never has donated
+----+------------+
donations:
+--------------------+------------+
| uid | amount | date |
+---------+----------+------------+
| 1 | 20 | 2013-10-10 |
| 2 | 5 | 2013-10-03 |
| 2 | 50 | 2013-09-25 |
| 2 | 5 | 2013-10-01 |
+---------+----------+------------+
Result I want:
+---------+-------------+---------+-------------+
| id | username | amount | monthly | <- sum of donations this month
+---------+-------------+---------+-------------+
| 1 | rob | 20 | 1 |
| 2 | john | 60 | 3 |
| 3 | jane | 0 | 0 | <- jane added
+---------+-------------+-----------------------+
This is my query:
SELECT t1.*, sum(t2.amount) amount, count(*) as monthly
FROM users t1
inner join donations t2
on t2.uid = t1.id
group by t1.username
EDIT: forgot to add jane, he never has donated.
How I can do this?
Your output is wrong as you didn't filter out the september record in your results (only October 2013 should be taken into account).
Your expected output should be this:
| ID | USERNAME | AMOUNT | MONTHLY |
|----|----------|--------|---------|
| 1 | rob | 20 | 1 |
| 2 | john | 10 | 2 |
| 3 | jane | 0 | 0 |
The query to get the output is:
SELECT
u.id,
u.username,
COALESCE(sum(d.amount), 0) amount,
COUNT(d.uid) monthly
FROM users u
LEFT JOIN donations d
ON u.id = d.uid
AND (month(d.date), year(d.date)) = (month(CURDATE()), year(CURDATE()))
GROUP BY u.id
Assuming users.ID holds unique values you can leave the group by as u.id if it is not then you will have to group by u.id, u.username.
Fiddle here.
SELECT t1.*, sum(t2.amount) as amount, count(t2.amount,t2.`date`) as monthly
FROM users t1
inner join donations t2
on t2.uid = t1.id
where month(t2.`date`)=month(curdate()) and year(t2.`date`)=year(curdate())
group by t1.username
How about this use current date and extract the month and match with the month from column date
CURDATE() , MONTH()
SELECT t1.*, (CASE WHEN SUM(t2.amount) IS NULL THEN 0 ELSE SUM(t2.amount) END) amount,
count(*) as monthly
FROM users t1
left join donations t2
on t2.uid = t1.id
WHERE MONTH(t2.`date`)=MONTH(CURDATE()) AND YEAR(t2.`date`)=YEAR(CURDATE())
group by t1.id