I am dealing with phone system and have to work with multiple service vendors. For one vendor I have a MySQL table country_codes
like this -
--
If you need to do the fix the data ONLY once, you can try this approach:
0) Backup your data, or better, run the query on copy of the data.
1) Creates a table that contains non-zero country codes. We need separate table because it says in MySQL manual that:
Currently, you cannot update a table and select from the same table in a subquery.
CREATE TABLE country_codes_list (
country_code INT NOT NULL PRIMARY KEY
);
INSERT INTO country_codes_list
SELECT country_code
FROM country_codes
WHERE country_code <> 0;
2) Update all rows where country code is 0 by finding the country code that matches the beginning of the area code:
UPDATE country_codes AS country_codes_zero SET country_code = (
SELECT country_code
FROM country_codes_list
WHERE country_codes_list.country_code = SUBSTRING(country_codes_zero.area_code, 1, LENGTH(country_codes_list.country_code))
) WHERE country_code = 0;
This could be a very slow query because it uses a co-related sub-query. But it should fix the data in one go.
Something like this should work, assuming you have a database called "testdb", and a table called "footable".
$link = mysql_connect("localhost", "username", "password1234");
mysql_select_db("testdb", $link);
$result = mysql_query("UPDATE footable SET country_code="93" WHERE country LIKE Afghanistan%", $link);
$result = mysql_query("UPDATE footable SET country_code="355" WHERE country LIKE Albania%", $link);
mysql_close($link);
You can create a table with countries
only, i.e.:
INSERT INTO countries (country_code,country)
SELECT country_code,country FROM country_codes WHERE country_code=0
Then you can easily update your table
UPDATE country_codes cc, countries c
SET cc.country_code = c.country_code
WHERE LOCATE(c.country,cc.country)=1 AND cc.country_code=0
I haven't tested this, but I believe you can get the point.
update cc set
country_code = t.country_code
from country_codes cc
join (
select country_code, country, char_length(trim(cast(country_code as char))) as code_len
from country_codes
where country_code <> 0
) t on
t.country_code = cast(substr(cast(cc.area_code as char), 1, t.code_len) as signed integer) and
cc.country_code = 0 and
cc.country like concat(t.country, '%')
I've added cc.country like concat(t.country, '%')
to condition to be more specific but it assumes that each cellular network name starts with its country name - so if it's not true omit it.
Added after @Sachyn comment:
Test code used on SQLZOO works fine, it is for testing only, it's not an update query:
select cc.*, t.country_code as new_country_code
from (
select 93 as country_code, 93 as area_code , 'Afghanistan' as country union
select 0 , 9375 , 'Afghanistan Cellular-AT' union
select 0 , 9370 , 'Afghanistan Cellular-AWCC' union
select 355, 355 , 'Albania' union
select 0 , 35568, 'Albania Cellular-AMC' union
select 0 , 35567, 'Albania Cellular-Eagle' union
select 213, 213 , 'Algeria' union
select 0 , 21377, 'Algeria Cellular-Djezzy' union
select 0 , 2135 , 'Algeria Cellular-Wataniya'
) cc
join (
select country_code, country, char_length(rtrim(cast(country_code as char))) as code_len
from (
select 93 as country_code, 93 as area_code , 'Afghanistan' as country union
select 0 , 9375 , 'Afghanistan Cellular-AT' union
select 0 , 9370 , 'Afghanistan Cellular-AWCC' union
select 355, 355 , 'Albania' union
select 0 , 35568, 'Albania Cellular-AMC' union
select 0 , 35567, 'Albania Cellular-Eagle' union
select 213, 213 , 'Algeria' union
select 0 , 21377, 'Algeria Cellular-Djezzy' union
select 0 , 2135 , 'Algeria Cellular-Wataniya'
) c
where country_code <> 0
) t on
t.country_code = cast(substr(cast(cc.area_code as char), 1, t.code_len) as signed integer) and
cc.country_code = 0 and
cc.country like concat(t.country, '%')
Try this query -
UPDATE country_codes
SET country_code := @c := IF(@c IS NOT NULL AND country_code = 0, @c, country_code)
ORDER BY CAST(area_code AS CHAR)