如何生成各种数据库备份

2 投票
3 回答
2146 浏览
提问于 2025-04-16 06:43

我有一个CSV文件,想把里面的数据生成适合sqlite、mysql、postgres、oracle和mssql的备份。

有没有一个通用的接口(最好是基于Python的)可以做到这一点呢?

我可以用一个ORM工具把数据插入到每个数据库里,然后再导出备份,但这样的话就得安装每个数据库。这感觉有点浪费资源,因为这些CSV文件非常

我不太想自己写SQL语句,因为每个数据库的写法都不一样。理想情况下,应该有人已经做过这项工作,但我还没找到。

3 个回答

0

你可以试试这个 - 从CSV文件创建SQL表

或者 从CSV文件生成插入语句

还可以试试这个 用Python从CSV生成.sql文件

当然,你可能需要根据自己的需求对这些脚本进行一些调整。

1

我不是数据库专家,但据我所知,Python里没有一个通用的接口可以直接满足你的需求。不过,有一个叫做PEP 249的标准,它定义了一个供数据库模块使用的接口,至少在MySQL和Postgre的Python模块中有用到(可以参考这里这里

不过,我自己会尝试走另一条路:

  1. 把CSV文件导入MySQL(这是因为我对MySQL最熟悉,网上有很多相关资料,比如这个简单的教程,不过你也可以从其他数据库开始做同样的事情)。
  2. 生成MySQL的转储文件
  3. 处理MySQL的转储文件,把它修改成SQLite(以及其他数据库)能识别的格式。

处理转储文件的脚本可以写得很简洁,虽然如果你用正则表达式来解析每一行,可能会有点复杂。这里有一个从这个页面复制过来的MySQL到SQLite的示例脚本:

#!/bin/sh 
mysqldump --compact --compatible=ansi --default-character-set=binary mydbname | 
grep -v ' KEY "' | 
grep -v ' UNIQUE KEY "' | 
perl -e 'local $/;$_=<>;s/,\n\)/\n\)/gs;print "begin;\n";print;print "commit;\n"' | 
perl -pe ' 
if (/^(INSERT.+?)\(/) { 
$a=$1; 
s/\\'\''/'\'\''/g; 
s/\\n/\n/g; 
s/\),\(/\);\n$a\(/g; 
} 
' | 
sqlite3 output.db

你可以用Python来写这个脚本(如果这样的话,可以看看re.compile以提高性能)。

我选择这种方法的原因是:

  1. 我可以让mysql帮我完成繁重的工作(导入和数据一致性检查,以及生成初始的SQL文件)。
  2. 我只需要安装一个数据库。
  3. 我可以完全控制整个过程,并有机会进行细微调整。
  4. 我可以把我的脚本结构设计得很容易扩展到其他数据库(基本上我会把它设计成一个解析器,能够识别各个字段,并为每个数据库设置一套语法规则,用户可以通过命令行选项选择)。
  5. 关于不同SQL方言之间差异的文档要比单个数据库的导入/导出库多得多。

编辑:基于模板的方法

如果你因为某种原因不太自信自己写SQL,可以使用一种基于模板的脚本。以下是我会怎么做:

  1. 导入并生成你计划使用的四个数据库的表的转储。
  2. 对于每个数据库,保存转储的初始部分(包括模式声明等)和一条插入指令。
  3. 写一个Python脚本,对于每个数据库的导出,输出转储的“头部”和同样的“保存行”,然后你可以程序化地替换CSV文件中每一行的值。

这种方法的明显缺点是你的“模板”只能适用于一个表。但它的优点是编写这样的脚本会非常简单和快速。

希望这对你有一点帮助!

5

SQLAlchemy 是一个数据库库,它不仅提供了ORM功能,还支持在各种数据库的SQL生成。这些数据库的类型可以在方言中找到,支持的数据库种类非常多。

在正常使用中,你可以创建一个SQL表达式或指令(使用schema.Table对象),然后创建一个数据库引擎,最后把这个指令绑定到引擎上,这样就能生成SQL了。

不过,其实引擎并不是绝对必要的;每种方言都有自己的编译器,可以在没有连接的情况下生成SQL。唯一需要注意的是,你需要阻止它默认生成绑定参数:

from sqlalchemy.sql import expression, compiler
from sqlalchemy import schema, types
import csv

# example for mssql
from sqlalchemy.dialects.mssql import base
dialect = base.dialect()
compiler_cls = dialect.statement_compiler
class NonBindingSQLCompiler(compiler_cls):
    def _create_crud_bind_param(self, col, value, required=False):
        # Don't do what we're called; return a literal value rather than binding
        return self.render_literal_value(value, col.type)

recipe_table = schema.Table("recipe", schema.MetaData(), schema.Column("name", types.String(50), primary_key=True), schema.Column("culture", types.String(50)))

for row in [{"name": "fudge", "culture": "america"}]: # csv.DictReader(open("x.csv", "r")):
    insert = expression.insert(recipe_table, row, inline=True)
    c = NonBindingSQLCompiler(dialect, insert)
    c.compile()
    sql = str(c)
    print sql

上面的例子实际上是可以工作的;它假设你知道目标数据库表的结构;这个方法应该很容易调整,可以从CSV文件导入数据,并为多个目标数据库方言生成SQL。

撰写回答