【问题标题】:Merge multiple backups of the same table schema into 1 master table将同一表模式的多个备份合并到 1 个主表中
【发布时间】:2016-01-17 22:36:24
【问题描述】:

我有大约 200 个 SQLite 数据库副本。所有这些都是在不同时间拍摄的,其中包含不同的数据。一些行被删除,一些被添加。它们都在一个目录中。

我想合并表my_table 中的所有行,使用目录中的所有.db 文件。我想删除重复的行,只显示所有数据库中的所有条目。

我想用纯 SQL 来做这件事,但我认为不可能,所以我们也可以使用 Python。

表定义:

CREATE TABLE my_table (
    ROWID INTEGER PRIMARY KEY AUTOINCREMENT,
    guid TEXT UNIQUE NOT NULL,
    text TEXT,
    replace INTEGER DEFAULT 0,
    service_center TEXT,
    handle_id INTEGER DEFAULT 0,
    subject TEXT,
    country TEXT,
    attributedBody BLOB,
    version INTEGER DEFAULT 0,
    type INTEGER DEFAULT 0,
    service TEXT,
    account TEXT,
    account_guid TEXT,
    error INTEGER DEFAULT 0,
    date INTEGER,
    date_read INTEGER,
    date_delivered INTEGER,
    is_delivered INTEGER DEFAULT 0,
    is_finished INTEGER DEFAULT 0,
    is_emote INTEGER DEFAULT 0,
    is_from_me INTEGER DEFAULT 0,
    is_empty INTEGER DEFAULT 0,
    is_delayed INTEGER DEFAULT 0,
    is_auto_reply INTEGER DEFAULT 0,
    is_prepared INTEGER DEFAULT 0,
    is_read INTEGER DEFAULT 0,
    is_system_message INTEGER DEFAULT 0,
    is_sent INTEGER DEFAULT 0,
    has_dd_results INTEGER DEFAULT 0,
    is_service_message INTEGER DEFAULT 0,
    is_forward INTEGER DEFAULT 0,
    was_downgraded INTEGER DEFAULT 0,
    is_archive INTEGER DEFAULT 0,
    cache_has_attachments INTEGER DEFAULT 0,
    cache_roomnames TEXT,
    was_data_detected INTEGER DEFAULT 0,
    was_deduplicated INTEGER DEFAULT 0,
    is_audio_message INTEGER DEFAULT 0,
    is_played INTEGER DEFAULT 0,
    date_played INTEGER,
    item_type INTEGER DEFAULT 0,
    other_handle INTEGER DEFAULT -1,
    group_title TEXT,
    group_action_type INTEGER DEFAULT 0,
    share_status INTEGER,
    share_direction INTEGER,
    is_expirable INTEGER DEFAULT 0,
    expire_state INTEGER DEFAULT 0,
    message_action_type INTEGER DEFAULT 0,
    message_source INTEGER DEFAULT 0
)

【问题讨论】:

  • 显示表定义。
  • @CL。添加到上面。
  • 如何识别条目?通过rowidguid
  • @CL。通过rowid,它是一个整数计数,它是主键

标签: python sql sqlite


【解决方案1】:

要同时访问主数据库和快照,请使用ATTACH。 要删除旧版本的行,请使用INSERT OR REPLACE

ATTACH 'snapshot123.db' AS snapshot;
INSERT OR REPLACE INTO main.my_table SELECT * FROM snapshot.my_table;
DETACH snapshot;

按照从最旧到最新的顺序对所有数据库执行此操作。 (SQLite 对此没有循环控制机制;在 Python 中执行此循环。)

或者,您可以从最新和最旧向后退,只插入尚不存在的行:

ATTACH 'snapshot123.db' AS snapshot;
INSERT OR IGNORE INTO main.my_table SELECT * FROM snapshot.my_table;
DETACH snapshot;

【讨论】:

  • 数据库有上百个,真的不能像这样手动完成。
  • 虽然不完整且有点粗糙(例如不删除行),但这是一个非常好的开始。编写一个 python 脚本来自动执行此操作,为已删除的行添加一个删除查询......你已经准备好了。
  • @FlipVernooij 根据问题,应保留已删除的行。如果要隐藏已删除的行,则最后一个快照将已经包含所需的数据。
  • @CL k,那么这个例子就更好了;)
  • 你能把它转换成 Python 吗?主要是想知道我是否需要 2 个数据库连接。
【解决方案2】:
import sqlite3
conn_1 = sqlite3.connect('master.db')
c = conn_1.cursor()
import glob, os
os.chdir("/Users/me/Downloads/Archives")
for file in glob.glob("*.db"):
    if file != "master.db":
        print file
        conn_2 = sqlite3.connect(file)
            c2 = conn_2.cursor()
            query = "ATTACH '%s' AS snapshot;" % file
            query += "INSERT OR IGNORE INTO master.my_table SELECT * FROM snapshot.my_table;"
            query += "DETACH snapshot;"
            c.executescript(query)

错误:sqlite3.OperationalError: no such table: master.my_table

【讨论】:

  • 主数据库(没有ATTACH打开的那个)总是叫main
【解决方案3】:

两件事:

你需要在你的 master.db 中有 my_table

在您的查询中应该是 my_table 而不是 master.my_table。

import sqlite3
conn_1 = sqlite3.connect('master.db')
c = conn_1.cursor()

query = "CREATE TABLE IF NOT EXISTS my_table (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, guid TEXT UNIQUE NOT NULL, text TEXT, replace INTEGER DEFAULT 0, service_center TEXT, handle_id INTEGER DEFAULT 0, subject TEXT, country TEXT, attributedBody BLOB, version INTEGER DEFAULT 0, type INTEGER DEFAULT 0, service TEXT, account TEXT, account_guid TEXT, error INTEGER DEFAULT 0, date INTEGER, date_read INTEGER, date_delivered INTEGER, is_delivered INTEGER DEFAULT 0, is_finished INTEGER DEFAULT 0, is_emote INTEGER DEFAULT 0, is_from_me INTEGER DEFAULT 0, is_empty INTEGER DEFAULT 0, is_delayed INTEGER DEFAULT 0, is_auto_reply INTEGER DEFAULT 0, is_prepared INTEGER DEFAULT 0, is_read INTEGER DEFAULT 0, is_system_message INTEGER DEFAULT 0, is_sent INTEGER DEFAULT 0, has_dd_results INTEGER DEFAULT 0, is_service_message INTEGER DEFAULT 0, is_forward INTEGER DEFAULT 0, was_downgraded INTEGER DEFAULT 0, is_archive INTEGER DEFAULT 0, cache_has_attachments INTEGER DEFAULT 0, cache_roomnames TEXT, was_data_detected INTEGER DEFAULT 0, was_deduplicated INTEGER DEFAULT 0, is_audio_message INTEGER DEFAULT 0, is_played INTEGER DEFAULT 0, date_played INTEGER, item_type INTEGER DEFAULT 0, other_handle INTEGER DEFAULT -1, group_title TEXT, group_action_type INTEGER DEFAULT 0, share_status INTEGER, share_direction INTEGER, is_expirable INTEGER DEFAULT 0, expire_state INTEGER DEFAULT 0, message_action_type INTEGER DEFAULT 0, message_source INTEGER DEFAULT 0)"

c.executescript(query)

import glob, os
os.chdir("/Users/me/Downloads/Archives")
for file in glob.glob("*.db"):
    if file != "master.db":
        print file
        conn_2 = sqlite3.connect(file)
        c2 = conn_2.cursor()
        query = "ATTACH '%s' AS snapshot;" % file
        query += "INSERT OR IGNORE INTO my_table SELECT * FROM snapshot.my_table;"
        query += "DETACH snapshot;"
        c.executescript(query)

【讨论】:

  • 在另一台机器上,我得到sqlite3.DatabaseError: file is encrypted or is not a database
  • 它在另一台机器上使用相同的数据和相同的脚本完美运行
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-01
  • 1970-01-01
  • 2012-04-13
  • 2021-07-05
  • 2021-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多