Update multiple mysql rows with 1 query? - mysql

I am porting client DB to new one with different post titles and rows ID's , but he wants to keep the hits from old website,
he has over 500 articles in new DB , and updating one is not an issue with this query
UPDATE blog_posts
SET hits=8523 WHERE title LIKE '%slim charger%' AND category = 2
but how would I go by doing this for all 500 articles with 1 query ? I already have export query from old db with post title and hits so we could find the new ones easier
INSERT INTO `news_items` (`title`, `hits`) VALUES
('Slim charger- your new friend', 8523 )...
the only reference in both tables is product name word within the title everything else is different , id , full title ...

Make a tmp table for old data in old_posts
UPDATE new_posts LEFT JOIN old_posts ON new_posts.title = old_posts.title SET new_posts.hits = old_posts.hits;

Unfortunately that's not how it works, you will have to write a script/program that does a loop.
articles cursor;
selection articlesTable%rowtype;
WHILE(FETCH(cursor into selection)%hasNext)
Insert into newTable selection;
END WHILE
How you bridge it is up to you, but that's the basic pseudo code/PLSQL.
The APIs for selecting from one DB and putting into another vary by DBMS, so you will need a common intermediate format. Basically take the record from the first DB, stick it into a struct in the programming language of your choice, and prefrom an insert using those struct values using the APIs for the other DBMS.

I'm not 100% sure that you can update multiple records at once, but I think what you want to do is use a loop in combination with the update query.
However, if you have 2 tables with absolutely no relationship or common identifiers between them, you are kind of in a hard place. The hard place in this instance would mean you have to do them all manually :(
The last possible idea to save you is that the id's might be different, but they might still have the same order. If that is the case you can still loop through the old table and update the number table as I described above.

You can build a procedure that'll do it for you:
CREATE PROCEDURE insert_news_items()
BEGIN
DECLARE news_items_cur CURSOR FOR
SELECT title, hits
FROM blog_posts
WHERE title LIKE '%slim charger%' AND category = 2;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN news_items_cur;
LOOP
IF done THEN
LEAVE read_loop;
END IF;
FETCH news_items_cur
INTO title, hits;
INSERT INTO `news_items` (`title`, `hits`) VALUES (title, hits);
END LOOP;
CLOSE news_items_cur;
END;

Related

Rails - How to reference model's own column value during update statement?

Is it possible to achieve something like this?
Suppose name and plural_name are fields of Animal's table.
Suppose pluralise_animal is a helper function which takes a string and returns its plural literal.
I cannot loop over the animal records for technical reasons.
This is just an example
Animal.update_all("plural_name = ?", pluralise_animal("I WANT THE ANIMAL NAME HERE, the `name` column's value"))
I want something similar to how you can use functions in MySQL while modifying column values. Is this out-of-scope or possible?
UPDATE animals SET plural_name = CONCAT(name, 's') -- just an example to explain what I mean by referencing a column. I'm aware of the problems in this example.
Thanks in advance
I cannot loop over the animal records for technical reasons.
Sorry, this cannot be done with this restriction.
If your pluralizing helper function is implemented in the client, then you have to fetch data values back to the client, pluralize them, and then post them back to the database.
If you want the UPDATE to run against a set of rows without fetching data values back to the client, then you must implement the pluralization logic in an SQL expression, or a stored function or something.
UPDATE statements run in the database engine. They cannot call functions in the client.
Use a ruby script to generate a SQL script that INSERTS the plural values into a temp table
File.open(filename, 'w') do |file|
file.puts "CREATE TEMPORARY TABLE pluralised_animals(id INT, plural varchar(50));"
file.puts "INSERT INTO pluralised_animals(id, plural) VALUES"
Animal.each.do |animal|
file.puts( "( #{animal.id}, #{pluralise_animal(animal.name)}),"
end
end
Note: replace the trailing comma(,) with a semicolon (;)
Then run the generated SQL script in the database to populate the temp table.
Finally run a SQL update statement in the database that joins the temp table to the main table...
UPDATE animals a
INNER JOIN pluralised_animals pa
ON a.id = pa.id
SET a.plural_name = pa.plural;

OPENQUERY SQL Server MYSQL UPDATE

I have to work on a linked server. My goal: Update an entire table in mysql server(version:8.0.21) via OPENQUERY in SQL Server(version 13.0.1742.0). I tried this but it generates an error Row cannot be located for updating. Some values may have been changed since it was last read and this one The rowset was using optimistic concurrency and the value of a column has been changed after the containing row was last fetched or resynchronized.
update linkedTable
set
linkedTable.id_parent=unlinkedTable.IdCat1,
linkedTable.code=unlinkedTable.CodeFamilleFAT,
linkedTable.niveau=unlinkedTable.NiveauCategorieFAT,
linkedTable.langue=unlinkedTable.CodeLangueFAT,
linkedTable.nom=unlinkedTable.LibelleCommercialFAT,
linkedTable.descriptionA=unlinkedTable.DescriptifCom1FAT,
linkedTable.vignette=null,
linkedTable.id_categorie=unlinkedTable.id
from openquery(NAMELINKEDSERVER, 'select id_categorie, id_parent, code, niveau, langue, nom, description as descriptionA, vignette from DatabaseMySQL.Table') as linkedTable
inner join DatabaseSQLserver.dbo.Table as unlinkedTable on unlinkedTable.Id = linkedTable.id_categorie
Then I tried this:
update linkedTable
set
linkedTable.id_parent=unlinkedTable.IdCat1,
linkedTable.code=unlinkedTable.CodeFamilleFAT,
linkedTable.niveau=unlinkedTable.NiveauCategorieFAT,
linkedTable.langue=unlinkedTable.CodeLangueFAT,
linkedTable.nom=unlinkedTable.LibelleCommercialFAT,
linkedTable.descriptionA=unlinkedTable.DescriptifCom1FAT,
linkedTable.vignette=null,
linkedTable.id_categorie=unlinkedTable.id
from openquery(NAMELINKEDSERVER, 'select id_categorie, id_parent, code, niveau, langue, nom, description as descriptionA, vignette from DatabaseMySQL.Table') as linkedTable
inner join DatabaseSQLserver.dbo.Table as unlinkedTable on unlinkedTable.Id = linkedTable.id_categorie
where linkedTable.id_categorie = 1
This work but only one row is updated. So I wrote a stored procedure to update each line but it took too much time.
Can someone explain why my first query didn't work (question1) and how I can reduce the time of my stored procedure (question2)?
I use while loop (count the number of id and update each id).
Thank you in advance.
Kind Regards.
I resolve the problem by checking some option on ODBC Driver in MySQL and reading some forum. I check this box.
enter image description here
This option allows to avoid the errors quoted previously. With this option, i can update multiple values without error on join or other request. Thank you Solarflare and "Another guy" (i lost the name) for correcting me (EDIT A POST). Have nice day both.

Running Multiple Sql Commands in a Loop

I successfully executed the sql code below from an msql editor (phpmyadmin), testing it with one customer (where Customer No=1). I need to now run the sql script for all the customers.
START TRANSACTION;
INSERT INTO `addresses` (`AddressLine1`,`CityID`,`ProvStateCode`,`AddressPostCode`,`CountryIso`) SELECT `Bill To Address`,`Bill To City`,`Bill To Province`,`Bill Code`,`Country` FROM `pdx_customers` where `Customer No`=1;
SELECT #last_id := LAST_INSERT_ID();
SELECT `Customer No` FROM `pdx_customers`
INSERT INTO `customer_addresses` (`CustID`,`AddressID`,`AddressTypeID`) Values(1,#last_id,1);
COMMIT;
It seems I would need to create a stored procedure ? In a loop, I need to get the Customer No dynamically for each row in the pdx_customers table, and enter into the Values clause in the insert command, i.e Values(#CustID,#last_id,1). Not sure how I would do this ?
Any help would be appreciated.
Thanks
This is a really common problem, and I would say that doing a loop in sql is almost never a good idea. Here is another option, which you may or may not consider good as it does introduce a new column. I've used it in some apps I've done, and its made things very simple. Does depend on your use case though so it wont be for everyone.
1) Firstly, add a new column to the address table, call it something that wont be confused by anyone looking at the table like TempInsertId.
2) When writing the new address, include the CustomerId in the TempInsertId column
3) Now you can easily read the AddressId and CustomerId back and write it into the CustomerAddress table
4) If you wish, do a final update to set the TempInsertId back to null.
As I said, not advocating in all cases, but it can be a very simple solution to the problem.
You can use the below statement to create a loop:
start transaction;
while counter < max do
insert into . . . ;
set counter=counter+1;
end while;

Select from all tables

I have a lot of tables in my data base all with same structure. I want to select from all tables without having to list them all like so:
SELECT name FROM table1,table2,table3,table4
And I tried but this doesn't work:
SELECT name FROM *
Is there a way to select all tables in a database without listing each table in the query?
i am working on a online file browser, each directory has its own table
It is very unuseful due to one reason: when you have about 200 files (this situation is real, yeah?) you have about 200 tables. And if there are about thousand files in each directory.. etc. In some time you will either have slow processing while selecting from your database either have to buy more server resources.
I think you should change your database structure: just begin from adding parent_folder_id column to your table, after this you can put all your rows (files and directories -- because directory is a file too -- here you can add type column to determine this) into the one table.
As far as I know there are no such wildcards to select from *all tables. I would recommend writing a view and then call that view instead (it will save you writing out the names every time) – VoodooChild
That means you should not have a lot of tables with same structure at all.
But just one table with a field to distinguish different kinds of data, whatever it is.
Then select all would be no problem.
I found a solution, but I would still like to know if there is a simpler way or a better solution.
But here's what I came up with:
$tables = mysql_query("show tables");
$string = '';
while ($table_data = mysql_fetch_row($tables)){
$string.=$table_data[0].',';
}
$ALL_TABLES = substr($string,0,strlen($string)-1);
$sql="SELECT name FROM $ALL_TABLES ";
Sounds like you want to UNION together each table, so you get the results as if they were one big table. You'll need to write out the query in full like
SELECT * FROM table1 UNION SELECT * FROM table2 UNION ... SELECT * FROM tableN
Copy & paste may be your friend here.
I'm curious as to why you have lots of different tables with the same structure?
You can generate SELECT by cursor like this code
and find all result step by step in sql server:
--Author: Ah.Ghasemi
Declare #Select sysname;
DECLARE A CURSOR
FOR Select 'select ' + '*' + ' from ' + name
from sys.tables
--Where name like 'tbl%'
Order by name
OPEN A
FETCH NEXT FROM A INTO #Select
While (##FETCH_STATUS <>-1)
Begin
exec sp_executesql #Select
FETCH NEXT FROM A INTO #Select;
End
close A
Deallocate A
Please let us know if the problem is not resolved.
I hope you for the best

Using IF statements in a MySQL trigger to insert multiple rows

I have a trigger that stores changes made in a separate table when a user edits the data. This data is written out on a web page beneath the current data in human readable format, i.e.
23/04/09 22:47 James Smith changed Tenant Name from "George Hill" to "George Hilling".
The trigger I have looks a bit like this - (this is the abridged version).
Two questions:
A) Is this quite costly performance-wise and if so is there a better approach to take?
B) Is there a tidier way to do this without all the IFs, using some sort of loop perhaps?
DELIMITER //
CREATE TRIGGER repair_history AFTER UPDATE ON repairs
FOR EACH ROW
BEGIN
INSERT INTO repair_edit SET repair_id=NEW.repair_id,
edit_date_time=NEW.edit_date_time, edited_by=NEW.edited_by;
IF OLD.tenant_name != NEW.tenant_name THEN
INSERT INTO repair_history SET edit_id=LAST_INSERT_ID(), field='tenant_name',
former_field_value=OLD.tenant_name, new_field_value=NEW.tenant_name;
END IF;
IF OLD.priority != NEW.priority THEN
INSERT INTO repair_history SET edit_id=LAST_INSERT_ID(), field='priority',
former_field_value=OLD.priority, new_field_value=NEW.priority;
END IF;
IF OLD.property_id != NEW.property_id THEN
INSERT INTO repair_history SET edit_id=LAST_INSERT_ID(), field='property_id',
former_field_value=OLD.property_id, new_field_value=NEW.property_id;
END IF;
IF OLD.type_id != NEW.type_id THEN
INSERT INTO repair_history SET edit_id=LAST_INSERT_ID(), field='type_id',
former_field_value=OLD.type_id, new_field_value=NEW.type_id;
END IF;
END; //
DELIMITER ;
A) Is this quite costly performance-wise
Profile it. Only you know what hardware you're using, and what volume of updates your database has to handle.
and if so is there a better approach to take?
Consider what's taking the mosst time in your trigger. Is it the comparisons, or the inserts?
B) Is there a tidier way to do this without all the IFs, using some sort of loop perhaps?
Unfortunately, I don't know of a way to index into the columns of pseudo tables NEW and OLD
Why not put a trigger on each column that can be updated and checked. This will have a performance hit though. What you may want to do is do a unit test where you have the trigger and don't have it, and see what the difference in time is when you are changing many rows quickly.
http://forums.mysql.com/read.php?99,174963,175381#msg-175381