how to update max row per group in SQL - mysql

I just added the 'default' column to my DB. I am trying to set the default value to '1' based on the latest 'addDate' per accountId.
+----+-----------+--------------------+--------+
| id | accountId | addDate | default|
+----+-----------+--------------------+--------+
| 1 | 45 |2012-02-29 08:41:59 | |
| 2 | 55 |2012-03-29 08:41:59 | |
| 3 | 45 |2012-04-29 08:41:59 | |
| 4 | 55 |2012-05-29 08:41:59 | |
| 5 | 60 |2012-05-29 08:41:59 | |
+----+-----------+--------------------+--------+
I found I was able to isolate the proper rows by using =>
select * from tble1
where addDate = (select max(addDate) from tble1 as sl where sl.accountId = tble1.accountId);
I need to be able to run an UPDATE that sets 'default' column to '1' only 1 time per 'accountId' basing it off of latest 'addDate'.

try this
UPdate Table1
SET `default` = 1
where addDate in (select * from (
select max(addDate) from table1 as sl group by accountId)t
)
DEMO HERE

UPDATE table1 x
LEFT
JOIN table1 y
ON y.accountid = x.accountid
AND y.adddate > x.adddate
SET x.default = 1
WHERE y.id IS NULL;
or (faster)
UPDATE table1 x
JOIN
( SELECT accountid
, MAX(addDate) max_adddate
FROM table1
GROUP
BY accountid
) y
ON y.accountId = x.accountId
AND y.max_adddate = x.adddate
SET x.default = 1;

Related

Fetching the rows from db table

Below is my db table.
RECORDNO| STAGE| COMMENT | STATE
12 | 1 | abcd | P
13 | 1 | adfg | P
14 | 2 | adsds | P
15 | 2 | defe | P
I want to fetch the records which has State'P' and stage = stage of minimum recordno ;
SELECT *
FROM history
WHERE STATE = 'P'
AND recordNO = ( SELECT MIN(record#)
FROM history
WHERE STATE = 'P' ) ;
The above query gives only the row with recordno 12. I want to fetch rows with recordno 12 and 13 .
Please help me with the query.
For MySql use this:
SELECT h.* FROM history h
WHERE h.STATE = 'P'
AND h.STAGE = (SELECT STAGE FROM history WHERE STATE = h.STATE ORDER BY RECORDNO LIMIT 1);
The subquery in the WHERE clause returns the stage of minimum recordno.
See the demo.
For Oracle 12c+ change LIMIT 1 with:
FETCH FIRST 1 ROWS ONLY
See the demo.
Results:
| RECORDNO | STAGE | COMMENT | STATE |
| -------- | ----- | ------- | ----- |
| 12 | 1 | abcd | P |
| 13 | 1 | adfg | P |
Oracle:
select * from history
where stage in
( select stage from history where recordno =
( select min(recordno) from history where state = 'P' )
);
Demo here
A subquery match for STAGE column with MINIMUM of STAGE
SELECT h1.*
FROM history h1
WHERE h1.STATE = 'P'
AND h1.STAGE = (SELECT MIN(STAGE) FROM history );
Or An Inline view through JOIN keyword
SELECT h1.*
FROM history h1
JOIN (SELECT MIN(STAGE) AS STAGE FROM history ) h2
ON h2.STAGE = h.STAGE
WHERE h1.STATE = 'P';
for both of the DBMS(MySQL&Oracle).

select data from two rows as single row sequentially

enter image description hereAs shown in the image below, we have 6 records for same vehicle_id (3 IN,3 OUT on different dates).
I need result as :
ID vehicle_id IN OUT
1 X first_record second_record
2 x third_record fourth_record
3 x fifth_record sixth_record
So,for one record one IN time and one OUT time.
Is it possible to get with select query or do I need to write a stored proc?
You could use sub queries with a limit clause for example
drop table if exists t;
create table t(id int auto_increment primary key, vid int, trip_status varchar(3),dt datetime);
insert into t (vid,trip_status,dt)
values
(1,'in','2018-12-01 01:00:00'),
(1,'out','2018-12-01 02:00:00'),
(1,'in','2018-12-01 03:00:00'),
(1,'out','2018-12-01 04:00:00'),
(1,'in','2018-12-01 05:00:00'),
(1,'in','2018-12-01 05:00:00');
select t.*
, (select case when t1.trip_status ='out' then trip_status
else concat(t1.trip_status, '**Error**')
end
from t t1 where t1.vid = t.vid and t1.id > t.id order by t1.id limit 1) nexttrip_status
, (select t1.dt from t t1 where t1.vid = t.vid and t1.id > t.id order by t1.id limit 1) next_dt
from t where trip_status = 'in';
+----+------+-------------+---------------------+-----------------+---------------------+
| id | vid | trip_status | dt | nexttrip_status | next_dt |
+----+------+-------------+---------------------+-----------------+---------------------+
| 1 | 1 | in | 2018-12-01 01:00:00 | out | 2018-12-01 02:00:00 |
| 3 | 1 | in | 2018-12-01 03:00:00 | out | 2018-12-01 04:00:00 |
| 5 | 1 | in | 2018-12-01 05:00:00 | in**Error** | 2018-12-01 05:00:00 |
| 6 | 1 | in | 2018-12-01 05:00:00 | NULL | NULL |
+----+------+-------------+---------------------+-----------------+---------------------+
4 rows in set (0.00 sec)
Click here This image show the sql records as per your questions
This is the output as you expect.
SQL = "Select x.id, x.vehicle_id, x.time as in_time, (Select y.time from xx.new_table as y where y.id =x.id+1) as outtime from xx.new_table as x where x.id % 2 = 1"
Please note "where x.id % 2 = 1" this condition you have to make it dynamic. Sometimes you have to set = 0 or = 1 based on your ID of the record. For that, you need to write addition select SQL to check it. Hope this will help you.
Click Here To See output screen shot

Update last row in group with data from first row in group

I'm currently in the process of converting data from one structure to another, and in the process I have to take a status id from the first entry in the group and apply it to the last entry in that same group. I am able to target and update the last item in the group just fine when using a hard-coded value, but I'm hitting a wall when trying to use the status_id from the first entry. Here is an example of the data structure.
-----------------------------------------------------------
| id | ticket_id | status_id | new_status_id | created_at |
-----------------------------------------------------------
| 1 | 10 | NULL | 3 | 2018-06-20 |
| 2 | 10 | 1 | 1 | 2018-06-22 |
| 3 | 10 | 1 | 1 | 2018-06-23 |
| 4 | 10 | 1 | 1 | 2018-06-26 |
-----------------------------------------------------------
So the idea would be to take the new_status_id of ID 1 and apply it to the same field for ID 4.
Here is the query that works when using a hard-coded value
UPDATE Communications_History as ch
JOIN
(
SELECT communication_id, MAX(created_at) max_time, new_status_id
FROM Communications_History
GROUP BY communication_id
) ch2
ON ch.communication_id = ch2.communication_id AND ch.created_at = ch2.max_time
SET ch.new_status_id = 3
But when I use the following query, I get Unknown column ch.communication_id in where clause
UPDATE Communications_History as ch
JOIN
(
SELECT communication_id, MAX(created_at) max_time, new_status_id
FROM Communications_History
GROUP BY communication_id
) ch2
ON ch.communication_id = ch2.communication_id AND ch.created_at = ch2.max_time
SET ch.new_status_id = (
SELECT nsi FROM
(
SELECT new_status_id FROM Communications_History WHERE communication_id = ch.communication_id AND status_id IS NULL
) as ch3
)
Thanks!
So I just figured it out using variables. It turns out the original "solution" only worked when there was one ticket's worth of history in the table, but when all the data was imported, it no longer worked. However, this tweak did seem to fix the issue.
UPDATE Communications_History as ch
JOIN
(
SELECT communication_id, MAX(created_at) max_time, new_status_id
FROM Communications_History
GROUP BY communication_id
) ch2
ON ch.communication_id = ch2.communication_id AND ch.created_at = ch2.max_time
SET ch.new_status_id = ch2.new_status_id;

Update value based on value from nearest smaller neigbour

I have a table with a column A that is INT(11) (it's a timestamp, but for now I just use small numbers)
id | A | diff |
---+----+------+
1 | 12 | |
2 | 7 | |
3 | 23 | |
4 | 9 | |
5 | 2 | |
6 | 30 | |
I like to update diff with the difference between A and it's nearest smaller neighbour. So if A=12 it's first smaller neightbour is A=7, if A=30 it is A=23. I should end up with a table like this (sorted on A):
id | A | diff |
---+----+------+
5 | 2 | - |
2 | 7 | 5 | (7-5)
4 | 9 | 2 | (9-7)
1 | 12 | 3 | (12-9)
3 | 23 | 11 | (23-12)
6 | 30 | 7 | (30-23)
I can calculate the difference at the moment of insertion, as I know A then (here: A=15):
INSERT INTO `table` (`A`,`diff`)
(SELECT 15 , 15-`A` FROM `table` WHERE `A` < 15 ORDER BY `A` DESC LIMIT 1)
This results in a new record:
id | A | diff |
---+----+------+
7 | 15 | 3 | (3 being the difference between A=12 and A=15
(NOTE: This fails miserably when A=1, being the new smallest value and having no smaller neighbour, so no value of diff)
But now the value of diff in record 3 is wrong, because it still is based on the difference between 23 - 12 as is now should be 23 - 15.
So I just want to insert the A value and then run an update on the table, refreshing diff where necessery. But that's where my knowledge of MYSQL ends...
I crafted this query, but it fails saying `You can't specify table 't1' for update in FROM clause
UPDATE `table` AS t1
SET
t1.`diff` = t1.`A` - (SELECT `A` FROM `table`
WHERE `A` < t1.`A`
ORDER BY `A` DESC LIMIT 1
)
Here's a query:
SELECT x.*
, x.a-MAX(y.a) diff
FROM my_table x
LEFT
JOIN my_table y
ON y.a < x.a
GROUP
BY x.id
ORDER
BY a;
I'm not sure why you would want to store derived data, but you can I guess...
UPDATE my_table m
JOIN
( SELECT x.*
, x.a-MAX(y.a) q
FROM my_table x
JOIN my_table y
ON y.a < x.a
GROUP
BY x.id
) n
ON n.id = m.id
SET m.diff = q;
You may try this after inserting new value :
UPDATE x
SET
x.diff = iq2.new_diff
FROM
#t x
INNER JOIN
(SELECt id,A,diff , new_diff
FROM
(select id,A,15 as new_number,
CASE WHEN (A-15) < 0 THEN NULL ELSE (A-15) END as new_diff,diff
from #t
) iq
WHERE
iq.new_diff <= iq.diff
AND iq.new_diff <> 0
)iq2
on x.A = iq2.A
inner query compares the previous difference and current one and then updates the relevant ones.

how to update a field in reverse order to other field in a MYSQL table

I have a table with fields like this
lev_1_id,lev_1_seq,lev_1_new_seq,lev_2_id,lev_2_seq,lev_2_new_seq
284e777e,1,null,b4dce5bb,1,null<br>
284e777e,1,null,dfd158ed,2,null<br>
284e777e,1,null,fedbf511,3,null<br>
0c7e0938,2,null,2333f431,1,null<br>
0c7e0938,2,null,808734fa,2,null<br>
0c7e0938,2,null,2504e0de,3,null<br>
And now I want to update the lev_1_new_seq and, lev_2_new_seq by reversing the values in lev_1_seq and lev_2_seq respectively.
After updating the fields, the table should look like this:
lev_1_id,lev_1_seq,lev_1_new_seq,lev_2_id,lev_2_seq,lev_2_new_seq
284e777e,1,2,b4dce5bb,1,3<br>
284e777e,1,2,dfd158ed,2,2<br>
284e777e,1,2,fedbf511,3,1<br>
0c7e0938,2,1,2333f431,1,3<br>
0c7e0938,2,1,808734fa,2,2<br>
0c7e0938,2,1,2504e0de,3,1<br>
can anyone help me with updating the fields?
Thanks in advance!
This solution works if initial ordering was done by id. 2 - the column you updating, 1 - column that needs to be in reverse order, tmp - table, id - unique key, initial sorting column.
BEGIN
DECLARE p INT;
DECLARE v INT;
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM `tmp` INTO n;
SET i=0;
WHILE i<n DO
select `1` from `tmp` order by `id` desc limit i,1 into p;
select `id` from `tmp` order by `id` limit i,1 into v;
update `tmp` set `2` = p where `id` = v;
SET i = i + 1;
END WHILE;
End
For your table: 1 = lev_1_seq, 2 = lev_1_new_seq, id = lev_1_id
It appears that you should be able to calculate the "new" sequences by deducting the exiting sequences from the relevant maximums + 1.
e.g. the max(lev_1_seq) + 1 = 3, so for an existing value of 2: 3-2 = 1, for an existing value of 1: 3-1 = 2
UPDATE table1 tu
JOIN (
SELECT
t1.lev_1_id
, m1.lev1maxseq
, MAX(t1.lev_2_seq) + 1 lev2maxseq
FROM table1 t1
CROSS JOIN (
SELECT
MAX(lev_1_seq) + 1 lev1maxseq
FROM table1
) m1
GROUP BY
t1.lev_1_id
, m1.lev1maxseq
) nv on tu.lev_1_id = nv.lev_1_id
SET
tu.lev_1_new_seq = (nv.lev1maxseq - tu.lev_1_seq)
, tu.lev_2_new_seq = (nv.lev2maxseq - tu.lev_2_seq)
;
see this sqlfiddle
results:
| lev_1_id | lev_1_seq | lev_1_new_seq | lev_2_id | lev_2_seq | lev_2_new_seq |
|----------|-----------|---------------|----------|-----------|---------------|
| 284e777e | 1 | 2 | b4dce5bb | 1 | 3 |
| 284e777e | 1 | 2 | dfd158ed | 2 | 2 |
| 284e777e | 1 | 2 | fedbf511 | 3 | 1 |
| 0c7e0938 | 2 | 1 | 2333f431 | 1 | 3 |
| 0c7e0938 | 2 | 1 | 808734fa | 2 | 2 |
| 0c7e0938 | 2 | 1 | 2504e0de | 3 | 1 |