How do I set the scope of this MySQL UPDATE operation? - mysql

Standard disclaimer: I'm a total know-nothing when it comes to MySQL. The way I'm trying to do things is almost certainly not clever, and I'm open to suggestions for improvement.
I have two databases: wordpress and wordpress3. wordpress3 is a copy of wordpress, converted to UTF-8. In the process of conversion, however, mis-encoded characters caused data loss.
My Goal:
Locate all entries in wordpress.wp_options where the option_value when encoded as UTF-8 is not the same as when encoded as ASCII.
For each entry described by #1 above, update the corresponding entries in wordpress3.wp_options with the data from wordpress, converted to UTF-8.
I'm checking and replacing the option_values column of wp_options right now as a proof of concept. Once I get it working, I want to rejigger the thing so that it does this for all columns in all tables in the database... but that's getting ahead of myself.
My Script:
update wordpress3.wp_options wp3
SET wp3.option_value = (SELECT
CONVERT(wp.option_value using UTF8) from wordpress.wp_options wp
WHERE convert(wp.option_value using ascii) != convert(wp.option_value using utf8)
AND wp.option_id = wp3.option_id)
WHERE [?]
My Issue:
I don't know how to write the WHERE statement for the UPDATE command (hence the [?]). With nothing in that WHERE statement, my script will match and update seven rows the way I want them updated... but then wp3.option_value will be set to NULL for everything that doesn't match the subquery.
I can define the WHERE explicitly, by using option_names for options I know need to be replaced, like so:
WHERE wp3.option_name = 'shortcoder_data';
...but that's slow and clunky.
Thanks!

I used INNER JOIN to join the two tables (wordpress.wp_options wp and wordpress3.wp_options wp3) and select only the entries where wp.option_id and wp3.option_id were the same, but convert(wp.option_value using ascii) and convert(wp.option_value using utf8) were different:
UPDATE wordpress3.wp_options wp3
INNER JOIN wordpress.wp_options wp ON (wp.option_id = wp3.option_id
AND convert(wp.option_value using utf8) != convert(wp.option_value using ascii))
SET wp3.option_value = convert(wp.option_value using utf8);
This seems to have done the trick.

Related

How to convert ASP MSAccess SQL CDbl and LEFT in a select statement to MySQL

I have this SQL statement in an ASP page querying the database and I need to convert it to MySQL.
SELECT DISTINCT trelMapSU.Site, trelMapSU.MapNum, tlkpSUTyp.SUTyp,
tblSU.SUNum, tlkpSUDesc.SUDesc,
CDbl(IIf(IsNumeric( [tblSU]![SUNum]),[tblSU]![SUNum],
Left([tblSU]![SUNum],
InStr(1,[tblSU]![SUNum],'-')-1)
)
)
FROM tlkpSUTyp
I am new to this and found that CDbl means to convert a value to a double which still make very little sense to me even with the examples I have found. It also seems that the Left command returns a specified number of characters from the left side of a string. A Little more clear but I am still not sure what this is trying to accomplish. Can someone explain how to convert this to MySQL?
UPDATE
Could someone translate what this means:
CDbl(IIf(IsNumeric( [tblSU]![SUNum]),[tblSU]![SUNum],
Left([tblSU]![SUNum],
InStr(1,[tblSU]![SUNum],'-')-1)
)
)
I think if I knew that I could get somewhere.

Character set 'binary' cannot be used in conjunction with 'utf8mb4_unicode_ci' in call to regexp_like

I've been using a case sensitive regular expression in a MySQL query for awhile and it has worked perfectly. It suddenly stopped working this weekend, I'm guessing after an update.
Per other people's questions, I learned to use CAST as BINARY for getting the query to be case sensitive.
Below is a simplified version of the query I am using.
SELECT * FROM Table
WHERE CAST(Name AS BINARY) REGEXP 'anything in here really'
I am now getting the error:
Character set 'binary' cannot be used in conjunction with 'utf8mb4_unicode_ci' in call to regexp_like.
I currently use utf8_general_ci on everything, but tried changing the column, table, and even database to utf8_bin without any change in the error message.
I'm running mysqlnd 7.4.3 on Ubuntu and doing most everything through PHP, but debugging in phpMyAdmin.
I should also point out that I am an extreme novice who doesn't used MySQL much and and never really has a need beyond the most basic things, so online guides are the only way I've even gotten this far.
Thank you for any help you can provide!
I just encountered this error with queries like:
SELECT * FROM Table
WHERE Name REGEXP BINARY 'anything in here really'
...which previously worked without error.
I'm finding that changing it to the following kind of thing is working:
SELECT * FROM Table
WHERE CAST(Name AS BINARY) REGEXP BINARY 'anything in here really'

Django mysql count distinct gives different result to postgres

I'm trying to count distinct string values for a fitered set of results in a django query against a mysql database versus the same data in a postgres database. However, I'm getting really confusing results.
In the code below, NewOrder represents queries against the same data in a postgres database, and OldOrder is the same data in a MYSQL instance.
( In the old database, completed orders had status=1, in the new DB complete status = 'Complete'. In both the 'email' field is the same )
OldOrder.objects.filter(status=1).count()
6751
NewOrder.objects.filter(status='Complete').count()
6751
OldOrder.objects.filter(status=1).values('email').distinct().count()
3747
NewOrder.objects.filter(status='Complete').values('email').distinct().count()
3825
print NewOrder.objects.filter(status='Complete').values('email').distinct().query
SELECT DISTINCT "order_order"."email" FROM "order_order" WHERE "order_order"."status" = Complete
print OldSale.objects.filter(status=1).values('email').distinct().query
SELECT DISTINCT "order_order"."email" FROM "order_order" WHERE "order_order"."status" = 1
And here is where it gets really bizarre
new_orders = NewOrder.objects.filter(status='Complete').values_list('email', flat=True)
len(set(new_orders))
3825
old_orders = OldOrder.objects.filter(status=1).values_list('email',flat=True)
len(set(old_orders))
3825
Can anyone explain this discrepancy? And possibly point me as to why results would be different between postgres and mysql? My only guess is a character encoding issue, but I'd expect the results of the python set() to also be different?
Sounds like you're probably using a case-insensitive collation in MySQL. There's no equivalent in PostgreSQL; the closest is the citext data type, but usually you just compare lower(...) of strings, or use ILIKE for pattern matching.
I don't know how to say it in Django, but I'd see if the count of the set of distinct lowercased email addresses is the same as the old DB.
According to the Django docs something like this might work:
NewOrder.objects.filter(status='Complete').values(Lower('email')).distinct()

Magento CSV Import Images Missing

I edited my products by exporting them with the Import/Export Tool in magento, after I imported them I got faced with There was a problem with reindexing process, which I finally fixed.
But now all my images are missing and not displaying in the front end, can someone help me fix this issue?
/1/_/1_7_138.jpg is the format that the CSV images locations are
I also tried moving the images in media/category/product to media/import but still not displaying correctly
I also tried editing file permissions from 755 to 77 in the media folder but still nothing
I also ran this in the corresponding SQL database
INSERT INTO catalog_product_entity_media_gallery (attribute_id, entity_id, `value`)
SELECT ga.attribute_id, v.entity_id, v.value
FROM catalog_product_entity_varchar v
INNER JOIN eav_entity_type et ON et.entity_type_code=\'catalog_product\'
INNER JOIN eav_attribute va ON va.entity_type_id=et.entity_type_id AND
va.frontend_input=\'media_image\' AND va.attribute_id=v.attribute_id
INNER JOIN eav_attribute ga ON va.entity_type_id=et.entity_type_id AND
ga.attribute_code=\'media_gallery\'
LEFT JOIN catalog_product_entity_media_gallery g ON g.entity_id=v.entity_id AND
g.value=v.value
WHERE v.value<>\'no_selection\' AND v.value<>\'\' AND g.value IS NULL;
and got the following error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near '\'catalog_product\' INNER JOIN
eav_attribute va ON va.entity_ty
Not sure if you're having the same problem that I did, but when I re-imported products my images broke but the image was still associated with the product, just not set as the base, small, thumbnail, etc
I did something like
update catalog_product_entity_varchar AS v inner join catalog_product_entity_media_gallery AS g on v.entity_id = g.entity_id set v.value = g.value where (v.attribute_id = '85' or v.attribute_id = '86' or v.attribute_id = '87');
in my database to reassign them all.
Check following in
data base table catalog_product_entity_media_gallery is there an entry for image you are looking for.
something like 1 703 17 /1/_/1_7_138.jpg
Then go to media/catalog/product/1/_/ and check if this image file exists.
Additional flush your cache and check.
When using Import/Export, the folder structure in your media/import folder has to be the same as specified in your csv file. So if a media filename is specified as "/1/_/1_7_138.jpg" in your CSV, there must exist a file "/media/import/1/_/1_7_138.jpg" in your Magento root. Otherwise Import/Export won't find the media file.
The easiest solution would be, to not define a folder structure in your csv and to put all media files, that should be imported, directly in media/import/. So in your case:
CSV entry (e.g. in column 'thumbnail'): 1_7_138.jpg
File: /media/import/1_7_138.jpg
Unfortunately, Magento is not capable of importing its own exports! So an exported CSV has to be modified, to be importable in another Magento installation.
Not sure if you're still having issues, but to help with the INSERT query you listed, it's not working because the single quotes are escaped. I'm guessing you found this query in a post somewhere and when the query was posted, the single quotes were escaped with "\'".
If you change all of the \' to just single quotes like this:
INSERT INTO ......
INNER JOIN eav_entity_type et ON et.entity_type_code='catalog_product' <-- is where I changed the \' to just a single '. You'll need to do that with the entire query.
The query should then work. I also suggest as good practice, that you first run the select without the insert command to make sure it gives back good results before running an insert command blindly.

Find and Replace text in the entire table using a MySQL query

Usually I use manual find to replace text in a MySQL database using phpMyAdmin. I'm tired of it now, how can I run a query to find and replace a text with new text in the entire table in phpMyAdmin?
Example: find keyword domain.example, replace with www.domain.example.
For a single table update
UPDATE `table_name`
SET `field_name` = replace(same_field_name, 'unwanted_text', 'wanted_text')
From multiple tables-
If you want to edit from all tables, best way is to take the dump and then find/replace and upload it back.
The easiest way I have found is to dump the database to a text file, run a sed command to do the replace, and reload the database back into MySQL.
All commands below are bash on Linux.
Dump database to text file
mysqldump -u user -p databasename > ./db.sql
Run sed command to find/replace target string
sed -i 's/oldString/newString/g' ./db.sql
Reload the database into MySQL
mysql -u user -p databasename < ./db.sql
Easy peasy.
Running an SQL query in phpMyAdmin to find and replace text in all WordPress blog posts, such as finding mysite.example/wordpress and replacing that with mysite.example/news
Table in this example is tj_posts
UPDATE `tj_posts`
SET `post_content` = replace(post_content, 'mysite.example/wordpress', 'mysite.example/news')
Put this in a php file and run it and it should do what you want it to do.
// Connect to your MySQL database.
$hostname = "localhost";
$username = "db_username";
$password = "db_password";
$database = "db_name";
mysql_connect($hostname, $username, $password);
// The find and replace strings.
$find = "find_this_text";
$replace = "replace_with_this_text";
$loop = mysql_query("
SELECT
concat('UPDATE ',table_schema,'.',table_name, ' SET ',column_name, '=replace(',column_name,', ''{$find}'', ''{$replace}'');') AS s
FROM
information_schema.columns
WHERE
table_schema = '{$database}'")
or die ('Cant loop through dbfields: ' . mysql_error());
while ($query = mysql_fetch_assoc($loop))
{
mysql_query($query['s']);
}
phpMyAdmin includes a neat find-and-replace tool.
Select the table, then hit Search > Find and replace
This query took about a minute and successfully replaced several thousand instances of oldurl.ext with the newurl.ext within Column post_content
Best thing about this method : You get to check every match before committing.
N.B. I am using phpMyAdmin 4.9.0.1
Another option is to generate the statements for each column in the database:
SELECT CONCAT(
'update ', table_name ,
' set ', column_name, ' = replace(', column_name,', ''www.oldDomain.example'', ''www.newDomain.example'');'
) AS statement
FROM information_schema.columns
WHERE table_schema = 'mySchema' AND table_name LIKE 'yourPrefix_%';
This should generate a list of update statements that you can then execute.
UPDATE table SET field = replace(field, text_needs_to_be_replaced, text_required);
Like for example, if I want to replace all occurrences of John by Mark I will use below,
UPDATE student SET student_name = replace(student_name, 'John', 'Mark');
If you are positive that none of the fields to be updated are serialized, the solutions above will work well.
However, if any of the fields that need updating contain serialized data, an SQL Query or a simple search/replace on a dump file, will break serialization (unless the replaced string has exactly the same number of characters as the searched string).
To be sure, a "serialized" field looks like this:
a:1:{s:13:"administrator";b:1;}
The number of characters in the relevant data is encoded as part of the data.
Serialization is a way to convert "objects" into a format easily stored in a database, or to easily transport object data between different languages.
Here is an explanation of different methods used to serialize object data, and why you might want to do so, and here is a WordPress-centric post: Serialized Data, What Does That Mean And Why is it so Important? in plain language.
It would be amazing if MySQL had some built in tool to handle serialized data automatically, but it does not, and since there are different serialization formats, it would not even make sense for it to do so.
wp-cli
Some of the answers above seemed specific to WordPress databases, which serializes much of its data. WordPress offers a command line tool, wp search-replace, that does handle serialization.
A basic command would be:
wp search-replace 'an-old-string' 'a-new-string' --dry-run
However, WordPress emphasizes that the guid should never be changed, so it recommends skipping that column.
It also suggests that often times you'll want to skip the wp_users table.
Here's what that would look like:
wp search-replace 'https://old-domain.example' 'https://shiney-new-domain.com' --skip-columns=guid --skip-tables=wp_users --dry-run
Note: I added the --dry-run flag so a copy-paste won't automatically ruin anyone's database. After you're sure the script does what you want, run it again without that flag.
Plugins
If you are using WordPress, there are also many free and commercial plugins available that offer a gui interface to do the same, packaged with many additional features.
Interconnect/it PHP script
Interconnect/it offers a PHP script to handle serialized data: Safe Search and Replace tool. It was created for use on WordPress sites, but it looks like it can be used on any database serialized by PHP.
Many companies, including WordPress itself, recommends this tool. Instructions here, about 3/4 down the page.
UPDATE `MySQL_Table`
SET `MySQL_Table_Column` = REPLACE(`MySQL_Table_Column`, 'oldString', 'newString')
WHERE `MySQL_Table_Column` LIKE 'oldString%';
I believe "swapnesh" answer to be the best ! Unfortunately I couldn't execute it in phpMyAdmin (4.5.0.2) who although illogical (and tried several things) it kept saying that a new statement was found and that no delimiter was found…
Thus I came with the following solution that might be usefull if you exeprience the same issue and have no other access to the database than PMA…
UPDATE `wp_posts` AS `toUpdate`,
(SELECT `ID`,REPLACE(`guid`,'http://old.tld','http://new.tld') AS `guid`
FROM `wp_posts` WHERE `guid` LIKE 'http://old.tld%') AS `updated`
SET `toUpdate`.`guid`=`updated`.`guid`
WHERE `toUpdate`.`ID`=`updated`.`ID`;
To test the expected result you may want to use :
SELECT `toUpdate`.`guid` AS `old guid`,`updated`.`guid` AS `new guid`
FROM `wp_posts` AS `toUpdate`,
(SELECT `ID`,REPLACE(`guid`,'http://old.tld','http://new.tld') AS `guid`
FROM `wp_posts` WHERE `guid` LIKE 'http://old.tld%') AS `updated`
WHERE `toUpdate`.`ID`=`updated`.`ID`;
the best you export it as sql file and open it with editor such as visual studio code and find and repalace your words.
i replace in 1 gig file sql in 1 minutes for 16 word that total is 14600 word.
its the best way.
and after replace it save and import it again.
do not forget compress it with zip for import.
In the case of sentences with uppercase - lowercase letters,
We can use BINARY REPACE
UPDATE `table_1` SET `field_1` = BINARY REPLACE(`field_1`, 'find_string', 'replace_string')
Here's an example of how to find and replace in Database
UPDATE TABLE_NAME
SET COLUMN = replace(COLUMN,'domain.example', 'www.domain.example')
TABLE_NAME => Change it with your table name
COLUMN => Change it to your column make sure it exists
I have good luck with this query when doing a search and replace in phpmyadmin:
UPDATE tableName SET fieldName1 = 'foo' WHERE fieldName1 = 'bar';
Of course this only applies to one table at a time.
Generate change SQL queries (FAST)
mysql -e "SELECT CONCAT( 'update ', table_name , ' set ', column_name, ' = replace(', column_name,', ''www.oldsite.example'', ''www.newsite.example'');' ) AS statement FROM information_schema.columns WHERE table_name LIKE 'wp_%'" -u root -p your_db_name_here > upgrade_script.sql
Remove any garbage at the start of the file. I had some.
nano upgrade_script.sql
Run generated script with --force options to skip errors. (SLOW - grab a coffee if big DB)
mysql -u root -p your_db_name_here --force < upgrade_script.sql