I'm trying to code a monopoly game and I'm getting a syntax error for the following:
SET #Token = 'Thimble';
SET #Roll = 7;
UPDATE Players
SET Players.Jail = FALSE, #Roll = #Roll - 6
WHERE Players.Jail = TRUE AND Players.Token = #Token AND #Roll > 5;
Is it not possible to set the value of a temp variable as part of UPDATE? I need #roll and Players.Jail to only update if the WHERE condition is met, so I can't see a way of updating them separately.
No, you can't SET #Roll in an UPDATE statement. You can only SET a column.
It's not a good practice to use tricks with temp variables like you are trying to do, because the order of evaluation of the variables is not well defined.
In this case, you should just do this:
UPDATE Players
SET Players.Jail = FALSE
WHERE Players.Jail = TRUE AND Players.Token = #Token
ORDER BY ...something...
LIMIT 1;
Using LIMIT doesn't make much sense without an ORDER BY, but I can't tell from your example which order you want to update the rows.
With updates you can't do this directly
You could solve this with help of a further , you update the valuen to #Roll and set so the new value
CREAte tablE Players (Jail INT , token varchar(10))
INSERT INTO Players VALUES (1,'Thimble')
CREATE TABLE Rolls(Roll int);
INSERT INTO Rolls VALUES(7)
SET #Token = 'Thimble';
SET #Roll = 7;
UPDATE Players,Rolls
SET Players.Jail = FALSE, Rolls.Roll = #Roll - 6
WHERE Players.Jail = TRUE AND Players.Token = #Token AND #Roll > 5
SET #Roll := (SELECT Roll FROM Rolls ORDER BY 1 LIMIT 1)
SELECT #Roll
| #Roll |
| ----: |
| 1 |
SELECT * FROM Players
Jail | token
---: | :------
0 | Thimble
db<>fiddle here
Related
Consider the following table.
myTable
+----+-----------+------------------------------------+
| Id | responseA | responseB |
+----+-----------+------------------------------------+
| 1 | | {"foo":"bar","lvl2":{"key":"val"}} |
+----+-----------+------------------------------------+
where:
Id, INT (11) PRIMARY
responseA, TEXT utf8_unicode_ci
responseB, TEXT utf8_unicode_ci
Let's say that I want to conditionally update the table with some outside data. The conditions are:
• if there's nothing in responseA, populate it with the outside data, otherwise
• if there is something in responseA, leave it as it is, and populate responseB with the outside data
I was pretty much convinced that I could just do this to get what I want:
UPDATE myTable
SET
responseA = IF(TRIM(responseA) = '','foo',TRIM(responseA)),
responseB = IF(TRIM(responseA) != '','foo',TRIM(responseB))
WHERE Id = 1
However, this updates both responseA and responseB to the same value - foo, making the table:
myTable
+----+-----------+-----------+
| Id | responseA | responseB |
+----+-----------+-----------+
| 1 | foo | foo |
+----+-----------+-----------+
I was expecting my table to look like this after the update:
myTable
+----+-----------+------------------------------------+
| Id | responseA | responseB |
+----+-----------+------------------------------------+
| 1 | foo | {"foo":"bar","lvl2":{"key":"val"}} |
+----+-----------+------------------------------------+
What am I misunderstanding, and how can I achieve this conditional update? Do the updates happen sequentially? If so, I guess that would explain why both of the fields are updated.
UPDATE TABLE
SET responseA = CASE WHEN responseA IS NULL
THEN #data
ELSE responseA
END,
responseB = CASE WHEN responseA IS NULL
THEN responseB
ELSE #data
END
;
here your changed query
UPDATE myTable
SET
responseB = IF(TRIM(responseA) != '','foo',TRIM(responseB)),
responseA = IF(TRIM(responseA) = '','foo',TRIM(responseA))
WHERE Id = 1
It seems the value of responseA is changed before the IF() for responseB is evaluated.
One possible solution is to do a simple UPDATE:
UPDATE mytable SET responseA = ? WHERE id = 1
Then adjust the columns in a trigger, where you have access to both the original and the new value of the columns:
CREATE TRIGGER t BEFORE UPDATE ON mytable
FOR EACH ROW BEGIN
IF TRIM(OLD.responseA) != '' THEN
SET NEW.responseB = NEW.responseA;
SET NEW.responseA = OLD.responseA;
END IF;
END
(I have not tested this.)
I am also assuming that your test for '' (empty string) instead of NULL is deliberate, and that you know that NULL is not the same as ''.
The key point in the UPDATE statement is that you should update first the column responseB, so that column responseA retains its original value which can be checked again when you try to update it:
UPDATE myTable
SET responseB = CASE WHEN TRIM(responseA) = '' THEN responseB ELSE 'foo' END,
responseA = CASE WHEN TRIM(responseA) = '' THEN 'foo' ELSE responseA END
WHERE Id = 1;
table
create table tst(locationId int,
scheduleCount tinyint(1) DEFAULT 0,
displayFlag tinyint(1) DEFAULT 0);
INSERT INTO tst(locationId,scheduleCount)
values(5,0),(2,0),(5,1),(5,2),(2,1),(2,2);
I update multiple rows and multiple columns with one query, but want to change the one of the columns only for the first row and keep the other things the same for that column.
I want to update all the rows with some location id and change displayFlag to 1 and increment scheduleCount of only the top entry with 1 , rest would remain the same
**Query **
update tst,(select #rownum:=0) r,
set tst.displayFlag =1,
scheduleCount = (CASE WHEN #rownum=0
then scheduleCount+1
ELSE scheduleCount
END),
#rownum:=1 where locationId = 5
But it gives error and does not set the user defined variable rownum, I am able to join the tables in a select and change the value of the rownum, is there any other way to update the values.
I'm not sure this is the correct way of doing such a thing, but it is possible to include the user variable logic in the CASE condition:
UPDATE tst
JOIN (SELECT #first_row := 1) r
SET tst.displayFlag = 1,
scheduleCount = CASE
WHEN #first_row = 1 AND ((#first_row := 0) OR TRUE) THEN scheduleCount+1
ELSE scheduleCount
END
WHERE locationId = 5;
I have used a #first_row flag as this is more inline with your initial attempt.
The CASE works as follows:
On the first row #first_row = 1 so the second part of the WHEN after AND is processed, setting #first_row := 0. Unfortunately for us, the assignment returns 0, hence the OR TRUE to ensure the condition as a whole is TRUE. Thus scheduleCount + 1 is used.
On the second row #first_row != 1 so the condition is FALSE, the second part of the WHEN after AND is not processed and the ELSE scheduleCount is used.
You can see it working in this SQL Fiddle. Note; I have had to set the column types to TINYINT(3) to get the correct results.
N.B. Without an ORDER BY there is no guarantee as to what the '1st' row will be; not even that it will be the 1st as returned by a SELECT * FROM tst.
UPDATE
Unfortunately one cannot add an ORDER BY if there is a join.. so you have a choice:
Initialise #first_row outside the query and remove the JOIN.
Otherwise you are probably better off rewriting the query to something similar to:
UPDATE tst
JOIN (
SELECT locationId,
scheduleCount,
displayFlag,
#row_number := #row_number + 1 AS row_number
FROM tst
JOIN (SELECT #row_number := 0) init
WHERE locationId = 5
ORDER BY scheduleCount DESC
) tst2
ON tst2.locationId = tst.locationId
AND tst2.scheduleCount = tst.scheduleCount
AND tst2.displayFlag = tst.displayFlag
SET tst.displayFlag = 1,
tst.scheduleCount = CASE
WHEN tst2.row_number = 1 THEN tst.scheduleCount+1
ELSE tst.scheduleCount
END;
Or write two queries:
UPDATE tst
SET displayFlag = 1
WHERE locationId = 5;
UPDATE tst
SET scheduleCount = scheduleCount + 1
WHERE locationId = 5
ORDER BY scheduleCount DESC
LIMIT 1;
Update myTable SET field = 1 (if field = 0 or if field is null) where myid = 12345;
Update myTable SET field = 0 (if field = 1) where myid = 12345;
What is the best way to transform this Pseudocode in proper SQL for Oracle and MySQL?
You could simply use the modulo like this:
UPDATE myTable SET field = (field + 1) % 2 WHERE myId = 12345;
Due to the lack of a real boolean in both DBMS you need a case statement:
update myTable
set the_column = case when the_column = 1 then 0 else 1 end
where myId = 12345;
This assumes that the column never has different values than 0 and 1
I am not sure if its possible or not, Just want to know if it is. I have column plan_popular which has default value 0. Lets same i have a list :
Plan Name | plan_popular | amount
===================================
plan A 0 25.00
plan B 1 50.00
plan C 0 90.00
This is how i am doing:
$stmt = "update {CI}plans set plan_popular = 0";
$this->db->query($stmt);
$stmt2 = "update {CI}plans set plan_popular = 1 where plan_id = ?";
$this->db->query( $stmt2, array($plan_id) );
Now i have set the plan C to make. Now i want to reset it and want to make popular plan C to 1. What i am doing is running two queries, One i reset and make the plan_popular 0 and the second is get the update the plan C to 1 with there id. Is it possible in single query?
You can use an expression to determine the value to assign:
UPDATE {CI}plans
SET plan_popular = IF(plan_id = ?, 1, 0);
try this,
UPDATE {CI}plans
SET `plan_popular` = CASE `Plan Name`
WHEN 'plan C' THEN 1
ELSE 0
END
WHERE `Plan Name` IN((select `Plan Name` from {CI}plans where plan_popular=1 ) , 'plan C');
Updates can be expensive, what with manipulating locks, triggers and constraints firing, etc. In general, you want to avoid updating a field to the same value it already has. In English, if plan_id = variable and plan_popular is 0 then set it to 1 but if plan_id is any other value and plan_popular is 1 then set it to 0.
UPDATE {CI}Plans
SET plan_popular = if( plan_id = ?, 1, 0 )
where (plan_id = ? and plan_popular = 0)
or (plan_id <> ? and plan_popular = 1);
The where clause lets through only those rows that will actually be changed by the update. If this is a largish table, that can make quite a difference in response time. Logic is much less expensive than any actual operation that can performed in the database.
I want to compare real results and predictions from 2 similar tables on mysql.
real
id | data1| data2 |
user
id | data1| data2 | points
ranking
id | user| total points
I want to do the following:
if (real.data1 = user.data1) AND (real.data2 = user.data2)
update user set points=8 where id=1
else if(real.data1 > user.data1) AND (real.data2 > user.data2)
update user set points=4 where id=1
else if (real.data1 = real.data2) AND (user.data1 = user.data2)
update user set points=4 where id=1
else if (real.data1 < user.data1) AND (real.data2 < user.data2)
update user set points=4 where id=1
else
update user set points=0 where id=1
sum all values from points and update ranking table
Is it possible?
I believe the below will work for the first half of your question, but I have not tested it:
UPDATE `user` u
INNER JOIN `real` r ON (u.id = r.id)
SET u.points = IF(r.data1 = u.data1 and r.data2 = u.data2,
8,
IF(r.data1 > u.data1 and r.data2 > u.data2,
4,
IF(r.data1 = r.data2 and u.data1 = u.data2,
4,
IF(r.data1 < u.data1 and r.data2 < u.data2,
4,
0)
)
)
)
See the MySQL docs concerning the IF statement if this doesn't make sense.