MySQL Update a column value with the rowid of the group - mysql

I have a table of images, which are associated with a particular group (vehID) and I need to create their order for each group.
This is for an initial image entries position for a field I forgot to design in.
I have been playing with #row, but not getting very far.
set #row= 0;
select #row:=#row+1 as row, vehID,imgID from images group by vehID;
This gives me the rowID but does not reset for each group
Each vehID has 1 to n entries and I wish to calculate that value and update that rows' entry with the calculated value.
I can not work out how to reset #row to 0 on a change of vehID. Probably some sub-select.
If I can get Select to work any advice on how code the UPDATE if not obvious would be appreciated
Update images set imgPosition = Calculated Value where imgID = current imgID

you just need to declare another variable that holds the previous vehID. then using an IF statement you can compare the vehID with the previous one and set the row number accordingly. and then you set the previous vehID variable to be the vehID of the current row.
please note that I changed "group by" to "order by". this is for two reasons:
1- to list all rows
2- to make sure that rows from same id are following each other. otherwise comparing with previous value will not be correct.
and last, make sure you compare the previous vehID value and decide what the rownum is before you reset the previous variable to hold the value of the current line.
set #previous_vehID= 0;
set #row= 0;
select if(#previous_vehID=vehID, #row:=#row+1, #row:=1) as row,#previous_vehID:=vehID, vehID,imgID from images order by vehID
EDIT:
I just missed the update part. you can try cross table update for that:
set #previous_vehID= 0;
set #row= 0;
update images a, (
select if(#previous_vehID=vehID, #row:=#row+1, #row:=1) as row,#previous_vehID:=vehID, vehID,imgID from images order by vehID ) aa
set a.imgPosition = aa.row where a.vehID=aa.vehID and a.imgID=aa.imgID
the above makes the select and the update in a single statement/query. if not working, insert the results into a temporary table and use them to make an update in a separate statement.

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;

MySQL correct statement for "update all rows where column > number"?

I have a table called 'images' with a few rows of image names and a value for their position (order which they will appear on site).
id name position
1 dog.png 3
2 cat.png 1
3 snake.png 2
What im trying to do is decrement all position column values if they are above a specific value.
For example, if 'cat' is to be deleted, i want to find all rows with a position higher (would be snake and dog) and decrement their position values by 1. I need an SQL statement for
"update all 'position' columns where 'position' > 'value'"
I know i need to get the 'position' of the image to be deleted, and set this to 'value' before updating the rest of the rows with higher position columns. But, I'm not sure how to create the SQL statement for the rest of:
"update all 'position' columns where 'position' > 'value'"
I'm not sure whether i would need one or two queries for it.
You can use the following simple UPDATE:
UPDATE images SET position = position - 1 WHERE position > 1
You can also use the following to UPDATE the images and DELETE the specific image:
-- first update the other images
UPDATE images t1, (SELECT * FROM images WHERE id = 2) t2 SET t1.position = t1.position - 1 WHERE t1.position > t2.position
-- now you can delete the image
DELETE FROM images WHERE id = 2
demo on dbfiddle.uk
Inspired by Tim Biegeleisen's solution you can use the following UPDATE to close the gaps after deleting one or more images. In this case you have to use MySQL 8.0 or later (for ROW_NUMBER):
UPDATE images t1,
(SELECT id, ROW_NUMBER() OVER (ORDER BY position) rn FROM images) t2
SET t1.position = t2.rn
WHERE t1.id = t2.id
In this case you can also delete multiple images like this:
DELETE FROM images WHERE id IN (1, 2)
demo on dbfiddle.uk
I'm actually going to recommend against doing the update after deleting records. Instead, just use ROW_NUMBER to generate the effective position of each record, e.g.
SELECT
id,
name,
ROW_NUMBER() OVER (ORDER BY position) position
FROM yourTable;
Deleting rows will not change the relative order which exists between all records in the table.
If you are not using MySQL 8+, then you can easily enough simulate row number using user variables.
I would use a trigger :
DELIMITER //
CREATE TRIGGER position_after_delete
AFTER DELETE
ON images FOR EACH ROW
BEGIN
-- Update position
UPDATE images SET position = position - 1 WHERE position > OLD.position
END; //
DELIMITER ;

How do i make duplicates in a existing column unique?

I am using MySQL 5.6 Server. I use Navicat to work in the DB.
I have searched and found alot of possible solutions to my problem but none of them have worked for me.
I have a table with around 36000 rows. I have a column wich allowes duplicate entrys but i would like to make the duplicates in the row unique. Column with duplicates
I can find my duplicates using this query.
But there is to many to manually edit them all. Search Result
SELECT name, COUNT(ItemTemplate_ID)
FROM itemtemplate
GROUP BY ItemTemplate_ID
HAVING ( COUNT(ItemTemplate_ID) > 1 )
What i am looking for is a way to do one of these things.
Update the duplicates with new unique entries.
Add a text entry in another column for every duplicates. (I have a couple of empty columns i can use to add some text too.
Update the entire column with unique entries. ( Doesnt matter what its calle just has to be unique.)
Thanks in advance.
Edit - There allready is a unique column called Id_nb.
The column i want to change entries in should not be unique.
Let me assume that you do not have a unique column in the table. If so, you can do this with variables:
set #rn := 0;
set #it := '';
update itemtemplate it
set it.ItemTemplate_ID = (case when #it = it.ItemTemplate_ID
then concat_ws('_', it.name, (#rn := #rn + 1))
when #it := it.ItemTemplate_ID
then if(#rn := 0, it.ItemTemplate_ID, it.ItemTemplate_ID)
else if(#rn := 0, it.ItemTemplate_ID, it.ItemTemplate_ID)
end)
order by it.ItemTemplate_ID;
This method does assume that there are not already columns with names like "ABC" and "ABC_1".
Update the duplicates with new unique entries.
Let's assume that you have a unique column named id.
update itemtemplate set ItemTemplate_ID = (select md5(uuid())) where
FIND_IN_SET(id,(SELECT GROUP_CONCAT(id) FROM itemtemplate GROUP BY ItemTemplate_ID HAVING ( COUNT(ItemTemplate_ID) > 1 ) ));
Add a text entry in another column for every duplicates. (I have a couple of empty columns i can use to add some text too.
update itemtemplate set ItemTemplate_ID = (select md5(uuid())), emptyColumn='text' where
FIND_IN_SET(id,(SELECT GROUP_CONCAT(id) FROM itemtemplate GROUP BY ItemTemplate_ID HAVING ( COUNT(ItemTemplate_ID) > 1 ) ));
Sorry, I don't quite understand the third question.
By the way,if you have executed the first sql, the second sql will not work anymore.

MySQL limit work around

I need to limit records based on percentage but MYSQL does not allow that. I need 10 percent User Id of (count(User Id)/max(Total_Users_bynow)
My code is as follows:
select * from flavia.TableforThe_top_10percent_of_the_user where `User Id` in (select distinct(`User Id`) from flavia.TableforThe_top_10percent_of_the_user group by `User Id` having count(distinct(`User Id`)) <= round((count(`User Id`)/max(Total_Users_bynow))*0.1)*count(`User Id`));
Kindly help.
Consider splitting your problem in pieces. You can use user variables to get what you need. Quoting from this question's answers:
You don't have to solve every problem in a single query.
So... let's get this done. I'll not put your full query, but some examples:
-- Step 1. Get the total of the rows of your dataset
set #nrows = (select count(*) from (select ...) as a);
-- --------------------------------------^^^^^^^^^^
-- The full original query (or, if possible a simple version of it) goes here
-- Step 2. Calculate how many rows you want to retreive
-- You may use "round()", "ceiling()" or "floor()", whichever fits your needs
set #limrows = round(#nrows * 0.1);
-- Step 3. Run your query:
select ...
limit #limrows;
After checking, I found this post which says that my above approach won't work. There's, however, an alternative:
-- Step 1. Get the total of the rows of your dataset
set #nrows = (select count(*) from (select ...) as a);
-- --------------------------------------^^^^^^^^^^
-- The full original query (or, if possible a simple version of it) goes here
-- Step 2. Calculate how many rows you want to retreive
-- You may use "round()", "ceiling()" or "floor()", whichever fits your needs
set #limrows = round(#nrows * 0.1);
-- Step 3. (UPDATED) Run your query.
-- You'll need to add a "rownumber" column to make this work.
select *
from (select #rownum := #rownum+1 as rownumber
, ... -- The rest of your columns
from (select #rownum := 0) as init
, ... -- The rest of your FROM definition
order by ... -- Be sure to order your data
) as a
where rownumber <= #limrows
Hope this helps (I think it will work without a quirk this time)

max(x,y) in MySQL

For the following table (all columns are integers)
[id, value, best_value]
For a given id and value I want update it's row setting the best_value column to max(newvalue,best_value). I seached into the documentation but I dont see a function for doing so.
Thanks
You want GREATEST(x,y). Example, if the new value is 530:
UPDATE my_table SET best_value = GREATEST(530,best_value) WHERE id=123
You don't strictly need any such function,
UPDATE my_table SET best_value = new_value
WHERE id=123 AND best_value < new_value
would do the job about as well as AlienWebguy's answer :)