簡體   English   中英

Python sqlite3:兩個數據庫中表的差異

[英]Python sqlite3: Diff of table in two databases

我有兩個具有相同模式的數據庫,我想在其中一個表上有效地進行差異。 即僅返回唯一記錄,折扣主鍵。

columns = zip(*db1.execute("PRAGMA table_info(foo)").fetchall())[1]
db1.execute("ATTACH DATABASE '/path/to/db1.db' AS db1")
db1.execute("ATTACH DATABASE '/path/to/db2.db' AS db2")
db2.execute("ATTACH DATABASE '/path/to/db1.db' AS db1")
db2.execute("ATTACH DATABASE '/path/to/db2.db' AS db2")
data = db2.execute("""
    SELECT 
        one.* 
    FROM 
        db1.foo AS one 
        JOIN db2.foo 
        AS two 
    WHERE {}
    """.format(' AND '.join( ['one.{0}!=two.{0}'.format(c) for c in columns[1:]]))
).fetchall()

也就是說,忽略主鍵(在這種情況下是meow ),不要返回兩個數據庫中存在相同的記錄。

db1的表foo如下所示:

meow    mix    please   deliver
1       123    abc
2       234    bcd      two
3       345    cde

db2的表foo看起來像:

meow    mix    please   deliver
1       345    cde
2       123    abc      one
3       234    bcd      two     
4       456    def      four

所以db2的唯一條目是:

[(2, 123, 'abc', 'one'), (4, 456, 'def', 'four')]

這就是我得到的。 如果我有兩列以上,這很有效。 但是如果只有兩個,即主鍵和一個值,例如在查找表中:

bar  baz         bar   baz
1    123         1     234
2    234         2     345
3    345         3     123
                 4     456

我得到所有非唯一值重復N-1次,唯一值重復N次,其中N是db1的記錄數。 我理解為什么會這樣,但我不知道如何解決它。

[(1, '234'),
 (1, '234'),
 (2, '345'),
 (2, '345'),
 (3, '123'),
 (3, '123'),
 (4, '456'),
 (4, '456'),
 (4, '456')]

我有一個想法是在拉出所有重復結果后取出模數:

N = db1.execute("SELECT Count(*) FROM foo").fetchone()[0]
data = [
     list(data) 
     for data,n in itertools.groupby(sorted(data)) 
     if np.mod(len(list(n)),N)==0
]

哪個工作:

[[4, '456']]

但這看起來很混亂,如果可能的話,我想在第一個SQL查詢中完成所有操作。

此外,在大型表(我的真實數據庫有~10k記錄)上,這需要很長時間。 有什么辦法優化這個? 謝謝!

取代我之前的答案 - 這是一個很好的通用解決方案。

輸入表看起來像這樣:

sqlite> select * from t1;
meow        mix         please      delivery  
----------  ----------  ----------  ----------
1           123         abc                   
2           234         bcd         two       
3           345         cde                   

sqlite> select * from t2;
meow        mix         please      delivery  
----------  ----------  ----------  ----------
1           345         cde                   
2           123         abc         one       
3           234         bcd         two       
4           456         def         four      

你可以得到t2 /不在t1(忽略PK)的記錄,如下所示:

select sum(q1.db), mix, please, delivery from (select 1 as db, mix, please,
delivery from t1 union all select 2 as db, mix, please, delivery from t2) q1
group by mix, please, delivery having sum(db)=2; 

sum(q1.db)  mix         please      delivery  
----------  ----------  ----------  ----------
2           123         abc         one       
2           456         def         four      

您可以通過更改having子句中的值來執行不同的set操作。 SUM(DB)=1返回1 /不是2的記錄; SUM(DB)=2返回2 /不是1的記錄; SUM(DB)=1 OR SUM(DB)=2返回存在於其中的記錄,但不返回兩者; SUM(DB)=3返回兩者中存在的記錄。

唯一不適合你的是返回PK。 這在我編寫的查詢中無法完成,因為GROUP BYSUM操作僅適用於公共/聚合數據,PK字段根據定義是唯一的。 如果您知道每個數據庫中非PK字段的組合是唯一的,您可以使用返回的記錄創建新查詢以查找PK。

請注意,此方法很好地擴展到超過2個表。 通過使db字段的冪為2,您可以對任意數量的表進行操作。 例如,如果您為t1執行了1作為數據,對於t2執行了2作為db,對於t3執行了4作為db,對於t4執行了db作為db,則可以通過更改條件來找到所需表的任何相交/差異 - 例如, HAVING SUM(DB)=5將返回t1和t3中的記錄,但不返回t2或t4中的記錄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM