MySQL find and update based on results from 2 tables - mysql

First off, please note that this is not answered in the question here:
MySQL update table based on another tables value
or indeed any other Stack question or answer that I could find!
I converted a forum on a website and now just need to repair the internal URL links on a few hundred of the posts.
Posts are found in the column post_content within the table xyz_posts
ID post_content
1467 This is great https://example.com/index.php?topic=1234 I really like it
1468 Hello world
1469 Take a look https://example.com/index.php?topic=5678.0
You can see the URLs are mostly buried in the post text.
Note that the example above can sometimes be written with topic=1234.0 at the end, although it is actually stored in the database as a value of 1234. I don't want to rewrite the url and accidentally keep the .0
Here's an example of how I need that table to look:
ID post_content
1467 This is great https://example.com/finished-page/ I really like it
1468 Hello world
1469 Take a look https://example.com/another-page/
So, the table xyz_converter maps the old topic number to the new post ID like this:
meta_key meta_value value_id
_bbp_old_topic_id 1234 15675
_bbp_old_reply_id 1234 17439
Caveat here, the number 1234 also exists in this table for forum replies which we don't want, but the meta_key and value_id are different for those as shown. This SQL query works to get to the right one:
SELECT * FROM `xyz_converter` WHERE meta_key LIKE '_bbp_old_topic_id' AND `meta_value` LIKE '1234'
Also in table xyz_posts we map the value_id mentioned above to the post's URL suffix like this:
ID post_name
15675 finished-page
15676 another-page
How do I construct a SQL query that will detect the meta_value in one table and then replace it with the correct final URL as mentioned?
PROCESS SUMMARY
Detect the URL in xyz_posts post_content
Extract the topic number from the URL (eg 1234). If it's 1234.0 then take just 1234
Convert it to a post number in found in xyz_converter value_id (eg 15675) ensuring it is found alongside _bbp_old_topic_id
Take the suffix of the URL in xyz_posts post_name (eg 'finished-page')
Rewrite the original URL to include the suffix (not forgetting the trailing slashes).
I'm using MySQL 5.7.29 and PHPMyAdmin.
I'm fairly new to SQL queries and a Regex noob, but willing to learn more!

A solution that uses only MySQL commands and works in MySQL 5.7 could be like this.
If .0 is present only in the urls you could use a query like this to remove all occurences of .0 from post_content in xyz_posts.
UPDATE `xyz_posts` SET post_content=REPLACE(post_content,'.0 ',' ') WHERE post_content LIKE '%topic=%.0 %';
Then you can use
CREATE TABLE temp_tbl
SELECT CONCAT('index.php?topic=',c.meta_value) as `find_value` ,p.post_name as `replace_value`
FROM `xyz_converter` c
INNER JOIN `xyz_posts` p ON c.value_id=p.id AND `meta_key`='_bbp_old_topic_id'
ORDER BY meta_value DESC;
UPDATE `xyz_posts` p
INNER JOIN `temp_tbl` t ON p.post_content LIKE CONCAT('%',t.find_value,'%')
SET p.`post_content`=REPLACE(p.`post_content`,t.find_value,t.replace_value);
The first command will create a temporary table where the first column will be the value that you want to find and replace like index.php?topic=1234 and the second column will be the value you want to be replace with like finished-page
The second command will replace posts_content in xyz_posts taking the first column from temp_tbl and replacing it with the second column.
Below an sql fiddle where you can see the solution in action
http://sqlfiddle.com/#!9/7bce8c
Of course you should first create a copy of your database and try these commands to ensure everything works fine before trying it in your production database.

Related

How to delete a specific string value from multiple tables on phpmyadmin?

I had a customer that installed a malware plugin which has already been cleaned.
The problem now it that i have this string - https://https;//main.travelfornamewalking.ga/stat.js?s=newrq - on the 2000 posts I have on the webiste.
How can I delete this specific string on each post bulk?
Keep in mind I don't want to delete the content. The problem is the malware added a script with that link on all the entries of the wp_posts table.... :(
You have to find out the table and the column that contains the problem link.
Once you have found the table and the column, check how many rows are affected. This will also give you an overview of what you could replace the problem link with.
First, the most important thing: Make a copy of the table! If you make a wrong update, you will need it.
// Maybe just look for a part of the problem link, it could be here in another form or with other parameters, good for checking.
SELECT ColumName FROM TableName WHERE ColumName like '%main.travelfornamewalking.ga%'
To replace the problem link, use REPLACE(), e.g. overwrite with an empty string.
https://www.w3resource.com/mysql/string-functions/mysql-replace-function.php
REPLACE(str, find_string, replace_with) -> full text of problemlink with all parameters.
UPDATE TableName SET ColumName = REPLACE(ColumName, 'https://https;//main.travelfornamewalking.ga/stat.js?s=newrq', '')
-> Repeat the select and update for all forms of this problem link that you are replacing.

Search comma separated string using LIKE in mysql

I have a table with 3 columns something like below,
expert table
id - 1589
name - Jhonny
expert_in - 1,12,8 (Values similar like this)
The experts_in contains another table's foreign key
experts_in table
id - 1
expert_in - painting
I want search experts who are expert in some jobs while searching for experts
SELECT * FROM `experts` WHERE expert_in LIKE 1%
The above query brings all experts with 11,12,13...etc. I want only exact word. I know LIKE will bring all. Is there any way to achieve this without altering table. Thanks in advance.
You should use REGEXP. Try this query:
SELECT * FROM experts
WHERE expert_in REGEXP '[[:<:]]1[[:>:]]';
Output: See Live Demo on SQLFiddle
Note: You can adjust searching string based on your requirement above REGEXP is searching exact word.
if you can alter the data (not the table/schema) you should append and prepend another comma, so you can search with where col like "%,123,%", this will always fit on an exact value. Otherwise you have to use regex with something like ,?123,?

Simple MySQL LIKE not working as expected

I have a database of information about images. I need to allow users to search for file names that contain a user-specified character string. It's not working the way it appears it should.
For example, the database contains 27 records for files whose names begin with the letter 'b'.
If I execute (in PHPMyAdmin) the query:
SELECT * FROM image WHERE img_name LIKE '%b%';
I get a list of records whose file names contain the letter 'b' (as expected).
But only 4 of the 27 records for files starting with 'b' show up in that list.
Any idea what I'm missing?
After I posted the question, another possibility occurred to me, which turned out to be the solution.
I looked further into the database definition (I did not design it), and it uses varbinary(255) for img_name. If I change the query to:
SELECT * FROM `image` WHERE CONVERT(img_name USING latin1) LIKE '%b%'
I get all of the records that I expect.
You say that the ones that aren't showing up are ones that start with a 'b'.
This could be a case issue.
Convert the name to lower case like so
SELECT * FROM image WHERE strtolower(img_name) LIKE '%b%';

How to Bulk Update post titles wordpress through mySQL

All my post titles have a static word in front of them. I have over 9000 published posts with two different static words in my post titles. I am trying to remove this word from all my posts.
Essentially, I am looking for a way to remove that constant word. I tried using export through wordpress and editing the post titles that way, but the file was 100mb + and simply won't open.
I looked towards SQL/phpmyadmin but I am not very well versed with SQL queries and don't want to mess up my database.
The "Constant" is always the first word of the title. What could I do
to instead have mysql detect the first space and remove everything
before it as well as including the space. Essentially, removing the
first word. Basically I have more than one constant, so it would be
better if I could just find the first space in the string and then
remove it and everything before it. I'm assuming we'd use sub_string
or something.
This is the title structure
Constant other stuff here
so if there is a search query where it finds "Constant " and a space and replaces it with "" nothing, that way I could have it completely removed. It'd be great if it could be a search and replace query, so I could utilize it later.
Information on the Database / Table / Column
the table is called: wp_posts and it needs to be restricted to the value of the table post_type when it's value is post and the title is in the post_title column
Any help would be greatly appreciated.
MySQL doesn't have exactly what you're looking for -- yes, there is a REPLACE() string function, but you can't limit it to a single substitution. As such, you might inadvertently replace other occurrences of this constant that could conceivably appear in your title string.
IMHO, the easiest way is to find all titles starting with your constant, and just replace the first one (i.e. at the start of the string):
UPDATE wp_posts
SET post_title =
MID( post_title, LENGTH('Constant ')+1 )
WHERE post_title LIKE 'Constant %'
AND post_type = 'post';
You need the +1 because MySQL string offsets start at 1, not zero.
Personally, I always prefer to run the equivalent SELECT first, just to be certain (too many years of MyISAM without BEGIN WORK):
SELECT post_title,
MID( post_title, LENGTH('Constant ')+1 ) AS replacedTitle
FROM wp_posts
WHERE post_title LIKE 'Constant %'
AND post_type = 'post';
Alternatively, if you're certain that you always want to remove the first word (i.e. up to and including the first space), then the following statement should work:
UPDATE wp_posts
SET post_title =
MID( post_title, POSITION( ' ' IN post_title )+1 )
WHERE post_type = 'post';
Since POSITION() will return zero if no space is found, this statement will be a no-op (i.e. non-destructive) in the general case.
Search RegEx is a great plugin to be able to search and replace - with grep or plain text - through all post and page content, post titles, post meta, etc. Does not search custom post types.
Back up your DB before making any changes, either with this plugin or direct query in the database.
Docs: http://urbangiraffe.com/plugins/search-regex/

Using Like and Concat in MySQL query

I'm loading text files into my db and trying to do some quick matching between a table that lists names of organizations, and a table that holds the text file and potential matches to those organizations.
I load the file using LOAD INFILE CONCURRENT and don't have any problems with that.
The twist comes from the fact that the field I'm trying to match in the raw text table (occupationoraffiliation) has more than just organization names in it. So I'm trying to use LIKE with wildcards to match the strings.
To match the text, I'm trying to use this query:
UPDATE raw_faca JOIN orgs AS o
ON raw_faca.org_id IS NULL AND raw_faca.occupationoraffiliation LIKE CONCAT('%',o.org_name,'%')
SET raw_faca.org_id = o.org_id;
I've also tried without CONCAT:
UPDATE raw_faca JOIN orgs AS o
ON raw_faca.org_id IS NULL AND raw_faca.occupationoraffiliation LIKE ('%' + o.org_name + '%')
SET raw_faca.org_id = o.org_id;
The raw_faca table has ~40,000 rows and the orgs table has ~ 20,000 rows. I have indexes on all the The query has been running for a couple of hours or so -- this seems like way too long for the operation. Is the comparison I'm trying to run just that inefficient or am I doing something spectacularly stupid here? I was hoping to avoid going line-by-line with an external php or python script.
In response to comments below about using Match . . . Against, I've tried the following query as well:
UPDATE raw_faca JOIN orgs AS o ON raw_faca.org_id IS NULL AND MATCH(raw_faca.occupationoraffiliation) AGAINST (o.org_name IN NATURAL LANGUAGE MODE)
SET raw_faca.org_id = o.org_id;
And it's giving me this error:
incorrect arguments to AGAINST
Any thoughts?
A LIKE clause with a leading wild card is not going to be able to take advantage of any indexes.