Select highest revision from table for each row - mysql

I have a table setup like this
ID JOBID REPORTNAME REVISION PDFLOCATION
1 1 RPT1 1 /var/rpt1.pdf
1 2 RPT2 1 /var/rpt2.pdf
1 1 RPT1 2 /var/rpt3.pdf
How do I select all the rows but I want only the highest revision per jobid
and example result from the query should be
1 2 RPT2 1 /var/rpt2.pdf
1 1 RPT1 2 /var/rpt3.pdf

If I understand correctly, you want to select the record having the maximum revision number for each ID/JOBID group.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT ID, JOBID, MAX(REVISION) AS REVISION
FROM yourTable
GROUP BY ID, JOBID
) t2
ON t1.ID = t2.ID AND
t1.JOBID = t2.JOBID AND
t1.REVISION = t2.REVISION

Related

Updating table based on same table with a max value

Have a table data structure like below:
id
regid
docid
archived
1
1000
1
0
2
1000
2
0
3
1000
3
0
4
2000
1
0
5
2000
2
0
6
3000
1
0
7
3000
2
0
8
3000
3
0
9
3000
4
0
What I'm trying to do update the archived column to 1 where the docid is less than the max docid, by each regid group.
So I should end up with id's 3, 5 & 9 not being set to 1
Have tried:
update table t1
join (select max(docid) as maxdocid, regid from table) t2 on t1.docid < t2.maxdocid and t1.regid = t2.regid
set t1.archived = 1
But doesn't work, only does the first regid group.
Here's a solution (in MySQL 8.0+) using a CTE:
WITH numbered_table AS (
SELECT id, ROW_NUMBER() OVER (PARTITION BY regid ORDER BY docid DESC) AS rownum
FROM mytable
)
UPDATE mytable JOIN numbered_table USING (id)
SET archived = 1
WHERE rownum > 1
AND archived = 0;
Second solution, if you use an older version of MySQL that doesn't support CTE syntax:
You don't really need to compute the max docid value. If you want to update all rows except for the row with the max docid value, then you can check if a row can be matched to any other row with a greater docid value.
UPDATE mytable AS t1
INNER JOIN mytable AS t2 ON t1.regid = t2.regid AND t1.docid < t2.docid
SET t1.archived = 1
WHERE t1.archived = 0;
This will be true for all rows except the row with the max value. That row will be excluded automatically by the join.
In steps:
Create a query with the MAX value, per docid:
SELECT
ID,
regid,
docid,
(SELECT MAX(docid) FROM t1 te where te.regid=t.regid) as M
FROM t1 t
Join the result, and update:
UPDATE t1
JOIN (
SELECT
ID,
regid,
docid,
(SELECT MAX(docid) FROM t1 te where te.regid=t.regid) as M
FROM t1 t
) x ON t1.id=x.id
SET archived = 1
WHERE t1.docid<x.M AND t1.archived=0;
see: DBFIDDLE
You could try:
update test_tbl t1
set t1.archived = 1
where t1.archived = 0
and t1.id not in ( select t2.id
from (select max(id) as id,
regid,
max(docid)
from test_tbl
group by regid
) as t2
) ;
Result:
id regid docid archived
1 1000 1 1
2 1000 2 1
3 1000 3 0
4 2000 1 1
5 2000 2 0
6 3000 1 1
7 3000 2 1
8 3000 3 1
9 3000 4 0
Demo
Or you can use a LEFT JOIN
update test_tbl t1
left join ( select max(id) as id,
regid,
max(docid) as docid
from test_tbl
group by regid
) as t2 on t1.id=t2.id
set t1.archived = 1
where t1.archived = 0
and t2.id IS NULL
Demo
Use a self join in the update statement:
UPDATE tablename t1
INNER JOIN tablename t2
ON t2.regid = t1.regid AND t2.docid > t1.docid
SET t1.archived = 1;
See the demo.

MySQL - How to select first string in group by clause by date

Given this transactions table
ID Date Name Stat1
1 1 a 1
1 2 b 1
1 3 c 1
2 4 d 1
2 5 e 1
I want to group the records by ID, and have the column 'Name' per group ID to show the last name by date as it is appears in table (high number in date is chronologically last). final result:
ID Date Name Stat1
1 3 c 3
2 5 e 2
Unfortunately this code:
Select ID,Date,Name,sum(Stat1)
From myTable
Group by ID
will generate "random" name,
how do i force choose the first/last record name(by date) in each group (ID)?
Thanks
You can do it with a query like this.
Change min to max if you want to have the first or last row of a group:
SELECT
result.id,
result.mdate,
mt.name,
result.stat1
FROM (
Select
ID,
min(date) mdate,
sum(Stat1) as stat1
From myTable
Group by ID
) AS result
LEFT JOIN myTable mt
ON mt.id = result.id
AND mt.date = result.mdate;

Multiple Aggregate with different Group By

I have table User, Company, ParentCompany and table Goal.
Each Company have ParentCompany, and each User inside one Company. Goal have number of action, and type of Goal, user who execute the goal, and time executed.
I want to calculate the number of action in a date range for each type of Goal, for each user, company, and parent_company. Number of action for each company equal to sum of action for user that reside in that company.
More or less after some join query, I able to get this table below, where column id is id of company, parent_id is id of companyparent, and num is number of goal for all user inside of id company.
id parent_id num
----------- -------------------- -----------------------
1 3 1
2 1 2
3 1 1
4 2 4
Now I want to make it like below:
id parent_id sum_id sum_parent
----------- -------------------- -------------- -------------
1 3 1 1
2 1 2 3
3 1 1 3
4 2 4 4
How can I make it works? I can get one of the value (sum_id or sum_parent) with GROUP BY,
SELECT id,SUM(num) AS sum_id FROM tableA GROUP BY id
or
SELECT parent_id,SUM(num) AS sum_parent FROM tableA GROUP BY parent_id
but is there any way to make it only in one query? tableA results from query with 5 join inside.
Try this:
SELECT a.id, a.parent_id, a.sum_id, b.sum_parent
FROM (SELECT id, parent_id, SUM(num) sum_id FROM tableA a GROUP BY id) a
INNER JOIN (SELECT parent_id, SUM(num) sum_parent FROM tableA a GROUP BY parent_id) b ON a.parent_id = b.parent_id
Try this :
SELECT
t1.id, t1.parent_id, t1.sum_id, t2.sum_parent
FROM
(SELECT id, parent_id, SUM(num) AS sum_id FROM mytable GROUP BY id) t1
INNER JOIN
(SELECT parent_id, SUM(num) AS sum_parent FROM mytable GROUP BY parent_id) t2
ON t1.parent_id = t2.parent_id
Apparently what I want can be done with WITH ROLLUP statement. (http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html)
With
SELECT id,sum(num) FROM tableA GROUP BY parent_id, id WITH ROLLUP;
will results in
parent_id id sum(num)
----------- -------------------- --------------
1 2 2
1 3 1
1 null 3
2 4 4
2 null 4
3 1 2
3 null 2

Mysql left join fails to returns all values from first table

I've two tables named table1 and table2. table2 may have elements from table1. I'd like to show all the results from table2 with the price if available in table1 and with status 1. If no product matches in table1 and also status is 0, need to return price as 0.
table1
id pname item_code price status
1 product1 abcd 200 1
2 product2 pqrs 500 1
3 product3 wxyz 425 1
4 product5 mnop 100 0
and table2 as follows
id item_code
10 efgh
11 abcd
12 pqrs
13 mnop
I have tried following query
SELECT `t2`.`id`, `t2`.`item_code`, `t1`.`price`,`t1`.`pname`, COUNT(t2.item_code) AS sellers FROM (`table2` as t2) LEFT JOIN `table1` as t1 ON `t1`.`item_code` = `t2`.`item_code` WHERE `t1`.`status` = 1 GROUP BY `t2`.`item_code`
but it returns common values in table1 and table2 with status 1, but I need all records from table2 with price as 0 if nothing match in table1 or status 0 in table1.
Expected output
id item_code price
10 efgh 0
11 abcd 200
12 pqrs 500
13 mnop 0
Any help please.
Thanks,
Not sure about your current query which is having count and group by however you can do as below
select
t2.id,
t2.item_code,
case
when t1.status = 1 then t1.price
else 0
end as price
from table2 t2
left join table1 t1 on t1.item_code = t2.item_code
Now note that if table1 has multiple matching values from table2 in that case we may need grouping data.
Try below query:
SELECT `t2`.`id`, `t2`.`item_code`, `t1`.`price`,`t1`.`pname`, COUNT(t2.item_code) AS sellers FROM (`table2` as t2) LEFT JOIN (select * from table1 where status = 1)t1 ON `t1`.`item_code` = `t2`.`item_code` GROUP BY `t2`.`item_code`
Move the part of the WHERE clause that checks the left joined table to the ON clause
SELECT `t2`.`id`, `t2`.`item_code`, COALESCE(`t1`.`price`, 0),`t1`.`pname`, COUNT(t2.item_code) AS sellers
FROM (`table2` as t2)
LEFT JOIN `table1` as t1
ON `t1`.`item_code` = `t2`.`item_code`
AND`t1`.`status` = 1
GROUP BY `t2`.`item_code`

Mysql update max value with group by

I have a simple table that has many rows already:
id grade ...
1 1 ...
2 2 ...
3 2 ...
4 1 ...
5 1 ...
Now i want to add a column "relative_order", which is the order in that grade. So the table becomes:
id grade ... relative_order
1 1 ... 1
2 2 ... 1
3 2 ... 2
4 1 ... 2
5 1 ... 3
After i add the column, all the relative_order becomes 0 first. How can i fill the relative_order column using update syntax?
I tried using inner join, but failed:
UPDATE table AS i
INNER JOIN(
SELECT max(relative_order) as mOrder,grade
FROM table
GROUP BY grade
) AS j
ON i.grade = j.grade
SET i.relative_order = j.mOrder + 1
You could use this SELECT query that will return the relative_order that you need:
SELECT
t1.id,
t1.grade,
COUNT(t2.id) relative_order
FROM
yourtable t1 INNER JOIN yourtable t2
ON t1.grade=t2.grade AND t1.id>=t2.id
GROUP BY
t1.id,
t1.grade
or if you want to update the value, you can join your table with the previous query, like this:
UPDATE
yourtable INNER JOIN (
SELECT
t1.id,
t1.grade,
COUNT(t2.id) relative_order
FROM
yourtable t1 INNER JOIN yourtable t2
ON t1.grade=t2.grade AND t1.id>=t2.id
GROUP BY
t1.id,
t1.grade) seq
ON yourtable.id=seq.id AND yourtable.grade=seq.grade
SET
yourtable.relative_order = seq.relative_order
Please see fiddle here.