UPDATE (B) from (A) if (B) = 0? - mysql

I'm learning this for school and I'm confused. I'm trying to copy information between columns in a single table in a single db, all local.
Basically:
(I need to loop through and update all records)
UPDATE `my_records`
SET `realname` = `name`
WHERE `realname` = 0;
SELECT * FROM `my_records` SET `realname` = `name` WHERE `realname` = 0;
It keeps telling me I have a syntax error.
I now see why they are asking me to learn this. Each row in the table is different so when I update all columns some rows change that shouldn't so that's not the end result I'm after. I can try to give an example but this is confusing to me.
DB -> Table -> Row 1 - holds the name of the person -> Row 2 - holds the picture
of the person
Both things have a name (example Row 1 David, Row 2 Flower.JPG)
So I'm guessing they want me to figure out a way to exclude updating the 'real_name' column on Row 2 where the image is a JPG, GIF, or PNG.
I think the final result they are looking for when the table is updated is:
Row 1 'David' 'David'
Row 2 'flower.jpg'
Then this loops over and over again for all the records.

You need to use an UPDATE instead of a SELECT. SELECT statements only return data, they do not modify data.
So, to return the records you will update in the next step:
SELECT `realname`, `name` FROM `my_records` WHERE `realname` = 0;
and then to update those records:
UPDATE `my_records` SET `realname` = `name` WHERE `realname` = 0;
Note that this query will update the entire table, setting any row where the value of realname is equivalent to 0, to the value of that same row's name column.
A few other possibly useful statements:
UPDATE `my_records` SET `realname` = `name` WHERE `realname` = '';
This will affect all rows where realname is equivalent to 'empty string'
UPDATE `my_records` SET `realname` = `name` WHERE `realname` IS NULL;
will affect all rows where realname is NULL

Related

Can I set multiple columns to NULL in MySQL in bulk?

I have a very large database and for testing, I want to set a certain amount of data to NULL.
As an example, I have 57 columns across 3 tables, all of which need to be nullified. I can't delete the rows, I just need to know that if the row exists and there's no data in those fields, that everything still works.
To clarify, all the data in those fields has been moved to anther table, and the old data was not wiped in the migration. To test my reports I need to know that the reports are pulling from the new location, not the old, since as new data is added, it will only go to the new location. Our plan is to generate each report from the old database, migrate, and then generate them again and compare. But to ensure that they are pulling from the right place, we want to wipe the old data so it doesn't provide a false positive.
Is there a way for me to do this in bulk or should I resign myself to writing one comma separated SET statement after another?
You can create the statements using the data from the internal information_schema.COLUMNS table.
Assuming you have this table:
CREATE TABLE my_table (
keep1 INT,
keep2 INT,
set_null1 INT,
set_null2 INT,
set_null3 INT
);
and you want to set all columns to NULL except of keep1 and keep2. Execute the following script:
set #db_name = 'test';
set #table_name = 'my_table';
set #exclude_columns = 'keep1,keep2';
select concat(
'UPDATE `', #table_name, '` SET\n',
group_concat('`', COLUMN_NAME, '` = NULL' separator ',\n'),
';'
)
from information_schema.COLUMNS c
where c.TABLE_SCHEMA = #db_name
and c.TABLE_NAME = #table_name
and find_in_set(c.COLUMN_NAME, #exclude_columns) = 0;
This will generate the following statement:
UPDATE `my_table` SET
`set_null1` = NULL,
`set_null2` = NULL,
`set_null3` = NULL;
Copy the result and paste it into your UPDATE script. Do it for all 12 tables adjusting the variables #db_name, #table_name and #exclude_columns.
See demo on db-fiddle.
This is a very unusual task for an SQL database, so it's not surprising that it's a bit awkward.
As you know, to set multiple columns to NULL in an UPDATE statement, you'd have to set each column individually.
UPDATE mytable
SET col1 = NULL, col2 = NULL, ... col57 = NULL
WHERE id = ?;
That could be quite a bit of typing. Or it could be a task to write code to loop over the column names in your table, and concatenate the terms for UPDATE statement. Up to you.
An alternative that might be easier is to delete the row and then re-insert it with no values specified except the primary key.
DELETE FROM mytable WHERE id = ?;
INSERT INTO mytable SET id = ?;
By omitting the other columns, they'll be NULL or else take a DEFAULT value defined in your table. If you want those columns with defaults to be NULL too, you'll have to specify that.
INSERT INTO mytable SET id = ?, col23 = NULL;

sql -- select and update

I've being trying to amend the solution found in this tutorial to write an SQL query that both SELECTs and UPDATEs my table:
enter link description here
DECLARE #column1 varchar(2);
SET #column1 = (SELECT `Id`, `Url` FROM `MyTable` WHERE `Retrieved` = 0);
SELECT * FROM `MyTable` WHERE `AdId`, `Url` = #column1;
UPDATE `MyTable` SET `Retrieved` = 1 where `Id`, `Url` = #column1;
What i'm trying to achieve the following simultaneously:
SELECT Id, Url FROM MyTable WHERE Retrieved = 0
UPDATE MyTable SET Retrieved = 1
for the rows where i have SELECTed the results from
Basically, i want to select all data from ID and Url columns where the Retrieved column equals 0. I then want to set the Retrieved column to 1 for the rows i have selected.
The "normal" SQL method would be:
UPDATE MyTable
SET Retrieved = 1
WHERE id IN (SELECT Id FROM MyTable WHERE Retrieved = 0);
That does not work in MySQL. Assuming that id is unique in MyTable (a reasonable assumption in my opinion), then this does what you want:
UPDATE MyTable
SET Retrieved = 1
WHERE Retrieved = 0;
UPDATE t SET t.Retrieved=1 FROM MyTable t WHERE t.Retrieved=0
This is only updating rows, that essentially you've selected. In your case you want to update rows where the selected rows Retrieved column is equal to 0.
The other thing and maybe for readibility or you need the rows returned you can use a cte.
--first get only the records you need
WITH MyRecords_cte
AS
(
SELECT Id, URL, Retreived FROM MyTable WHERE Retreived=0
)
UPDATE MyRecords_cte SET MyRecords_cte.Retreived=1
Once you're done with the update you can return the data.

MySQL update a row but a single field

I update a Table with multiple fields. Now one of the fields may only be updated if another field has a defined value, e.g.:
id | name | image | update
--------------------------------------------------
1 | john | myimage.jpg | 0
2 | ben | yourimage.gif | 1
--------------------------------------------------
Now i walk through all rows and update all fields but the image should only be update if the "update"-flag is set to 1.
If its 0 the existing value should not be overwritten.
Now i tried this:
...
`image` = IF(update = 1, VALUES(`image`),`image`)
...
but its obviously not working because it overwrites the image in every case.
update table
set image = new_value
where update = 1
and id = ?// if you want spacific row, if not ignore this line
If you only want to update the image column Ofer's answer is surely the best. If you'd like to pack the image update into a bigger query, the IF() works as follows:
IF(expression, return this if expression true, return this if expression false)
in your case:
UPDATE table t1
SET
t1.image = IF(t1.update = 1, t1.image, 'new image')
First just fetch the value of update from table by query
Select update from your table where id = 'provide row id'
Then using if else condition by checking value of update fetch fire your update
query
eg.
if($update == 1)
{
echo "Your update query here";
}
else
{
}
Be careful with the name of your column 'update'. It's a reserved word, like you can see below (for updating rows).
I would change it to:
ALTER mytable
CHANGE update update_flag tinyint
and then use the following for updating your rows:
UPDATE mytable
SET image = somevalue
WHERE update_flag = 1
AND id = someid
You only need the last line if you don't want to update all your rows where update_flag is 1.
update your_table
set `image` = case when update = 1
then $newvalue
else `image`
end,
other_column = 'some_value'

Trigger an update on a column of a row if a select partially matches one of that row's columns

To be more clear:
The table thetable (id int, username varchar(30), password varchar(30), last_successful_login timestamp, last_unsuccessful_login timestamp, another_variable varchar(30)) has the following row: (1, "tgh", "pass", 0, 0, "another")
1) Wrong User/Pass Pair, but there is a row with the username
I want select id from thetable where username="tgh" and password="wrongpass" and another_variable="another"; to update the last_unsuccessful_login columns of all the rows with username="tgh" AND another_variable="another" (which is unique, there can't be two rows with ("tgh", "another") pair. There can be ("tgh", "another2") though.) to CURRENT_TIMESTAMP.
So the example row would be (1, "tgh", "pass", 0, CURRENT_TIMESTAMP, "another"), after the "select" query that does not completely match.
To be even more clear, I am trying to avoid running an extra update with only username="tgh" and another_variable="another" on the table, i.e. update thetable set last_unsuccessful_login=CURRENT_TIMESTAMP where username="tgh" and another_variable="another";, according to the result of the select.
2) Correct User/Pass Pair
Also, if all three username and password and another_variable matches, this time I want to set the last_successful_login to CURRENT_TIMESTAMP.
That would make the example row `(1, "tgh", "pass", CURRENT_TIMESTAMP, 0, "another")
What is the most efficient way to do this?
The short answer to your question is no, it is not possible for a SELECT statement to cause or trigger an update. (The caveat here is that a SELECT statement can call a FUNCTION (MySQL stored program) which can perform an UPDATE.)
You can't get around issuing an UPDATE statement; an UPDATE statement has to be issued from somewhere, and a SELECT statement cannot "trigger" it.
It is possible to have a single UPDATE statement do the check of the supplied password against the current value in the password column, and set both the last_successful_login and last_unsuccessful_login columns, e.g.:
UPDATE thetable
SET last_successful_login =
IF(IFNULL(password,'')='wrongpass',CURRENT_TIMESTAMP,0)
, last_unsuccessful_login =
IF(IFNULL(password,'')='wrongpass',0,CURRENT_TIMESTAMP)
WHERE username='tgh'
AND another_variable='another'
So, you could issue an UPDATE statement first; and then issue a SELECT statement.
If you want to minimize the number of "roundtrips" to the database, at the cost of additional complexity (making it harder for someone else to figure out what is going on) you could put the UPDATE statement into a stored program. If you put this into a function, you could set the return value to indicate whether the login was successful.
SELECT udf_login('username','wrongpass','another')
So, from your application, it looks like you are doing a login check, but the called function can perform the UPDATE.
CREATE FUNCTION `udf_login`
( as_username VARCHAR(30)
, as_password VARCHAR(30)
, as_another_variable VARCHAR(30)
) RETURNS INT
READS SQL DATA
BEGIN
UPDATE `thetable`
SET `last_successful_login` =
IF(IFNULL(`password`,'')=IFNULL(as_password,''),CURRENT_TIMESTAMP,0)
, `last_unsuccessful_login` =
IF(IFNULL(`password`,'')=IFNULL(as_password,''),0,CURRENT_TIMESTAMP)
WHERE `username` = as_username
AND `another_variable` = as_another_variable;
-- then perform whatever checks you need to (e.g)
-- SELECT IFNULL(t.password,'')=IFNULL(as_password,'') AS password_match
-- FROM `thetable` t
-- WHERE t.username = as_username
-- AND t.another_variable = as_another_variable
-- and conditionally return a 0 or 1
RETURN 0;
END$$

MySQL if statement

I want to update all rows when invoiceID is NULL else update only the rows where all invoiceID's are the same.
My current SQL statement is as follows:
UPDATE Table SET strPOnummer = '123'
WHERE strPOnummer = '456' AND strPOnummer != '' AND strPOnummer IS NOT NULL
So, when Table.invoiceID is NULL, it should update all rows, else update only the rows where invoiceID is the same.
Assuming that invoiceID is an input parameter, you could do this:
UPDATE Table
SET strPOnummer = '123'
WHERE --your non-invoiceID filtering conditions go here
AND (Table.invoiceID = #InvoiceID OR #InvoiceID IS NULL)
In this case if the #InvoiceID parameter is not null then the first condition will have to be met as the second will never be met, but if it is null then each row of the table will be matched by the second part of the condition and thus the first one isn't relevant anymore
I will write just example not code to use, please modify it yourself as needed
SELECT IF(invoiceID=1,
(UPDATE table as tmp SET... WHERE tmp.id=table.id),
(UPDATE table as tmp SET... WHERE tmp.id=table.id)
) FROM table);