MySQL query with a Max row value with multiple conditions - mysql

I have a table like this
gen_loc
rev_number
status
action
5A2
09
PROCESSED
INSERT
5A2
10
PROCESSED
INSERT
5A2
10
PROCESSED
DELETE
8A5
09
PROCESSED
INSERT
8A5
10
PROCESSED
UPDATE
10A6
09
PROCESSED
INSERT
10A6
10
PROCESSED
DELETE
I am trying to select the rows which contains the MAX value from rev_number column BUT ONLY IF THIS COLUMN ITS THE MAX VALUE WITH ACTION DIFFERENT TO DELETE AND EQUAL TO PROCESSED
As you can see, in the gen_loc 10A6 we have 10 as a max value but action delete so, I expect that the query doesn't show the gen_loc 10A6 for this case.
I have been trying other queries using MAX(rev_number) but it shows me still the gen_loc with 09 rev_number.
I expect this result:
gen_loc
rev_number
status
action
5A2
10
PROCESSED
INSERT
8A5
10
PROCESSED
UPDATE
How to select a Max value with the condition that the action IS NOT DELETE AND STATUS EQUAL TO PROCESSED?
Thank you!

Check out this db fiddle
If you don't want to group by any column, you can do in this way
SELECT tbl.*
FROM tbl
JOIN
(
SELECT max(rev_number) as t2_revNum
FROM tbl
) t2 ON tbl.rev_number=t2.t2_revNum
WHERE status = 'PROCESSED' AND action <> 'Delete'

Related

SQL join each row in a table with a one row from another table

The Problem
I have a table window with start and end timestamps. I have another table activity that has a timestamp. I would like to create a query that:
For each row in activity it joins with a single row from window, where the timestamp occurs between start and end, choosing the older window.
Window Table
Start
End
ISBN
0
10
"ABC"
5
15
"ABC"
20
30
"ABC"
25
35
"ABC"
Activity Table
Timestamp
ISBN
7.5
"ABC"
27.5
"ABC"
Desired Result
Start
End
ISBN
Timestamp
0
10
"ABC"
7.5
20
30
"ABC"
27.5
The Attempt
My attempt at solving this so far has ended with the following query:
SELECT
*
FROM
test.activity AS a
JOIN test.`window` AS w ON w.isbn = (
SELECT
w1.isbn
FROM
test.window as w1
WHERE a.`timestamp` BETWEEN w1.`start` AND w1.`end`
ORDER BY w1.`start`
LIMIT 1
)
The output of this query is 8 rows.
When there is guaranteed to be a single oldest window (i.e. no two Start times are the same for any ISBN)
with activity_window as (
select
a.`Timestamp`,
a.`ISBN`,
w.`Start`,
w.`End`,
row_number() over (partition by a.`ISBN`, a.`Timestamp` order by w.`Start`) rn
from
`Activity` a
inner join `Window` w on a.`ISBN` = w.`ISBN` and a.`Timestamp` between w.`Start` and w.`End`
)
select `Start`, `End`, `ISBN`, `Timestamp` from activity_window where rn = 1;
Result:
Start
End
ISBN
Timestamp
0
10
ABC
7.5
20
30
ABC
27.5
(see complete example at DB<>Fiddle)
CTEs are available from MySQL 8.0. Use subqueries when you are still on MySQL 5. Try to avoid table- and column names that are reserved words in SQL (things like Window, Start, End or Timestamp are examples for bad name choices).
Keeping an index over (ISBN, Start, End) on Window (or clustering the entire table that way by defining those three columns as the primary key) helps this query.

Update only the greatest row - Sequential Based Update

I want to write a query to find the LOWEST SEQUENCE for status = REQUEST_PENDING then update it after a certain condition.
For example:
person_name
status
sequence
a
request_progressed
1
b
request_pending
2
c
request_pending
3
If the person named A is done, it's status would change from "request_progressed" to "request_done"; then the next person B will have his status changed to "request_progressed" while the person C stays the same because its sequence is the 3rd.
So I just need to know how do I change the person B status by finding the lowest sequence which has "request_pending" status and THERE IS (SUPPOSED TO BE) ONLY ONE "request_progressed" on the table that is why when it is updated to "request_done" the next "request_pending" need to be updated to "request_progressed".
I tried the following:
update table
set status = 'request_progressed'
where status = 'pending' AND sequence = min(sequence)
In MySQL - you can specify order by and limit in update queries:
update t
set status = 'request_progressed'
where status = 'request_pending'
order by sequence
limit 1
In PostgreSQL - you still need order by and limit but they can only be used inside a subquery:
update t
set status = 'request_progressed'
where (status, sequence) in (
select status, sequence
from t
where status = 'request_pending'
order by sequence
offset 0 rows fetch first 1 row only
)

MySQL update values of unique column

I am trying to:
select values from a unique column that match some condition, for example, numbers that can be divided by 2
alter those numbers
write the result back in the table. If altered numbers duplicate with numbers that are already there, skip this row insertion
Create the table:
CREATE TABLE test (
id INT AUTO_INCREMENT PRIMARY KEY,
number INT NOT NULL UNIQUE
)
Populate:
INSERT test(number)
VALUES
(4), (5), (6), (9)
Do the trick:
UPDATE test
SET number = number - 1
WHERE MOD(number, 2) > 0
(this code fails with Duplicate entry '4' for key 'test.number')
I would like to end up with the following table:
id number
1 4
3 6
4 8
I want number 5 with id 2 to be changed to 4 (number = number-1), and then to be rejected because it duplicates number 4 with id 1
I have tried the following also:
INSERT INTO test
(id, number)
SELECT id, (number-1) AS number
FROM test
WHERE MOD(number, 2) > 0
ON DUPLICATE KEY UPDATE id = id
But this fails with "Column 'id' in field list is ambiguous"
Why do I want to do this? I have a table with a unique time series column, that is quite large. Values in that column are supposed to have one minute interval between them, for example:
19-Oct-2018 05:59:00
19-Oct-2018 06:00:00
19-Oct-2018 06:01:00
but some of them have non-zero seconds:
19-Oct-2018 05:59:00
19-Oct-2018 06:00:00
19-Oct-2018 06:00:20
19-Oct-2018 06:01:20
19-Oct-2018 06:02:20
19-Oct-2018 06:03:00
So I want to alter those by rounding up to the neighboring minute, but that leads to duplicates sometimes, and those duplicates should be discarded.
I have found some similar topics here, but was unable to figure out how to implement the answers to my case.
So, the answer, that was found in comments:
UPDATE IGNORE test
SET number = number-1
WHERE MOD(number, 2) > 0
request2:
DELETE FROM test
WHERE MOD(number, 2) > 0

Calculate running day difference in MySQL

I'd like tot calculate the difference in days from the current row, compared to the previous row. What I have now:
Here is my column is day difference
**Day_Diff**
351
363
363
But what I actually want:
**Day_Diff**
351
12
12
What query would I need to accomplish this?
This should do the work (if what you want is minimum in first row and then difference to the minimum, with table being the name of your table and day_diff the name of the column you named Day_diff):
See sqlfiddle :
SELECT
CASE WHEN t1.day_diff = t2.min_day_diff
THEN t1.day_diff
ELSE t1.day_diff - t2.min_day_diff
END
FROM mytable t1
LEFT JOIN (SELECT MIN(day_diff) AS min_day_diff FROM mytable) t2
ON True;

Get max value in MySQL?

I've following values in my database:
Column1
-----
10
20
30
05
12
21
10
40
As you can see, the value is increasing in the first three rows. It starts again in the fourth row with some value like 5. and then starts again in the 7th row with 10, for example. That is, it lowers and then increases again to some extent. The value starts with different numbers. I want to get the highest of each. i.e. I want to get rows with value 30,21, and 40.
Note that I've only the sorted list, It can be done with some variable in programming language but how to do this in mysql with some query?
I would insert all the values into another table which will have only 2 columns (id AUTOINCREMENT and Val as your values).
And then I would use this select:
SELECT
Val
FROM (
SELECT
T1.id, T1.Val, (Select Val from MyTable T2 where T2.id = T1.id + 1) NextVal
FROM
MyTable T1
)
WHERE
Val > NextVal