Increment value upto missing consicutive numbers - mysql

I have a table with a field have values 1,2,3,5,6,....
My problem is,When i try to insert "2" current 2,3 are incremented with 1 and 5,6 remains unchanged(because 4 is not exist),Then in the place of 2 new value needs to be inserted.
I try update query with
Update table set v1=v1+1 where v1>=newvalue
before insert a new value.But 5,6 also incremented with 1.I dont know how to do this.Does anyone know how to handle this ,Please help me.I have large amount of data,so not possible to make loop for update each value

SELECT t1.v1 + 1 AS gap
FROM `table` AS t1
LEFT OUTER JOIN `table` AS t2 ON t2.v1 = t1.v1 + 1
WHERE t2.v1 IS NULL AND t1.v1 >= :newvalue
ORDER BY t1.v1 ASC
LIMIT 1
This query gives the upper bound for updating v1 when inserting :newvalue.

Related

MySQL: Conditional Trigger

Is it possible to create a trigger that conditionally updates a column with a random value from another tables column.
Previously I received help to create a trigger that updates a column with a random value from another tables column: MySQL: Trigger Update with random value from another tables column. I’m trying now to make it conditionally based on another columns value.
If the users.selection column = ‘fruits’ then random select from fruits.
If the users.selection column = ‘animals’ then random from animals.
If neither ‘fruits’ nor ‘animals’ don’t update.
Here is a db-fiddle: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=6bc76ed2c104dad0e27dd35b1da112a7
Major thanks to #Akina for getting me this far! Lots to learn.
Update (May 29th):
I still can’t figure it out. I thought maybe I would need a SELECT with IF statement first to return the selection column value but that didn’t seem to work. Basically I have tried a lot of different combinations using these examples below as templates. None of them seem to bring my closer.
Anyone have any ideas?
Examples:
SELECT T1.ID, IFNULL(T1.name, T2.name) AS name
FROM firsttable T1
LEFT JOIN secondtable T2
ON T1.T2_id = T2.id
SET final_price= CASE
WHEN currency=1 THEN 0.81*final_price
ELSE final_price
END
SET col = (
SELECT other_col
FROM other_table
WHERE other_table.table_id = table.id
);
SELECT book_name,isbn_no,
IF((SELECT COUNT(*) FROM book_mast WHERE pub_lang='English')>
(SELECT COUNT(*) FROM book_mast WHERE pub_lang<>'English'),
(CONCAT("Pages: ",no_page)),(CONCAT("Price: ",book_price)))
AS "Page / Price"
FROM book_mast;
I think you need to conditionally define what does what, if selection is fruit, then do something. else if selection is animals, then do another thing.
e.g:
CREATE TRIGGER trigger_test
BEFORE UPDATE
ON users
FOR EACH ROW
BEGIN
IF (NEW.selection = 'fruits') THEN
SET NEW.random = ( SELECT fruits
FROM list
ORDER BY RAND() LIMIT 1 );
ELSEIF (NEW.selection = 'animals') THEN
SET NEW.random = ( SELECT animals
FROM list
ORDER BY RAND() LIMIT 1 );
END IF;
END;

Select last two values from two IDs

I would like to select two specific values, the first value is the last inserted row where the ID_SENSOR is 1, and the second value is the last inserted row where the ID_SENSOR is 2.
My Database table:
My Query:
SELECT DATA FROM (SELECT * FROM registovalores WHERE ID_SENSOR = '1' OR ID_SENSOR = '2' ORDER BY ID_SENSOR DESC LIMIT 2) as r ORDER BY TIMESTAMP
My Query is printing the last value just from the ID_SENSOR 1, which it means that I'm only getting the last inserted values, and not the last inserted value from both IDS.
I would like to print my values like this:
ID_SENSOR 1 = 90
ID SENSOR 2 = 800
What do I need to change on my Query?
Thank you.
One method uses a correlated subquery:
SELECT rv.*
FROM registovalores rv
WHERE rv.ID_SENSOR IN (1, 2) AND
rv.TIMESTAMP = (SELECT MAX(rv2.TIMESTAMP)
FROM registovalores rv2
WHERE rv.ID_SENSOR = rv2.ID_SENSOR
);
You have to have two separate queries, one per sensor.
select id_sensor, data
from the_table
where id_sensor = 'sensor_1'
order by timestamp desc -- the latest value is the first to come
limit 1; -- only pick the top (latest) row.
If you want to query for more than one value in a single database roundtrip, consider using union all between several such queries.
Please note that such a query may return one row or zero rows, since data for a particular sensor may not be available yet.

MAX(count) + 1 when inserting, MySQL

I currently use the below query to increment the third column count on every insert.
$DB2->query("INSERT INTO relations (item_ID,tag_ID,count)
SELECT '$ID', '$tag_id', MAX(count) + 1
FROM relations
WHERE tag_ID = '$tag_id';");
The problem is when there is no rows in the table and i try to insert, the Max(count) + 1 is just null. I've tried defining the default value as zero but still null. The column should be 1 on first insert.
How do i change the query, so if first insert then count is 1. I don't want to do a select query before because this code is in a loop.
add an ifnull(...,1)
"INSERT INTO relations (item_ID,tag_ID,count)
SELECT '$ID', '$tag_id', ifnull(MAX(count) + 1,1)
FROM relations
WHERE tag_ID = ''$tag_id';");

Calculated value in another column

I have a table that has 4 column that needs to be calculated to get the average value. I know how to get the average value.
What I don't know how to do is to get get that value to show on another column on another table. How do I do that?
Example:
Columns: ID Size1 Size2 Size3 Size4
Values: 1 92 82 63 83
I know how to get the average value from that, but I need to know how a column in another table can refer to that average value. I am using PHPMyAdmin
Has stated in the comments if you just need this as a query result a join will do.
Select t1.ID,t2.ID,(T1.Size1 + T1.Size2 + T1.Size3 + T1.Size4) / 4 as Avg
From t1 join t2 on t1.ID = t2.ID;
This assumes that T1 is table one (has sizes) and T2 is the second table in which you have the other values that you want to add average to.
Now lets assume you want an avg column in another table to be tied to rows in your T1 (sizes) table. To do this you can use a trigger.
CREATE TRIGGER AvgValues
ON T1
AFTER INSERT
AS
BEGIN
INSERT INTO T2(Avg)
SELECT (T1.Size1 + T1.Size2 + T1.Size3 + T1.Size4) / 4
FROM T1
WHERE T1.ID = T2.ID
END

Swap column value with the same column of another record

I have this fairly straightforward table with ID, Position, Name columns.
ID Position Name
1 1 RecordX
2 3 RecordY
3 2 RecordZ
The Position column serves as an index for displaying the records in a user defined order, it should be unique, can not be lower than 1 and not be higher than the number of records in the table, in this case 3. The column doesn't enforce uniqueness so temporarily there can be 2 records with the same Position, but eventually no two records should have the same position for the correct working of the program.
Currently, in order to swap the position of two records I need to do 3 queries, namely:
find the other record's ID
update the current record's Position to match the other record's Position
update the other record's Position by it's previously found ID (Since momentarily there will be two records with the same Position, updating by Position is not possible.
I feel there should be a way to do this with less rounds to the database, and thus with less than 3 queries. How should I approach this problem?
Single "swap" operation...
SWAP(#old_pos, #new_pos)
UPDATE
my_table
SET
position = CASE WHEN position = #old_pos THEN #new_pos ELSE #old_pos END
WHERE
position IN (#old_pos, #new_pos)
This doesn't easily expand to a table of swap-operations though. This is because it will try to do all the swaps at once, when in fact the swaps must happen in a specific order...
Also, if you want to do SWAP(#id, #new_pos) you need to either do a sub-query or self join on the table you are updating. MySQL doesn't like that, and although there are ways around the limitation, it makes things get a bit messy...
UPDATE
my_table
INNER JOIN
(SELECT position AS old_pos, #new_pos AS new_pos FROM (SELECT position FROM my_table WHERE id = #id)) AS params
ON my_table.position IN (params.old_pos, params.new_pos)
SET
myTable.position = CASE WHEN position = old_pos THEN new_pos ELSE old_pos END
(I think that will work)
NOTE:
Both of these assume that BOTH #old_pos and #new_pos, or #id and #new_pos are found, it doesn't check, and will make a mess if they don't exist.
This can be resolved by putting it in a transaction, and rolling back if ROW_COUNT() shows that only 1 record is updated.
SET #new_pos_for_id_1:=3, #new_pos_for_id_3:=1;
UPDATE my_table
JOIN (
SELECT 1 as id, #new_pos_for_id_1 as new_position
UNION ALL
SELECT 3 as id, #new_pos_for_id_3 as new_position) as positions
USING (id)
SET position = new_position
This query can be used to change positions for several rows at a time. I like the #Dems' solution as well.
UPD:
Explanation
SELECT 1 as id, 3 as new_position
UNION ALL
SELECT 3 as id, 1 as new_position
is a on-fly constructed table of two columns: id, new_position where each id is mapped to some new intended position. THen I just JOIN the table with my_table on the common id field and substitute values in my_table with values from the constructed table.
This will probably work for any DBMS.
-- create some data
DROP TABLE ztable CASCADE;
CREATE TABLE ztable
( id integer NOT NULL PRIMARY KEY
, val INTEGER
);
INSERT INTO ztable(id,val) VALUES (1,1), (2,3), (3,2);
SELECT * FROM ztable;
UPDATE ztable t1
SET val=t2.val
FROM ztable t2
WHERE t1.id IN (2,3)
AND t2.id IN (2,3)
AND t1.id <> t2.id
;
SELECT * FROM ztable;
Results:
CREATE TABLE
INSERT 0 3
id | val
----+-----
1 | 1
2 | 3
3 | 2
(3 rows)
UPDATE 2
id | val
----+-----
1 | 1
2 | 2
3 | 3
(3 rows)