Reputation: 541
I am trying to construct a query to UPDATE
a row if it exists else update a different row. I only wish to update one row each time the query is executed. The second WHERE
is for the case when there is no return from the first part of the query.
I wish to update a single attribute that has a default value of 'null'
. There isn't a means to use a public key as I've seen in other posts (e.g.).
I can return the desired tuple with a UNION
but am then unable to convert the expression to an UPDATE
query, as desired:
(SELECT * FROM table
WHERE (foo BETWEEN x-c AND x+c) AND (bar ..) AND column='null' LIMIT 1)
UNION
(SELECT * FROM table
WHERE column='null' LIMIT 1)
LIMIT 1;
This seems to always return the first WHERE
if exists else the second WHERE
.
I've been receiving syntax errors when trying to design an IF-ELSE based on a count variable:
SET @count=(SELECT COUNT(*) FROM table
WHERE (foo BETWEEN x-c AND x+c) AND (bar ..) AND column='null' LIMIT 1);
IF @count THEN
(UPDATE table SET column='foobar'
WHERE (foo BETWEEN x-c AND x+c) AND (bar ..) AND column='null' LIMIT 1);
ELSE
(UPDATE table SET column='foobar'
WHERE column='null' LIMIT 1);
END IF;
I've also tried to structure a subquery but had no luck in getting the desired behaviour.
I am concerned that using a count could lead to an opportunity for race conditions? I am unsure whether there is a better approach, however.
Any help is much appreciated!
Upvotes: 1
Views: 860
Reputation: 1269753
If I understand correctly, you can just use order by
and limit
:
update table
set . . .
where column = 'null'
order by ((foo) AND (bar)) desc
limit 1;
The desc
will put the rows that match the two conditions first. It will then be followed by other rows. The limit
chooses the first match.
I think I would be more inclined to order the two conditions separately:
order by (foo) desc, (bar) desc
Upvotes: 2
Reputation: 562310
Here's one way to do it. Run the first UPDATE. After this runs, the function ROW_COUNT()
will return either 0 or 1, depending on whether the first UPDATE affected any rows.
In the second UPDATE, make the change a no-op by setting column=column if ROW_COUNT()
indicates that the first UPDATE did change something.
UPDATE table SET column='foobar' WHERE (foo) AND (bar) AND column='null' LIMIT 1;
UPDATE table SET column=IF(ROW_COUNT()=1,column,'foobar') WHERE column='null' LIMIT 1;
However, note that ROW_COUNT() returns 0 if the first UPDATE matched rows, but didn't make any net change, because the rows it found already had the value 'foobar'.
Upvotes: 0
Reputation: 17915
Something like this? I can't promise it's fast:
update <table>
where
column is null and <foo> and <bar>
or not (<foo> and <bar>) and not exists (
select 1 from <table> where column is null and <foo> and <bar>
);
Upvotes: 0