2016-01-17 9 views
6

に同じテーブルスキーマの複数のバックアップをマージします。すべてが異なるデータで異なる時間に撮影されています。一部の行は削除され、一部は追加されます。それらはすべて単一のディレクトリにあります。は、私はSQLiteデータベースの約200のコピーを持っている1つのマスタテーブル

ディレクトリ内のすべての.dbファイルを使用して、テーブルmy_tableのすべての行をマージしたいとします。私は重複した行を削除して、すべてのデータベースからすべてのエントリをただ一度表示します。

私は純粋なSQLでこれを行うにはしたいと思いますが、私はそれが可能だとは思わないので、私たちはあまりにもパイソンを使用することができます。

テーブル定義:

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 
) 
+0

テーブル定義を表示します。 –

+0

@ CL。上記に追加されました。 – User

+0

エントリはどのように識別されますか? 'rowid'または' guid'によって? –

答えて

7

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; 
+0

何百ものデータベースがありますので、実際には手動でこれを行うことはできません。 – User

+0

不完全で少し荒い(例えば行を削除しない)場合でも、これは非常に良いスタートです。これを自動化するpythonスクリプトを書いて、削除された行の削除クエリを追加してください。あなたはかなり準備ができています。 –

+2

@FlipVernooij質問によれば、削除された行は保持されるべきです。削除された行を非表示にする場合、最後のスナップショットには既に必要なデータが含まれています。 –

1
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

+0

メインデータベース( 'ATTACH'なしでオープンしたデータベース)は常に' main'と呼ばれます。 –

1

二つのこと:

あなたmaster.dbでMY_TABLEを持っている必要があります

あなたのクエリにmaster.my_tableませ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) 
+0

別のマシンで、 'sqlite3.DatabaseError:ファイルが暗号化されているかデータベースではありません.' – User

+0

ファイルが壊れていますか? – Allen

+0

別のマシンで同じデータと同じスクリプトで完璧に実行されました – User

関連する問題