SQLite3를 MySQL로 마이그레이션하는 가장 쉬운 방법은 무엇입니까? [닫은]


224

누구나 SQLite3 데이터베이스를 MySQL로 마이그레이션하는 빠르고 쉬운 방법을 알고 있습니까?

답변:


62

다음은 변환기 목록입니다 (2011 년 이후 업데이트되지 않음).


잘 작동하지만 거의 언급되지 않는 대체 방법은 다음과 같습니다. 특정 데이터베이스 차이점을 추상화하는 ORM 클래스를 사용하십시오. 예를 들어 PHP ( RedBean ), Python (Django의 ORM 레이어, Storm , SqlAlchemy ), Ruby on Rails ( ActiveRecord ), Cocoa ( CoreData )에서 얻을 수 있습니다

즉, 당신은 이것을 할 수 있습니다 :

  1. ORM 클래스를 사용하여 소스 데이터베이스에서 데이터를로드하십시오.
  2. 데이터를 메모리에 저장하거나 디스크에 직렬화하십시오.
  3. ORM 클래스를 사용하여 대상 데이터베이스에 데이터를 저장하십시오.

107

모두가 몇 가지 grep과 perl 표현으로 시작하는 것처럼 보이며 특정 데이터 세트에 적합한 것을 얻지 만 데이터를 올바르게 가져 왔는지 여부는 알 수 없습니다. 아무도이 둘 사이를 변환 할 수있는 견고한 라이브러리를 만들지 않은 것에 놀랐습니다.

다음은 두 파일 형식 사이에서 알고있는 SQL 구문의 모든 차이점 목록입니다.

  • 거래 시작
  • 범하다
  • sqlite_sequence
  • 고유 인덱스 생성

MySQL에서는 사용되지 않습니다

  • SQLlite 사용 CREATE TABLE/INSERT INTO "table_name"및 MySQL 사용CREATE TABLE/INSERT INTO table_name
  • MySQL은 스키마 정의 안에 따옴표를 사용하지 않습니다
  • MySQL은 INSERT INTO절 내부의 문자열에 작은 따옴표를 사용 합니다
  • SQLlite와 MySQL은 INSERT INTO절 내부에서 문자열을 이스케이프하는 방법이 다릅니다.
  • SQLlite 사용 't''f'부울, MySQL의 용도 10(당신이 같은 문자열이있을 때 이것에 대한 간단한 정규식이 실패 할 수 있습니다 : t '당신의 내부에'당신은 \ 돈 내가 않는 '를 INSERT INTO)
  • SQLLite 사용 AUTOINCREMENT, MySQL 사용AUTO_INCREMENT

여기 데이터 세트에서 작동 하고 웹에서 찾은 다른 perl 스크립트보다 많은 조건을 확인 하는 매우 기본적인 해킹 된 perl 스크립트가 있습니다 . Nu는 귀하의 데이터에 적합하지만 여기에 자유롭게 수정하고 게시 할 것을 보증합니다.

#! /usr/bin/perl

while ($line = <>){
    if (($line !~  /BEGIN TRANSACTION/) && ($line !~ /COMMIT/) && ($line !~ /sqlite_sequence/) && ($line !~ /CREATE UNIQUE INDEX/)){

        if ($line =~ /CREATE TABLE \"([a-z_]*)\"(.*)/i){
            $name = $1;
            $sub = $2;
            $sub =~ s/\"//g;
            $line = "DROP TABLE IF EXISTS $name;\nCREATE TABLE IF NOT EXISTS $name$sub\n";
        }
        elsif ($line =~ /INSERT INTO \"([a-z_]*)\"(.*)/i){
            $line = "INSERT INTO $1$2\n";
            $line =~ s/\"/\\\"/g;
            $line =~ s/\"/\'/g;
        }else{
            $line =~ s/\'\'/\\\'/g;
        }
        $line =~ s/([^\\'])\'t\'(.)/$1THIS_IS_TRUE$2/g;
        $line =~ s/THIS_IS_TRUE/1/g;
        $line =~ s/([^\\'])\'f\'(.)/$1THIS_IS_FALSE$2/g;
        $line =~ s/THIS_IS_FALSE/0/g;
        $line =~ s/AUTOINCREMENT/AUTO_INCREMENT/g;
        print $line;
    }
}


완전한 python 스크립트를 추가했습니다 (perl 스크립트만으로는 저에게는 효과가 없었습니다. 외래 키 및 인덱스를 처리하기 위해 추가 처리가 필요했습니다)
Jiaaro


2
COMMITCREATE UNIQUE INDEX 는 유효한 MySQL 명령이므로 수정하십시오.
niutech

5
그래서 여기에 몇 가지 추가 / 버그 수정의, 스크립트가 매우 유용 또한 "신속하고 더러운"하지만 이해 : * 후 && ($line !~ /CREATE UNIQUE INDEX/)추가 && ($line !~ /PRAGMA foreign_keys=OFF/) * 대신에있는 테이블 이름 일치 정규식 미스 자리, $line =~ /INSERT INTO \"([a-z_]*)\"(.*)/거기가 있어야합니다 $line =~ /INSERT INTO \"([a-z_1-9]*)\"(.*)/ 희망이 미래를하는 데 도움이 독자
Michał Leon

50

다음은 Shalmanese의 답변으로 작성된 Python 스크립트와 Alex Pertelli의 번역을 Perl에서 Python으로

커뮤니티 위키를 만들고 있으므로 기능을 위반하지 않는 한 자유롭게 편집하고 리팩토링하십시오 (감사하게 롤백 할 수 있음)-꽤 추악하지만 작동합니다.

다음과 같이 사용하십시오 (스크립트가 있다고 가정하면 dump_for_mysql.py:

sqlite3 sample.db .dump | python dump_for_mysql.py > dump.sql

그런 다음 mysql로 ​​가져올 수 있습니다

참고-sqlite는 실제로 외래 키 제약 조건을 지원하지 않으므로 외래 키 제약 조건을 수동으로 추가해야합니다

여기 스크립트가 있습니다 :

#!/usr/bin/env python

import re
import fileinput

def this_line_is_useless(line):
    useless_es = [
        'BEGIN TRANSACTION',
        'COMMIT',
        'sqlite_sequence',
        'CREATE UNIQUE INDEX',
        'PRAGMA foreign_keys=OFF',
    ]
    for useless in useless_es:
        if re.search(useless, line):
            return True

def has_primary_key(line):
    return bool(re.search(r'PRIMARY KEY', line))

searching_for_end = False
for line in fileinput.input():
    if this_line_is_useless(line):
        continue

    # this line was necessary because '');
    # would be converted to \'); which isn't appropriate
    if re.match(r".*, ''\);", line):
        line = re.sub(r"''\);", r'``);', line)

    if re.match(r'^CREATE TABLE.*', line):
        searching_for_end = True

    m = re.search('CREATE TABLE "?(\w*)"?(.*)', line)
    if m:
        name, sub = m.groups()
        line = "DROP TABLE IF EXISTS %(name)s;\nCREATE TABLE IF NOT EXISTS `%(name)s`%(sub)s\n"
        line = line % dict(name=name, sub=sub)
    else:
        m = re.search('INSERT INTO "(\w*)"(.*)', line)
        if m:
            line = 'INSERT INTO %s%s\n' % m.groups()
            line = line.replace('"', r'\"')
            line = line.replace('"', "'")
    line = re.sub(r"([^'])'t'(.)", "\1THIS_IS_TRUE\2", line)
    line = line.replace('THIS_IS_TRUE', '1')
    line = re.sub(r"([^'])'f'(.)", "\1THIS_IS_FALSE\2", line)
    line = line.replace('THIS_IS_FALSE', '0')

    # Add auto_increment if it is not there since sqlite auto_increments ALL
    # primary keys
    if searching_for_end:
        if re.search(r"integer(?:\s+\w+)*\s*PRIMARY KEY(?:\s+\w+)*\s*,", line):
            line = line.replace("PRIMARY KEY", "PRIMARY KEY AUTO_INCREMENT")
        # replace " and ' with ` because mysql doesn't like quotes in CREATE commands 
        if line.find('DEFAULT') == -1:
            line = line.replace(r'"', r'`').replace(r"'", r'`')
        else:
            parts = line.split('DEFAULT')
            parts[0] = parts[0].replace(r'"', r'`').replace(r"'", r'`')
            line = 'DEFAULT'.join(parts)

    # And now we convert it back (see above)
    if re.match(r".*, ``\);", line):
        line = re.sub(r'``\);', r"'');", line)

    if searching_for_end and re.match(r'.*\);', line):
        searching_for_end = False

    if re.match(r"CREATE INDEX", line):
        line = re.sub('"', '`', line)

    if re.match(r"AUTOINCREMENT", line):
        line = re.sub("AUTOINCREMENT", "AUTO_INCREMENT", line)

    print line,

2
안녕 Jim, 내 데이터 세트에서 모든 첫 번째 INSERT 문은 작은 따옴표 대신 백 따옴표로 묶습니다. __ DROP TABLE IF EXISTS schema_migrations; 존재하지 않는 테이블 작성 schema_migrations( versionvarchar (255) NOT NULL); INSERT INTO schema_migrations VALUES ( 20100714032840); INSERT INTO schema_migrations VALUES ( '20100714033251'); __
David

음 ... 위에 표시되지는 않지만 따옴표 안에 역 따옴표가 나타납니다 ([HERE] 20100714032840 [/ HERE])
David

1
Mysql의 AUTOINCREMENT는 AUTO_INCREMENT입니다. 스크립트는이를 설명하지 않습니다.
주세페

미디어 위키 데이터베이스에는 작동하지 않습니다. 많은 오류 : Blobvar데이터 유형, CREATE 문의
백틱

1
작동하지 않습니다. 모든 조건은 ... 고려되어 있지 수 있습니다
Himanshu 반살에게

10

아마도 가장 빠른 방법은 sqlite .dump 명령을 사용하는 것입니다.이 경우 샘플 데이터베이스의 덤프를 작성하십시오.

sqlite3 sample.db .dump > dump.sql

그런 다음 이론적으로 이것을 사용자 루트를 사용하여 mysql 데이터베이스 (이 경우 데이터베이스 서버 127.0.0.1의 테스트 데이터베이스)로 가져올 수 있습니다.

mysql -p -u root -h 127.0.0.1 test < dump.sql

문법에는 약간의 차이가 있기 때문에 이론적으로 말합니다.

sqlite 거래에서 시작

BEGIN TRANSACTION;
...
COMMIT;

MySQL은 단지 사용

BEGIN;
...
COMMIT;

다른 유사한 문제 (varchars 및 큰 따옴표가 떠 올랐습니다)가 있지만 찾아서 바꿀 수있는 것은 없습니다.

성능 / 데이터베이스 크기가 문제인 경우 스키마를 다시 살펴 보는 것이 좋습니다. 시스템이보다 강력한 제품으로 이동하는 경우 데이터의 미래를 계획하기에 이상적인 시간 일 수 있습니다.


2
그러나 가장 어려운 일은 베트 위크 문법의 차이입니다.
francois


8
aptitude install sqlfairy libdbd-sqlite3-perl

sqlt -f DBI --dsn dbi:SQLite:../.open-tran/ten-sq.db -t MySQL --add-drop-table > mysql-ten-sq.sql
sqlt -f DBI --dsn dbi:SQLite:../.open-tran/ten-sq.db -t Dumper --use-same-auth > sqlite2mysql-dumper.pl
chmod +x sqlite2mysql-dumper.pl
./sqlite2mysql-dumper.pl --help
./sqlite2mysql-dumper.pl --add-truncate --mysql-loadfile > mysql-dump.sql
sed -e 's/LOAD DATA INFILE/LOAD DATA LOCAL INFILE/' -i mysql-dump.sql

echo 'drop database `ten-sq`' | mysql -p -u root
echo 'create database `ten-sq` charset utf8' | mysql -p -u root
mysql -p -u root -D ten-sq < mysql-ten-sq.sql
mysql -p -u root -D ten-sq < mysql-dump.sql

7

방금이 과정을 거쳤으며이 Q / A에는 매우 유용한 도움말과 정보가 많이 있지만 작업 솔루션을 얻기 위해 다양한 요소 (다른 Q / A의 일부)를 함께 가져와야한다는 것을 알았습니다. 성공적으로 마이그레이션합니다.

그러나 기존 답변을 결합한 후에도 INSERT에서 여러 부울이 발생하는 곳에서는 작동하지 않으므로 Python 스크립트가 제대로 작동하지 않는 것으로 나타났습니다. 보다그 이유를 여기에서 .

그래서 여기에 병합 된 답변을 게시 할 것이라고 생각했습니다. 신용은 물론 다른 곳에 기여한 사람들에게 간다. 그러나 나는 무언가를 돌려주고 싶었고 다른 사람들이 따르는 시간을 절약하고 싶었습니다.

아래에 스크립트를 게시하겠습니다. 그러나 먼저 전환에 대한 지침은 다음과 같습니다.

OS X 10.7.5 Lion에서 스크립트를 실행했습니다. 파이썬은 기본적으로 작동했습니다.

기존 SQLite3 데이터베이스에서 MySQL 입력 파일을 생성하려면 다음과 같이 자신의 파일에서 스크립트를 실행하십시오.

Snips$ sqlite3 original_database.sqlite3 .dump | python ~/scripts/dump_for_mysql.py > dumped_data.sql

그런 다음 결과 dumped_sql.sql 파일을 MySQL 데이터베이스가 상주하는 Ubuntu 10.04.4 LTS를 실행하는 Linux 상자에 복사했습니다.

MySQL 파일을 가져올 때 발생하는 또 다른 문제는 일부 유니 코드 UTF-8 문자 (특히 작은 따옴표)를 올바르게 가져 오지 못했기 때문에 UTF-8을 지정하기 위해 명령에 스위치를 추가해야했습니다.

빈 새 MySQL 데이터베이스에 데이터를 입력하는 결과 명령은 다음과 같습니다.

Snips$ mysql -p -u root -h 127.0.0.1 test_import --default-character-set=utf8 < dumped_data.sql

요리하자, 그게 다야! 전후에 데이터를 면밀히 조사하는 것을 잊지 마십시오.

따라서 OP가 요청한대로 방법을 알면 쉽고 빠릅니다. :-)

따로,이 마이그레이션을 살펴보기 전에 확실하지 않은 한 가지 사항은 created_at 및 updated_at 필드 값이 보존되는지 여부입니다. 나에게 반가운 소식은 기존 프로덕션 데이터를 마이그레이션 할 수 있다는 것입니다.

행운을 빕니다!

최신 정보

이 스위치를 만든 이후로, 이전에는 눈치 채지 못했던 문제를 발견했습니다. Rails 애플리케이션에서 텍스트 필드는 'string'으로 정의되며 데이터베이스 스키마로 전달됩니다. 여기에 요약 된 프로세스는 MySQL 데이터베이스에서 VARCHAR (255)로 정의됩니다. 이렇게하면 필드 크기가 255 자로 제한되며 가져 오는 동안이 범위를 넘어서는 것은 자동으로 잘립니다. 255보다 긴 텍스트 길이를 지원하려면 MySQL 스키마가 VARCHAR (255) 대신 'TEXT'를 사용해야합니다. 여기에 정의 된 프로세스에는이 변환이 포함되지 않습니다.


내 데이터에서 작동하는 병합 및 수정 된 Python 스크립트는 다음과 같습니다.

#!/usr/bin/env python

import re
import fileinput

def this_line_is_useless(line):
    useless_es = [
        'BEGIN TRANSACTION',
        'COMMIT',
        'sqlite_sequence',
        'CREATE UNIQUE INDEX',        
        'PRAGMA foreign_keys=OFF'
        ]
    for useless in useless_es:
        if re.search(useless, line):
            return True

def has_primary_key(line):
    return bool(re.search(r'PRIMARY KEY', line))

searching_for_end = False
for line in fileinput.input():
    if this_line_is_useless(line): continue

    # this line was necessary because ''); was getting
    # converted (inappropriately) to \');
    if re.match(r".*, ''\);", line):
        line = re.sub(r"''\);", r'``);', line)

    if re.match(r'^CREATE TABLE.*', line):
        searching_for_end = True

    m = re.search('CREATE TABLE "?([A-Za-z_]*)"?(.*)', line)
    if m:
        name, sub = m.groups()
        line = "DROP TABLE IF EXISTS %(name)s;\nCREATE TABLE IF NOT EXISTS `%(name)s`%(sub)s\n"
        line = line % dict(name=name, sub=sub)
        line = line.replace('AUTOINCREMENT','AUTO_INCREMENT')
        line = line.replace('UNIQUE','')
        line = line.replace('"','')
    else:
        m = re.search('INSERT INTO "([A-Za-z_]*)"(.*)', line)
        if m:
            line = 'INSERT INTO %s%s\n' % m.groups()
            line = line.replace('"', r'\"')
            line = line.replace('"', "'")
            line = re.sub(r"(?<!')'t'(?=.)", r"1", line)
            line = re.sub(r"(?<!')'f'(?=.)", r"0", line)

    # Add auto_increment if it's not there since sqlite auto_increments ALL
    # primary keys
    if searching_for_end:
        if re.search(r"integer(?:\s+\w+)*\s*PRIMARY KEY(?:\s+\w+)*\s*,", line):
            line = line.replace("PRIMARY KEY", "PRIMARY KEY AUTO_INCREMENT")
        # replace " and ' with ` because mysql doesn't like quotes in CREATE commands

    # And now we convert it back (see above)
    if re.match(r".*, ``\);", line):
        line = re.sub(r'``\);', r"'');", line)

    if searching_for_end and re.match(r'.*\);', line):
        searching_for_end = False

    if re.match(r"CREATE INDEX", line):
        line = re.sub('"', '`', line)

    print line,

1
감사. 현재 위에 작성된 스크립트에는 구문 오류가 있습니다. 41 행의 "else :"가 적절한 들여 쓰기 레벨이 아닙니다. 위의 줄이 들여 쓰기되어야하는지 또는 다른 일이 진행되고 있는지 명확하지 않습니다. 업데이트 하시겠습니까?
Dan Tenenbaum


5

최근 우리 팀이 작업중인 프로젝트를 위해 MySQL에서 JavaDB로 마이그레이션해야했습니다. Apache가 작성한 DdlUtils라는 Java 라이브러리를 찾았습니다 . 다음을 수행 할 수있는 API를 제공합니다.

  1. 데이터베이스의 스키마를 발견하고 XML 파일로 내보내십시오.
  2. 이 스키마를 기반으로 DB를 수정하십시오.
  3. 동일한 스키마를 가지고 있다고 가정하면 한 DB에서 다른 DB로 레코드를 가져옵니다.

우리가 사용했던 도구는 완전히 자동화되지는 않았지만 꽤 잘 작동했습니다. 애플리케이션이 Java가 아니더라도 일회성 마이그레이션을 수행하기 위해 몇 가지 작은 도구를 준비하는 것이 어렵지 않아야합니다. 150 줄 미만의 코드로 마이그레이션을 시작할 수 있다고 생각합니다.


4

스크립트, 명령 등이 필요하지 않습니다.

sqlite 데이터베이스를 .csv파일로 내보내고 phpmyadmin을 사용하여 Mysql로 ​​가져와야합니다.

나는 그것을 사용했고 훌륭하게 일했다 ...


이것 과 함께 , 이것은 나를 위해 일한 유일한 대답입니다.
cdauth

3

Jims의 솔루션을 기반으로 : SQLite3를 MySQL로 마이그레이션하는 빠른 방법?

sqlite3 your_sql3_database.db .dump | python ./dump.py > your_dump_name.sql
cat your_dump_name.sql | sed '1d' | mysql --user=your_mysql_user --default-character-set=utf8 your_mysql_db -p  

이것은 나를 위해 작동합니다. 나는 sed를 사용하여 mysql과 같은 첫 번째 줄을 던지지 만 dump.py 스크립트를 수정 하여이 줄을 버릴 수도 있습니다.


1
가져온 데이터에 UTF-8 인코딩 문제가 있었지만 import 명령에 --default-character-set = utf8을 추가하면 문제가 해결 된 것으로 보입니다. 이 Q / A에서 가져온 것 : stackoverflow.com/questions/346092/…
Snips

좋아, 나는 이것을 추가했다-괜찮습니까?
alekwisnia

내가 여분의 스위치를 사용하고있는 곳이다.
Snips

3

SQL 덤프 받기

moose@pc08$ sqlite3 mySqliteDatabase.db .dump > myTemporarySQLFile.sql

MySQL로 덤프 가져 오기

소량 수입의 경우 :

moose@pc08$ mysql -u <username> -p
Enter password:
....
mysql> use somedb;
Database changed
mysql> source myTemporarySQLFile.sql;

또는

mysql -u root -p somedb < myTemporarySQLFile.sql

암호를 묻는 메시지가 나타납니다. 참고 : 비밀번호를 직접 입력하려면 다음과 같이 공백없이 비밀번호를 직접 입력해야합니다 -p.

mysql -u root -pYOURPASS somedb < myTemporarySQLFile.sql

큰 덤프의 경우 :

mysqlimport 또는 BigDump 와 같은 다른 가져 오기 도구 .

BigDump는 진행률 표시 줄을 제공합니다.

여기에 이미지 설명을 입력하십시오


12
sqlite와 mysql의 구문 차이와 플래그가 약간 다르기 때문에 작동하지 않습니다. 여전히 수동으로 변환해야합니다.
dlite922

1

하 ... 이걸 먼저 찾았 으면 좋겠다! 이 게시물에 대한 응답은 ... mysql 덤프 SQL 파일을 sqlite3 db로 가져올 수있는 형식으로 변환하는 스크립트

이 두 가지를 결합하면 정확히 필요한 것입니다.


sqlite3 데이터베이스를 루비와 함께 사용하려는 경우 다음을 변경하려고 할 수 있습니다.

tinyint([0-9]*) 

에:

sed 's/ tinyint(1*) / boolean/g ' |
sed 's/ tinyint([0|2-9]*) / integer /g' |

아아,이 절반은 작동합니다 .1과 0을 부울로 표시된 필드에 삽입하더라도 sqlite3은 1과 0으로 저장하므로 다음과 같이 수행해야합니다.

Table.find(:all, :conditions => {:column => 1 }).each { |t| t.column = true }.each(&:save)
Table.find(:all, :conditions => {:column => 0 }).each { |t| t.column = false}.each(&:save)

그러나 모든 부울을 찾기 위해 SQL 파일을 보는 것이 도움이되었습니다.


1

이 간단한 스크립트를 Python3으로 작성했습니다. 포함 된 클래스 또는 터미널 쉘을 통해 호출 된 독립형 스크립트로 사용될 수 있습니다. 기본적으로 모든 정수를 int(11)문자열로 가져오고varchar(300) 오지만 생성자 또는 스크립트 인수에서 각각 조정할 수 있습니다.

참고 : MySQL Connector / Python 2.0.4 이상이 필요합니다

아래 코드를 읽기 어려운 경우 GitHub의 소스에 대한 링크는 다음과 같습니다. https://github.com/techouse/sqlite3-to-mysql

#!/usr/bin/env python3

__author__ = "Klemen Tušar"
__email__ = "techouse@gmail.com"
__copyright__ = "GPL"
__version__ = "1.0.1"
__date__ = "2015-09-12"
__status__ = "Production"

import os.path, sqlite3, mysql.connector
from mysql.connector import errorcode


class SQLite3toMySQL:
    """
    Use this class to transfer an SQLite 3 database to MySQL.

    NOTE: Requires MySQL Connector/Python 2.0.4 or higher (https://dev.mysql.com/downloads/connector/python/)
    """
    def __init__(self, **kwargs):
        self._properties = kwargs
        self._sqlite_file = self._properties.get('sqlite_file', None)
        if not os.path.isfile(self._sqlite_file):
            print('SQLite file does not exist!')
            exit(1)
        self._mysql_user = self._properties.get('mysql_user', None)
        if self._mysql_user is None:
            print('Please provide a MySQL user!')
            exit(1)
        self._mysql_password = self._properties.get('mysql_password', None)
        if self._mysql_password is None:
            print('Please provide a MySQL password')
            exit(1)
        self._mysql_database = self._properties.get('mysql_database', 'transfer')
        self._mysql_host = self._properties.get('mysql_host', 'localhost')

        self._mysql_integer_type = self._properties.get('mysql_integer_type', 'int(11)')
        self._mysql_string_type = self._properties.get('mysql_string_type', 'varchar(300)')

        self._sqlite = sqlite3.connect(self._sqlite_file)
        self._sqlite.row_factory = sqlite3.Row
        self._sqlite_cur = self._sqlite.cursor()

        self._mysql = mysql.connector.connect(
            user=self._mysql_user,
            password=self._mysql_password,
            host=self._mysql_host
        )
        self._mysql_cur = self._mysql.cursor(prepared=True)
        try:
            self._mysql.database = self._mysql_database
        except mysql.connector.Error as err:
            if err.errno == errorcode.ER_BAD_DB_ERROR:
                self._create_database()
            else:
                print(err)
                exit(1)

    def _create_database(self):
        try:
            self._mysql_cur.execute("CREATE DATABASE IF NOT EXISTS `{}` DEFAULT CHARACTER SET 'utf8'".format(self._mysql_database))
            self._mysql_cur.close()
            self._mysql.commit()
            self._mysql.database = self._mysql_database
            self._mysql_cur = self._mysql.cursor(prepared=True)
        except mysql.connector.Error as err:
            print('_create_database failed creating databse {}: {}'.format(self._mysql_database, err))
            exit(1)

    def _create_table(self, table_name):
        primary_key = ''
        sql = 'CREATE TABLE IF NOT EXISTS `{}` ( '.format(table_name)
        self._sqlite_cur.execute('PRAGMA table_info("{}")'.format(table_name))
        for row in self._sqlite_cur.fetchall():
            column = dict(row)
            sql += ' `{name}` {type} {notnull} {auto_increment}, '.format(
                name=column['name'],
                type=self._mysql_string_type if column['type'].upper() == 'TEXT' else self._mysql_integer_type,
                notnull='NOT NULL' if column['notnull'] else 'NULL',
                auto_increment='AUTO_INCREMENT' if column['pk'] else ''
            )
            if column['pk']:
                primary_key = column['name']
        sql += ' PRIMARY KEY (`{}`) ) ENGINE = InnoDB CHARACTER SET utf8'.format(primary_key)
        try:
            self._mysql_cur.execute(sql)
            self._mysql.commit()
        except mysql.connector.Error as err:
            print('_create_table failed creating table {}: {}'.format(table_name, err))
            exit(1)

    def transfer(self):
        self._sqlite_cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
        for row in self._sqlite_cur.fetchall():
            table = dict(row)
            # create the table
            self._create_table(table['name'])
            # populate it
            print('Transferring table {}'.format(table['name']))
            self._sqlite_cur.execute('SELECT * FROM "{}"'.format(table['name']))
            columns = [column[0] for column in self._sqlite_cur.description]
            try:
                self._mysql_cur.executemany("INSERT IGNORE INTO `{table}` ({fields}) VALUES ({placeholders})".format(
                    table=table['name'],
                    fields=('`{}`, ' * len(columns)).rstrip(' ,').format(*columns),
                    placeholders=('%s, ' * len(columns)).rstrip(' ,')
                ), (tuple(data) for data in self._sqlite_cur.fetchall()))
                self._mysql.commit()
            except mysql.connector.Error as err:
                print('_insert_table_data failed inserting data into table {}: {}'.format(table['name'], err))
                exit(1)
        print('Done!')


def main():
    """ For use in standalone terminal form """
    import sys, argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--sqlite-file', dest='sqlite_file', default=None, help='SQLite3 db file')
    parser.add_argument('--mysql-user', dest='mysql_user', default=None, help='MySQL user')
    parser.add_argument('--mysql-password', dest='mysql_password', default=None, help='MySQL password')
    parser.add_argument('--mysql-database', dest='mysql_database', default=None, help='MySQL host')
    parser.add_argument('--mysql-host', dest='mysql_host', default='localhost', help='MySQL host')
    parser.add_argument('--mysql-integer-type', dest='mysql_integer_type', default='int(11)', help='MySQL default integer field type')
    parser.add_argument('--mysql-string-type', dest='mysql_string_type', default='varchar(300)', help='MySQL default string field type')
    args = parser.parse_args()

    if len(sys.argv) == 1:
        parser.print_help()
        exit(1)

    converter = SQLite3toMySQL(
        sqlite_file=args.sqlite_file,
        mysql_user=args.mysql_user,
        mysql_password=args.mysql_password,
        mysql_database=args.mysql_database,
        mysql_host=args.mysql_host,
        mysql_integer_type=args.mysql_integer_type,
        mysql_string_type=args.mysql_string_type
    )
    converter.transfer()

if __name__ == '__main__':
    main()

0

이 스크립트는 물론이 경우를 제외하고는 괜찮습니다.

"requestcomparison_stopword"에 삽입 VALUES (149, 'f');
"requestcomparison_stopword"에 삽입 VALUES (420, 't');

스크립트는이 출력을 제공해야합니다.

INSERT INTO requestcomparison_stopword VALUES (149, 'f');
INSERT INTO requestcomparison_stopword VALUES (420, 't');

그러나 대신 그 출력을 제공합니다.

INSERT INTO requestcomparison_stopword VALUES (1490;
INSERT INTO requestcomparison_stopword VALUES (4201;

마지막 0과 1에 이상한 비 ASCII 문자가 있습니다.

다음 코드 줄 (43-46)에 주석을 달았을 때 더 이상 나타나지 않았지만 다른 문제가 나타났습니다.


    line = re.sub(r"([^'])'t'(.)", "\1THIS_IS_TRUE\2", line)
    line = line.replace('THIS_IS_TRUE', '1')
    line = re.sub(r"([^'])'f'(.)", "\1THIS_IS_FALSE\2", line)
    line = line.replace('THIS_IS_FALSE', '0')

이것은 우리가 값을 'f'또는 't'로 추가하고 싶지만 정규 표현식에 실제로 익숙하지 않은 특별한 경우입니다. 나는이 사례를 누군가가 수정하기를 원했습니다.

어쨌든 그 편리한 스크립트에 감사드립니다!


0

이 간단한 솔루션은 저에게 효과적이었습니다.

<?php
$sq = new SQLite3( 'sqlite3.db' );

$tables = $sq->query( 'SELECT name FROM sqlite_master WHERE type="table"' );

while ( $table = $tables->fetchArray() ) {
    $table = current( $table );
    $result = $sq->query( sprintf( 'SELECT * FROM %s', $table ) );

    if ( strpos( $table, 'sqlite' ) !== false )
        continue;

    printf( "-- %s\n", $table );
    while ( $row = $result->fetchArray( SQLITE3_ASSOC ) ) {
        $values = array_map( function( $value ) {
            return sprintf( "'%s'", mysql_real_escape_string( $value ) );
        }, array_values( $row ) );
        printf( "INSERT INTO `%s` VALUES( %s );\n", $table, implode( ', ', $values ) );
    }
}

-5
echo ".dump" | sqlite3 /tmp/db.sqlite > db.sql

CREATE 문을 조심하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.