วิธีง่ายๆอย่างรวดเร็วในการโยกย้าย SQLite3 ไปยัง MySQL? [ปิด]


224

ใครรู้วิธีที่ง่ายรวดเร็วในการโยกย้ายฐานข้อมูล SQLite3 ไปยัง MySQL?

คำตอบ:


62

นี่คือรายการตัวแปลง (ไม่อัปเดตตั้งแต่ 2554):


วิธีการทางเลือกที่จะทำงานได้ดี แต่ไม่ค่อยมีการกล่าวถึงคือใช้คลาส ORM ที่แยกความแตกต่างของฐานข้อมูลเฉพาะออกจากคุณ เช่นคุณได้รับใน PHP ( RedBean ), Python (ชั้น ORM ของ Django, Storm , SqlAlchemy ), Ruby on Rails ( ActiveRecord ), Cocoa ( CoreData )

เช่นคุณสามารถทำสิ่งนี้:

  1. โหลดข้อมูลจากฐานข้อมูลต้นทางโดยใช้คลาส ORM
  2. จัดเก็บข้อมูลในหน่วยความจำหรือทำให้เป็นอนุกรมในดิสก์
  3. เก็บข้อมูลลงในฐานข้อมูลปลายทางโดยใช้คลาส ORM

107

ดูเหมือนว่าทุกคนจะเริ่มต้นด้วยการแสดง greps และ perl เล็กน้อยและคุณก็จะได้สิ่งที่เหมาะกับชุดข้อมูลเฉพาะของคุณ แต่คุณไม่รู้ว่ามันนำเข้าข้อมูลถูกต้องหรือไม่ ฉันประหลาดใจอย่างจริงจังไม่มีใครสร้างห้องสมุดที่มั่นคงที่สามารถแปลงระหว่างสอง

นี่คือรายการความแตกต่างทั้งหมดในไวยากรณ์ SQL ที่ฉันรู้เกี่ยวกับรูปแบบไฟล์ทั้งสอง: บรรทัดที่ขึ้นต้นด้วย:

  • เริ่มต้นการทำธุรกรรม
  • COMMIT
  • SQLITE_SEQUENCE
  • สร้าง INDEX ที่ไม่ซ้ำกัน

ไม่ได้ใช้ใน 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'สำหรับ booleans, MySQL ใช้1และ0(regex ง่าย ๆ สำหรับสิ่งนี้อาจล้มเหลวเมื่อคุณมีสตริงเช่น: 'I do you don \' t 'in your your INSERT INTO)
  • SQLLite ใช้งานAUTOINCREMENT, MySQL ใช้AUTO_INCREMENT

นี่เป็นสคริปต์ Perl พื้นฐานที่แฮ็กข้อมูลซึ่งใช้งานได้กับชุดข้อมูลของฉันและตรวจสอบเงื่อนไขอื่น ๆ อีกมากมายที่สคริปต์ Perl อื่น ๆ ที่ฉันพบในเว็บ Nu guarentees ว่ามันจะทำงานกับข้อมูลของคุณ แต่อย่าลังเลที่จะแก้ไขและโพสต์กลับมาที่นี่

#! /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;
    }
}

8
อเล็กซ์เทลได้งานที่ดีเขียนใหม่นี้เป็นงูหลามมากกว่าที่stackoverflow.com/questions/1067060/perl-to-python
Jiaaro

ฉันเพิ่มสคริปต์หลามฉบับสมบูรณ์ (สคริปต์ Perl เพียงอย่างเดียวไม่ได้ค่อนข้างทำงานสำหรับฉัน ... บางอย่างที่จำเป็นในการประมวลผลพิเศษในการจัดการคีย์ต่างประเทศและดัชนี)
Jiaaro

ฉันเขียนคำตอบนี้ในคำถามอื่น ๆstackoverflow.com/questions/1067060/_/1070463#1070463
แบรดกิลเบิร์ต

2
COMMITและCREATE UNIQUE INDEXเป็นคำสั่ง MySQL ที่ถูกต้องโปรดแก้ไข
niutech

5
ฉันเข้าใจว่าสคริปต์ของคุณคือ "รวดเร็วและสกปรก" แต่ก็มีประโยชน์มากดังนั้นต่อไปนี้คือส่วนเพิ่มเติม / bugfixes: * หลังจาก&& ($line !~ /CREATE UNIQUE INDEX/)เพิ่ม&& ($line !~ /PRAGMA foreign_keys=OFF/) * regex การจับคู่ชื่อตารางที่ตรงกับตัวเลขที่หายไปแทนที่จะ$line =~ /INSERT INTO \"([a-z_]*)\"(.*)/ต้องมี$line =~ /INSERT INTO \"([a-z_1-9]*)\"(.*)/ หวังว่านี่จะช่วยอนาคต ผู้อ่าน
Michał Leon

50

นี่คือสคริปต์ python ที่สร้างขึ้นจากคำตอบของ Shalmanese และความช่วยเหลือจาก Alex martelli มากกว่าที่การแปล 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 แรกถูกห่อด้วย backquote แทนที่จะเป็นเครื่องหมายคำพูดเดี่ยว: __ DROP Table IF EXISTS schema_migrations; สร้างตารางหากไม่มีอยู่schema_migrations( versionvarchar (255) ไม่ใช่ค่า NULL); INSERT INTO schema_migrations VALUES ( 20100714032840); INSERT INTO schema_migrations VALUES ('20100714033251'); __
เดวิด

ดี ... มันไม่ปรากฏขึ้นด้านบน แต่ backquotes ปรากฏอยู่ในค่า ([ที่นี่] 20100714032840 [/ ที่นี่])
David

1
AUTOINCREMENT ใน Mysql คือ AUTO_INCREMENT สคริปต์ไม่ได้พิจารณาถึงสิ่งนั้น
giuseppe

สิ่งนี้ไม่ได้ผลสำหรับฐานข้อมูลสื่อวิกิ ข้อผิดพลาดหลายBlobvarชนิดข้อมูลกลับเห็บในคำสั่งสร้าง ...
แฟรงก์ Hintsch

1
ไม่ทำงาน อาจไม่ใช่เงื่อนไขทั้งหมดที่นำมาพิจารณา ...
Himanshu Bansal

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 และเครื่องหมายคำพูดคู่เด้งกลับใจ) แต่ไม่มีอะไรที่ค้นหาและแทนที่ไม่สามารถแก้ไขได้

บางทีคุณควรถามว่าทำไมคุณถึงต้องย้ายถ้าขนาดประสิทธิภาพ / ฐานข้อมูลเป็นปัญหาอาจดู reoginising schema หากระบบย้ายไปยังผลิตภัณฑ์ที่มีประสิทธิภาพมากขึ้นนี่อาจเป็นเวลาที่เหมาะสำหรับการวางแผนอนาคตของข้อมูลของคุณ


2
แต่งานที่ยากที่สุดคือความแตกต่าง betweek ไวยากรณ์
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 / As อื่น ๆ ) เพื่อหาวิธีการทำงานใน เพื่อที่จะโยกย้ายได้สำเร็จ

อย่างไรก็ตามแม้หลังจากรวมคำตอบที่มีอยู่แล้วฉันพบว่าสคริปต์ Python ไม่ทำงานอย่างสมบูรณ์สำหรับฉันเนื่องจากไม่ได้ทำงานในกรณีที่มีบูลีนหลายรายการเกิดขึ้นใน INSERT ดูที่นี่ทำไมเป็นกรณี

ดังนั้นฉันคิดว่าฉันโพสต์คำตอบที่ผสานของฉันที่นี่ เครดิตไปยังผู้ที่มีส่วนร่วมในที่อื่นแน่นอน แต่ฉันต้องการคืนบางสิ่งบางอย่างและประหยัดเวลาผู้อื่นที่ตามมา

ฉันจะโพสต์สคริปต์ด้านล่าง แต่ก่อนอื่นนี่คือคำแนะนำสำหรับการแปลง ...

ฉันรันสคริปต์บน OS X 10.7.5 Lion Python ทำงานนอกกรอบ

ในการสร้างไฟล์อินพุต MySQL จากฐานข้อมูล SQLite3 ที่มีอยู่ให้รันสคริปต์บนไฟล์ของคุณเองดังนี้

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

ฉันก็คัดลอกไฟล์ dumped_sql.sql ที่เป็นผลลัพธ์ไปยังกล่อง Linux ที่ใช้ Ubuntu 10.04.4 LTS ที่ฐานข้อมูล MySQL ของฉันตั้งอยู่

ปัญหาอีกข้อที่ฉันมีเมื่อนำเข้าไฟล์ 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 ร้องขอมันง่ายและรวดเร็วเมื่อคุณรู้วิธี! :-)

นอกจากนี้สิ่งหนึ่งที่ฉันไม่แน่ใจก่อนที่ฉันจะดูการโยกย้ายครั้งนี้คือการสร้างค่าของฟิลด์ __ และ _ ที่อัปเดตจะถูกรักษาไว้หรือไม่ข่าวดีสำหรับฉันก็คือพวกเขาเป็นดังนั้นฉันสามารถย้ายข้อมูลการผลิตที่มีอยู่

โชคดี!

UPDATE

ตั้งแต่เปลี่ยนมาฉันได้สังเกตเห็นปัญหาที่ฉันไม่เคยสังเกตมาก่อน ในแอปพลิเคชัน Rails ของฉันฟิลด์ข้อความของฉันถูกกำหนดเป็น 'string' และสิ่งนี้จะนำไปสู่สกีมาฐานข้อมูล กระบวนการที่ระบุไว้ที่นี่ส่งผลให้สิ่งเหล่านี้ถูกกำหนดเป็น VARCHAR (255) ในฐานข้อมูล MySQL สิ่งนี้วางขีด จำกัด 255 อักขระบนขนาดฟิลด์เหล่านี้ - และสิ่งอื่นนอกเหนือจากนี้จะถูกตัดทอนอย่างเงียบ ๆ ระหว่างการนำเข้า เพื่อรองรับความยาวข้อความที่มากกว่า 255 สคีมา MySQL จะต้องใช้ 'TEXT' แทน VARCHAR (255) ฉันเชื่อ กระบวนการที่กำหนดไว้ที่นี่ไม่รวมการแปลงนี้


นี่คือสคริปต์ 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
ขอบคุณ สคริปต์ตามที่เขียนไว้ด้านบนมีข้อผิดพลาดทางไวยากรณ์ "else:" ในบรรทัดที่ 41 ไม่อยู่ในระดับการเยื้องที่เหมาะสม ไม่ชัดเจนสำหรับฉันว่าควรมีการเยื้องบรรทัดข้างบนหรือมีสิ่งอื่นเกิดขึ้น สนใจอัปเดตหรือไม่
Dan Tenenbaum

5

ฉันเพิ่งต้องย้ายจาก MySQL ไปยัง JavaDB สำหรับโครงการที่ทีมของเรากำลังทำงาน ฉันพบห้องสมุด Java ที่เขียนโดย Apache ชื่อ DdlUtilsซึ่งทำให้มันง่ายมาก มันมี API ที่ให้คุณทำสิ่งต่อไปนี้:

  1. ค้นพบสคีมาของฐานข้อมูลและส่งออกเป็นไฟล์ XML
  2. ปรับเปลี่ยนฐานข้อมูลตามสคีมานี้
  3. นำเข้าบันทึกจากฐานข้อมูลหนึ่งไปยังอีกสมมติว่าพวกเขามีสคีเดียวกัน

เครื่องมือที่เราลงเอยด้วยการไม่ได้เป็นไปโดยอัตโนมัติอย่างสมบูรณ์ แต่มันก็ใช้งานได้ดี แม้ว่าแอปพลิเคชันของคุณไม่ได้อยู่ใน Java แต่ก็ไม่ควรยากเกินไปที่จะใช้เครื่องมือเล็ก ๆ น้อย ๆ ในการโยกย้ายครั้งเดียว ฉันคิดว่าฉันสามารถดึงการย้ายข้อมูลของเราด้วยรหัสน้อยกว่า 150 บรรทัด


4

ไม่จำเป็นต้องมีสคริปต์คำสั่งและอื่น ๆ ...

คุณต้องส่งออกฐานข้อมูล sqlite ของคุณเป็น.csvไฟล์แล้วนำเข้าใน Mysql โดยใช้ phpmyadmin

ฉันใช้มันและมันทำงานได้ยอดเยี่ยม ...


เมื่อใช้ร่วมกับสิ่งนี้นี่เป็นคำตอบเดียวที่เหมาะกับฉัน
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 กับข้อมูลที่นำเข้า แต่การเพิ่ม --default-character-set = utf8 ไปยังคำสั่ง import ดูเหมือนว่าจะแก้ไขแล้ว นำมาจาก 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 vs mysql คุณยังต้องแปลงด้วยตนเอง
dlite922

1

ฮ่า ... ฉันหวังว่าฉันจะพบสิ่งนี้ก่อน! การตอบสนองของฉันคือการโพสต์นี้ ... สคริปต์เพื่อแปลงไฟล์ sql การถ่ายโอนข้อมูล mysql ในรูปแบบที่สามารถนำเข้าสู่ 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

สคริปต์นี้ใช้ได้ยกเว้นกรณีนี้ซึ่งแน่นอนว่าฉันเจอแล้ว:

INSERT INTO "requestcomparison_stopword" ค่า (149, 'f');
INSERT INTO "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;

มีอักขระที่ไม่ใช่ ascii ที่แปลกประหลาดอยู่ประมาณ 0 และ 1 ตัวสุดท้าย

สิ่งนี้ไม่ปรากฏอีกต่อไปเมื่อฉันแสดงความคิดเห็นบรรทัดต่อไปนี้ของรหัส (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 ) );
    }
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.