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;
Related
I am trying to get a minimum value from the Candidate table and insert that value in the MinTotal table. Can you do both in one SQL statement?
Here's my SQL Statement:
UPDATE MinTotal SET MinTotal.min_total= MIN(CandidateID.TotalVotes);
UPDATE MinTotal a
INNER JOIN (SELECT MIN(c.TotalVotes) min_vote, c.CandidateID FROM Candidate c
GROUP BY c.CandidateID) b ON b.CandidateID = a.CandidateID
SET a.min_total = b.min_vote;
Try the above. This is specific for each candidate, else you can use the other answers provided.
You have to use a select so you can properly set your MIN().
One way of doing that would be like that:
UPDATE MinTotal
SET
min_total = Cmin.minresult
FROM (
SELECT MIN(TotalVotes) as minresult
from CandidateID
) Cmin
In general, that would be one way to solve the Problem. In this case you would set the minresult for every row you have in your MinTotal table. If you dont want that, you may need to be more specific about your desired output and add some examples in your question
UPDATE MinTotal
SET MinTotal.min_total = (
SELECT MIN(TotalVotes)
FROM CandidateID
);
Below is my sample data. Row 3 and 4 have the same st_case (the primary key), but their dist_min are different. I want to keep the row with the minimum dist_min value. And please notice that there could be more than 2 duplicate rows associate with the same st_case. Thank you so much for the help!
In MySQL, you can do this with a delete and join:
delete s
from sample s left join
(select st_case, min(dist_min) as mindm
from sample s
group by st_case
) ss
on ss.st_case = s.st_case and s.dist_min > ss.mindm;
You can try this one:
DELETE t1 FROM table AS t1
LEFT JOIN table t2 ON t1.st_case = t2.st_case
WHERE t1.dist_min > t2.dist_min
As SAM M suggested, I am not sure how you can have duplicate rows with same primary key.
However in case st_case is not your only key and the table has a composite key
OR had it been a non-key column,
You could write a trigger to control the insertion
Something like:
CREATE table CALC_STATUS(id varchar(40), correlatoinToken integer, requirement double)
CREATE TRIGGER keep_min BEFORE INSERT ON CALC_STATUS
FOR EACH row
BEGIN
IF NEW.correlatoinToken = correlatoinToken AND NEW.requirement <= requirement then
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = "A row with similar correlation token with lower requirement already exists";
ELSEIF NEW.correlatoinToken = correlatoinToken AND NEW.requirement > requirement
NEW.requirement = requirement;
END IF;
END;
And if you meant to query:
SELECT c1.* FROM CALC_STATUS c1,(SELECT st_case,MIN(dist_min) FROM CALC_STATUS GROUP BY road_id) AS c2 WHERE c1.st_case=c2.st_case
DELETE FROM sample
WHERE dist_min !=(SELECT dist_min FROM (SELECT * FROM sample) sample2
WHERE sample2.st_case = sample.st_case
ORDER BY dist_min
LIMIT 1)
I didn't get to test this so please forgive any syntax errors. SQL ranking functions can solve your problem. Essentially you group by one column and then rank by another. Then you can select only those of rank one.
SELECT *
FROM(
SELECT *, Rank() OVER (PARTITION BY 'st_case' Order by Dist_min DESC) as Rank
From 'tbl_Name')
WHERE Rank = '1'
I have: something like
UPDATE table
SET field = (SELECT field FROM another_table WHERE id = #id);
Problem: SELECT field FROM another_table WHERE id = #id subquery can return one field or EMPTY SET.
Question: How to handle situation when subquery returns empty set?
Updated:
UPDATE table t
SET field = IF((SELECT field FROM another_table WHERE id = #id) IS NOT NULL, -- select field
(SELECT field FROM another_table WHERE id = #id), -- Problem #1: select field AGAIN!
(SELECT field FROM table WHERE id = t.id) -- Problem #2: try to not change value, so select the current field value!!
);
If function can be useful:
UPDATE table
SET field = if((SELECT field FROM another_table WHERE id = #id) IS NULL,true,false);
You can add the conditional:
WHERE (SELECT COUNT(*) FROM another_table WHERE id = #id) > 0
This will make sure that at least one row exists in another_table with the id. See my SQL Fiddle as an example.
Note: this may not be the most efficient because it does a count on another_table, and if it is greater than 1 it will do another SELECT (two sub-queries). Instead, you can do an INNER JOIN:
UPDATE table
INNER JOIN another_table ON table.id=another_table.id
SET table.field = another_table.field
WHERE another_table.id = #id;
See this SQL Fiddle. The reason why I saved this as a second option, is not all SQL languages can UPDATE with joins (MySQL can). Also, you need some way to relate the tables..in this case I said that the table.id we are updating is equal to another_table.id we are taking the data from.
NOTE The UPDATE statement will modify EVERY row in table and assign the same value to every row; that seems a little unusual.
To answer your question:
If you want to handle the "empty set" by not updating any rows in table, then one way to do this is with a JOIN to an inline view:
UPDATE table t
CROSS
JOIN (SELECT a.field
FROM another_table a
WHERE a.id = #id
LIMIT 1
) s
SET t.field = s.field
Note that if the inline view query (aliased as s) return an "empty set", then no rows in table will be updated, because the JOIN operation will also return an "empty set", meaning there are zero rows to be updated.
Modified some stuff from my pic so you guys can understand it
I have this database. I am trying to update a value from a table based on another value from an another table.
I want to update the SUM from salary like this :
( sum = presence * 5 )
This is what I've been trying to use ( unsuccessful )
update table salary
set suma.salary = users.presence * 5
FROM salary INNER JOIN users1 INNER JOIN presence on id_salary = id_presence
I am not sure what to do, I'd appreciate some help, Thanks
In MySQL to UPDATE tables with a join you use this syntax:
UPDATE table1, table2
SET table1.column = some expression
WHERE table1.column = table2.column
That said, even with the updated picture, in your SQL you are mentioning columns that I cannot understand in which table are to be found. You also have an inner join between salariu and users1, with no join condition. Could you please clean up the question and make everything clear?
Assuming you are making the updates to the db structure you were talking about, then you can start working on this one maybe:
UPDATE salary, presence
SET salary.sum = SUM(presence.hours) * 5
WHERE presence.id = salary.id
AND <some filter on the month that depends on salary.date>
Another way, but I'm not sure it is supported in all RDBMS, would be something like this:
UPDATE salary
SET sum = (
SELECT SUM(presence.hours) * 5
FROM user, presence
WHERE presence.id = salary.id
AND <some filter on the month that depends on salary.date>
)
I want to update multiple rows based on a SELECT sql query.
I want to do it ALL IN AN SQL SHELL!
Here is my select:
SELECT #myid := id, #mytitle := title
FROM event
WHERE pid>0 GROUP BY title
ORDER BY start;
Then, I want to do an update with this pseudocode:
foreach($mytitle as $t)
BEGIN
UPDATE event
SET pid=$myid
WHERE title=$t;
END
But I don't know how to ake a loop in SQL.
Maybe there's a way to make it in a single sql query?
I DON'T WANT ANY PHP!!! ONLY SQL SHELL CODE!!!
I want to update every rows with a pid with the id of the first occurence of an event. Start is a timestamp
I think this should do what you want, but if it doesn't (I'm not sure about joining a subquery in an UPDATE query) then you can use a temporary table instead.
UPDATE
event
JOIN (
SELECT
MIN(pid) AS minPID,
title
FROM
event
WHERE
pid > 0
GROUP BY
title
) AS findPIDsQuery ON event.title = findPIDsQuery.title
SET
event.pid = findPIDsQuery.minPID
Pure SQL doesn't really have "loops", per se: it's a set-based descriptive language. I believe the following update will do what you want (though your problem statements leaves much to be desired—we know nothing about the underlying schema).
update event t
set pid = ( select min(id)
from event x
where x.title = t.title
and x.pid > 0
group by x.title
having count(*) > 1
)
Cheers!