Заменить экземпляры старого домена новым во всей базе данных - PullRequest
0 голосов
/ 16 сентября 2018

У меня есть база данных MYSQL, которая содержит более 21500 экземпляров для старого домена, я хочу заменить старый домен на новый.

Я искал способ замены во всей БД инашел следующее:

Использование SQL:

create procedure replace_all(find varchar(255), 
        replce varchar(255), 
        indb varcv=char(255))
 DECLARE loopdone INTEGER DEFAULT 0;
 DECLARE currtable varchar(100);
 DECLARE alltables CURSOR FOR SELECT t.tablename, c.column_name 
    FROM information_schema.tables t,
    information_schema.columns c
    WHERE t.table_schema=indb
    AND c.table_schema=indb
    AND t.table_name=c.table_name;

 DECLARE CONTINUE HANDLER FOR NOT FOUND
     SET loopdone = 1;

 OPEN alltables;

 tableloop: LOOP
    FETCH alltables INTO currtable, currcol; 
    IF (loopdone>0) THEN LEAVE LOOP;
    END IF;
         SET stmt=CONCAT('UPDATE ', 
                  indb, '.', currtable, ' SET ',
                  currcol, ' = word_sub(\'', find, 
                  '\','\'', replce, '\') WHERE ',
                  currcol, ' LIKE \'%', find, '%\'');
         PREPARE s1 FROM stmt;
         EXECUTE s1;
         DEALLOCATE PREPARE s1;
     END LOOP;
 END //

И:

use information_schema;
set @q = 'Boston';
set @t = 'my_db';

select CONCAT('use \'',@q,'\';') as q UNION
select CONCAT('select \'', tbl.`TABLE_NAME`,'\' as TableName, \'', col.`COLUMN_NAME`,'\' as Col, `',col.`COLUMN_NAME`,'` as value  from `' , tbl.`TABLE_NAME`,'` where `' ,
        col.`COLUMN_NAME` , '` like \'%' ,@q,  '%\' UNION') AS q
from `tables` tbl
inner join `columns` col on tbl.`TABLE_NAME` = col.`TABLE_NAME`and col.DATA_TYPE='varchar'
where tbl.TABLE_SCHEMA  =  @t  ;

Также:

DROP PROCEDURE IF EXISTS findAll;
CREATE PROCEDURE `findAll`( IN `tableName` VARCHAR( 28 ) , IN `search` TEXT )
BEGIN
       DECLARE finished INT DEFAULT FALSE ;
       DECLARE columnName VARCHAR ( 28 ) ;
       DECLARE stmtFields TEXT ;
       DECLARE columnNames CURSOR FOR
              SELECT DISTINCT `COLUMN_NAME` FROM `information_schema`.`COLUMNS`
              WHERE `TABLE_NAME` = tableName ORDER BY `ORDINAL_POSITION` ;
       DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = TRUE;
       SET stmtFields = '' ;
       OPEN columnNames ;
       readColumns: LOOP
              FETCH columnNames INTO columnName ;
              IF finished THEN
                     LEAVE readColumns ;
              END IF;
              SET stmtFields = CONCAT(
                     stmtFields , IF ( LENGTH( stmtFields ) > 0 , ' OR' , ''  ) ,
                     ' `', tableName ,'`.`' , columnName , '` REGEXP "' , search , '"'
              ) ;
       END LOOP;
       SET @stmtQuery := CONCAT ( 'SELECT * FROM `' , tableName , '` WHERE ' , stmtFields ) ;
       PREPARE stmt FROM @stmtQuery ;
       EXECUTE stmt ;
       CLOSE columnNames ;
END;

С PHP:

// Connect to your MySQL database.
$hostname = "hostname";
$username = "username";
$password = "password";
$database = "database";

mysql_connect($hostname, $username, $password);

// The find and replace strings.
$find = "old domain";
$replace = "new domain";

$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']);
}

Но большинство этих фрагментов, похоже, не завершены / не работают.

Итак, как обновить старый домен, скажем, olddomain.com с newdomain.com?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

Как упомянуто в комментариях @dnFer, дамп db заменяет строку и импортирует ее снова.

Это может быть легко написано с помощью пары строк bash, например:

#!/bin/bash

DB_USER="..."
DB_PASS="..."
DB_BASE="..."

DUMP=$(mysqldump --add-drop-table --user="$DB_USER" --password="$DB_PASS" $DB_BASE)

echo "${DUMP/olddomain.com/newdomain.com}" | mysql --user="$DB_USER" --password="$DB_PASS" $DB_BASE

Очевидно, что сначала нужно сделать резервную копию, вы делаете резервные копии, верно?

0 голосов
/ 16 сентября 2018

С уважением, то, как вы надеетесь выполнить эту задачу, пугает меня до чертиков.У вас есть ценные данные, которые накапливаются за период, без сомнения, лет, и вы надеетесь заменить их на глобальном уровне?Вы могли бы это сильно испортить.

Было бы намного мудрее найти таблицы и столбцы, которые нужно изменить, просмотреть их, а затем менять их по одному.В принципе, довольно просто обновлять URL-адреса в столбцах.Что-то вроде этого должно сделать это.

 UPDATE table 
    SET link = REPLACE(link, 'https://former.example.com', 'https://new.example.com')
  WHERE link like CONCAT('%','https://former.example.com','%')

Обратите внимание, что эта замена заменяет ссылки https на имя конкретного хоста / домена.Это не очень беспорядочная стратегия замены:

  • она не изменит данные, если это не https url
  • , она обновляет только те строки, которые необходимо обновить (из-за предложения WHERE)
  • он только обновляет таблицу и столбец, который вы хотите обновить.

Если ваши таблицы были созданы с помощью php, вы должны быть осторожны.Некоторые столбцы в вашей базе данных могут содержать сериализованные данные php - вывод serialize().Несмотря на то, что разработчики баз данных ограничиваются базами данных с сериализованными данными, хранящимися в столбцах базы данных, это распространено.(WordPress делает это в таблице wp_options, например).

Проблема заключается в следующем:

 $links = array(
    'top' => 'https://former.example.com/index.php'
  );
 $serial = serialize($links);

помещает это в $serial, кодируя длину строки (s:36").

 a:2:{s:3:"top";s:36:"https://former.example.com/index.php";}

И если вы просто измените URL в этих сериализованных данных, вы измените фактическую длину строки без изменения закодированной длины.Это портит сериализованные данные.(Размус Лердорф и другие авторы php выбрали хороший формат сериализованных данных? Это разговор на другой день).

Так что, если вы собираетесь обновить сериализованные текстовые строки в вашей базе данных с помощью MySQL REPLACE() или чего-то подобного, вы не сможете изменить его длину.

Моя точка зрения: понять, чтоВы обновляете его перед обновлением.

Вы можете запросить information_schema.COLUMNS, чтобы написать список запросов, которые будут искать текстовую строку, которую вы хотите изменить, во всех ваших столбцах.

SET @string = 'former.example.com';

SELECT CONCAT(
      'SELECT COUNT(*) FREQUENCY ,', 
      COLUMN_NAME, ' ''VALUE'', ',
        '''',  TABLE_NAME , ''' TABLE_NAME, ', 
       '''',  COLUMN_NAME ,''' COLUMN_NAME ', 
        'FROM ',TABLE_NAME,' ',
      'WHERE ', COLUMN_NAME,' LIKE ''%', @string, '%'' ',
      'GROUP BY ', COLUMN_NAME, ' ORDER BY 1 DESC'
          )   query
  FROM information_schema.COLUMNS
 WHERE TABLE_SCHEMA = DATABASE()
   AND DATA_TYPE = 'varchar'

Затем вы можете просмотреть каждый столбец в каждой таблице, содержащей строку, которую вы хотите заменить.Только тогда вы можете быть уверены, что замените его правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...