10

For some reason while using PhpMyAdmin returns 90 rows when running:

SELECT COUNT(*) 
FROM le_wp_posts 
WHERE post_content LIKE '%Â%'

But the following updates 3 rows only:

UPDATE le_wp_posts 
SET post_content = REPLACE(post_content, 'Â', '') 
WHERE post_content LIKE '%Â%'

I have also tried it omitting the WHERE clause in the UPDATE statement. Is there any obvious reason I'm overlooking that's causing this issue? Or what steps can I take further to investigate the cause? My SQL is not the best.

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
rickyduck
  • 4,030
  • 14
  • 58
  • 93
  • Did you try using the select clause in the where condition : `WHERE post_content IN (SELECT distinct post_content FROM le_wp_posts WHERE post_content LIKE '%Â%')` – Patrick Sep 19 '16 at 22:20
  • @pat `#1093 - You can't specify target table 'le_wp_posts' for update in FROM clause ` is the result of `UPDATE le_wp_posts SET post_content = REPLACE(post_content, 'Â', '') WHERE post_content IN (SELECT distinct post_content FROM le_wp_posts WHERE post_content LIKE '%Â%')` – rickyduck Sep 19 '16 at 22:27
  • http://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause - check this out – Patrick Sep 19 '16 at 22:41
  • Dirty solution : UPDATE le_wp_posts SET post_content = REPLACE(post_content, 'Â', '') WHERE post_content IN (SELECT distinct post_content FROM (select * from le_wp_posts) as x WHERE post_content LIKE '%Â%') – Patrick Sep 19 '16 at 22:42
  • @Pat thanks, was looking at that as you posted. Returned 0 rows updated. I've even changed the connector charset to correlate to the server charset. I'm going to try a regex replacement – rickyduck Sep 19 '16 at 22:44
  • Just to be sure: have you checked that there are no triggers blocking your update on that table? – Jens Sep 22 '16 at 13:42
  • Maybe related to http://stackoverflow.com/questions/6482531/how-to-make-mysql-aware-of-multi-byte-characters-in-like-and-regexp – walen Sep 22 '16 at 13:47
  • @Jens ni triggers. @walen - so I tried `SELECT COUNT(*) FROM le_wp_posts where hex(post_content) rlike concat('(..)*', hex('Â'), '(..)*')` and got 0 rows, while my original select gets 90 – rickyduck Sep 22 '16 at 14:19
  • Shall I dump the DB so someone can test? – rickyduck Sep 22 '16 at 14:50
  • What is your charset? If you use e.g. `latin1`, `select * from le_wp_posts where post_content LIKE '%Â%'` will search for (and return) `A` and `a` too. Check your results if they actually use an `Â`. When you update the rows, you will get the number of actually changed rows. This is the expected behaviour. You can force a collation if you want. – Solarflare Sep 22 '16 at 15:39
  • Your `COUNT` query searches case-insensitive, as `LIKE` is (usually) case-insensitive. But pay attention to `REPLACE` being [case-sensitive](http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_replace) regarding the first parameter. So you might have some lower-case chars in there. You could dump the records that are returned by your first query and cross-check. – MicSim Sep 22 '16 at 15:55
  • What does the following query return `select post_content from le_wp_posts where replace(post_content, 'Â', '') like '%Â%'` ? – Paul Spiegel Sep 25 '16 at 20:11

8 Answers8

3

I did the following test...

1) Create a table with some data:

create table test(col varchar(10));

insert into test values ('abc'), ('dbe');

2) Select number of rows using your same filter (but different character):

select count(*)
from test
where col like '%B%' -- note the uppercase
;

Got the following result:

+----------+                                                                                                                                                                
| count(*) |                                                                                                                                                                
+----------+                                                                                                                                                                
|        2 |                                                                                                                                                                
+----------+ 

1 row in set

3) Tried your update:

update test 
set col = replace(col, 'B', '') -- note the uppercase
where col like '%B%' -- note the uppercase
;

And got this result:

Query OK, 0 rows affected (0.01 sec)                                                                                                                                        
Rows matched: 2  Changed: 0  Warnings: 0

In my case, a default character set and collation where used on table creation. The default character set was 'latin1' and collation 'latin1_swedish_ci'. Note the ci at the end of the collation.... it means case insensitive. So, the LIKE filter did a case insensitive search, found 2 rows, but the REPLACE function, as can be seen on documentation, is case sensitive. Probably, as in my case, the update found the same number of rows as in the select, but updated less data because of the case restriction on REPLACE.

If this is your problem, can't you just run two updates, one for the uppercase case and one for the lowercase? I'll try to develop a solution on one update...

The docs about the REPLACE(str, from_str, to_str) function:

Returns the string str with all occurrences of the string from_str replaced by the string to_str. REPLACE() performs a case-sensitive match when searching for from_str.

The docs about the LIKE operator:

The following two statements illustrate that string comparisons are not case sensitive unless one of the operands is a case sensitive (uses a case-sensitive collation or is a binary string):

The first example:

mysql> SELECT 'abc' LIKE 'ABC';
        -> 1

The second example:

mysql> SELECT 'abc' LIKE _latin1 'ABC' COLLATE latin1_general_cs;
        -> 0

Note the cs at the end of the collation. It means case sensitive.

Felypp Oliveira
  • 2,147
  • 1
  • 17
  • 17
  • "If this is your problem, can't you just run two updates, one for the uppercase case and one for the lowercase?" Probably will work for the one character but what about Title Case for long strings? – Matt Sep 29 '16 at 01:03
3

If you take a utf8-encoded £ (C2A3, treated as utf8) and store it into a latin1 column, when you read it back, you get £ (C2A3, treated as latin1). Removing the  will work for about 32 characters, but will fail for many other characters. And it will make the table harder to repair!

Let's look at an example of what you tried to store, together with the HEX of that ended up in the table. Also, let's look at SHOW CREATE TABLE to confirm my suspicion that the target it latin1.

This discusses the HEX debugging technique. And it discusses "Best Practice", which includes declaring, during the connection, that you really have utf8, not latin1. And it talks about "Mojibake", with an example of where ñ turns into ñ, making REPLACE a messy prospect.

Your symptom with LIKE is consistent with character set mismatches.

Community
  • 1
  • 1
Rick James
  • 135,179
  • 13
  • 127
  • 222
2

The LIKE is Case-insensitive but Replace is Case-sensitive, to bypass that use the following query:

UPDATE le_wp_posts 
SET post_content = REPLACE(LOWER(post_content), LOWER('Â'), '') 
WHERE post_content LIKE '%Â%'

OR if you want the final result not to be lower case:

UPDATE le_wp_posts 
SET post_content = REPLACE(REPLACE(post_content, LOWER('Â'), ''), 'Â', '') 
WHERE post_content LIKE '%Â%'
Amr Magdy
  • 1,710
  • 11
  • 13
  • Case insensitivity depends on the collation of the column. – Rick James Sep 26 '16 at 19:55
  • `LIKE` is either case-sensitive or case-insensitive, depending on the collation. (I'm quibbling with your first sentence.) In my answer, I don't see `LIKE` as having any relevance to the _real problem and solution_. – Rick James Sep 26 '16 at 22:36
1
--you just need to put N before string pattern too (if you want look for unicode char)*/
Update le_wp_posts
Set post_content=REPLACE(post_content,N'Â','')
where post_content like '%Â%'
Poonam
  • 669
  • 4
  • 14
0

Can you please try using JOIN as below:

UPDATE le_wp_posts l
INNER JOIN (SELECT t.post_content  
            FROM le_wp_posts t 
            WHERE t.post_content LIKE '%Â%') t ON l.post_content = t.post_content
SET l.post_content = REPLACE(l.post_content, 'Â', '')
Shushil Bohara
  • 5,556
  • 2
  • 15
  • 32
  • Ok there was an error in the query as `a` isn't a table, so I change `a.post_content` to `l.post_content` like so: `UPDATE le_wp_posts l INNER JOIN (SELECT t.post_content FROM le_wp_posts t WHERE t.post_content LIKE '%Â%') t ON l.post_content = t.post_content SET l.post_content = REPLACE(t.post_content, 'Â', '')` however 0 rows were effected again. This is bizzare – rickyduck Sep 20 '16 at 09:10
  • Updated please check it once again and thank you for reporting issue – Shushil Bohara Sep 20 '16 at 09:18
  • Error: Token mismatch now :( – rickyduck Sep 20 '16 at 09:55
0

If you have an "Id" you could try this way:

UPDATE le_wp_posts 
SET post_content = REPLACE(post_content, 'Â', '') 
WHERE Id IN ( SELECT * 
             FROM (
            SELECT Id 
            FROM le_wp_posts 
            WHERE post_content LIKE '%Â%'
                 ) as A
            )
genespos
  • 3,211
  • 6
  • 38
  • 70
0

I guess the update didn't occur from within PhpMyAdmin but from a client? If so it's just the differing locale settings.

Alim Özdemir
  • 2,396
  • 1
  • 24
  • 35
0
--Query first selects original column as well as replacement string and then update original column
Update Tbl1
Set Tbl1.post_content=Tbl2.Replacement
From le_wp_posts as Tbl1
Inner Join
(
    select post_content,REPLACE(post_content,'Â','') as Replacement
    from le_wp_posts
    where post_content like '%Â%'
) as Tbl2
On Tbl1.post_content=Tbl2.post_content
Poonam
  • 669
  • 4
  • 14