使用Python在SQLite中插入包含相同列的两个表的外键
我的计算机上有一个SQLite数据库,其中有两个表: 表_post包含关于twitter帖子的信息:喜欢、作者、URL等。。。 表_profile包含关于Twitter配置文件的信息:用户名、描述、关注者等。。。 我使用的是一个python脚本,它创建了两个单独的CSV文件,其中包含table_post和table_profile的行 然后我使用另一个脚本将CSV文件传输到SQLite数据库。在我想用外键链接这两个表之前,一切都正常 My table_post有以下列:post_IDPK、profile_IDPK、postrl、postText、pubDate、commentCount、likeCount、profileUrl 我的表格配置文件有以下列:profile_IDPK、profileUrl、subCount、userName、profileDesc 两个表都有profileUrl,我想使用profileUrl列将相应的表profile.profile\u ID插入到表\u post.profile\u ID中 我知道我们可以使用此SQLite查询来连接行: 从表_profile中选择* JOIN table_post ON table_profile.profileUrl=table_post.profileUrl 您需要的是UPDATE语句,而不是INSERT语句 将CSV文件传输到SQLite数据库后,必须更新表\u post:使用Python在SQLite中插入包含相同列的两个表的外键,python,sqlite,sql-update,foreign-keys,primary-key,Python,Sqlite,Sql Update,Foreign Keys,Primary Key,我的计算机上有一个SQLite数据库,其中有两个表: 表_post包含关于twitter帖子的信息:喜欢、作者、URL等。。。 表_profile包含关于Twitter配置文件的信息:用户名、描述、关注者等。。。 我使用的是一个python脚本,它创建了两个单独的CSV文件,其中包含table_post和table_profile的行 然后我使用另一个脚本将CSV文件传输到SQLite数据库。在我想用外键链接这两个表之前,一切都正常 My table_post有以下列:post_IDPK、pro
UPDATE table_post
SET profile_ID = (SELECT profile.profile_ID FROM profile WHERE profile.profileUrl = table_post.profileUrl)
如果您的SQLite版本为3.33.0+,则可以使用UPDATE…FROM语法:
如果您已经从CSV加载了两个表,并且如果您不使用或不希望使用外键约束,那么您可以简单地运行更新,例如
UPDATE table_post
SET profile_ID = (SELECT table_profile.profile
FROM table_profile
WHERE table_profile.profileurl = table_post.profileurl)
;
但是,如果您希望使用外键约束来强制引用完整性,和/或如果您希望规范profileurl以减少数据的重复,那么另一种方法是
读取配置文件CSV文件并插入/加载配置文件的,
然后读取帖子的CSV文件,并使用子查询插入/加载帖子,以在插入过程中解析帖子的概要文件ID。
除非关闭外键处理,否则插入/加载后的更新将失败,并出现外键约束异常。请参阅
您可能必须打开外键处理,因为默认情况下它是打开的。
使用外键约束不仅可以强制引用完整性,还可以将概要文件中的更新和删除级联到帖子中。例如,如果您要删除一个配置文件,那么与该配置文件相关的所有帖子都将被删除,而不是外键例外
如果不使用外键约束,删除一个配置文件可能会导致孤立的帖子,使其没有与之相关的配置文件。
第一种方法的关键是使用子查询SELECT profile_id FROM table_profile设置table_post profile_id列,其中profileurl='url2'。如果使用唯一约束,这将增加所需的时间,从而减少所需的时间,但这样做的代价是在配置文件表中插入所需的时间稍长一点,因为它们是父对象,插入配置文件的影响较小
关于正常化;在当前模型中,profileurl存储在父配置文件和子配置文件中,但似乎不想将其用于关系,因此不需要将profileurl存储在post表中。可以释放多余的存储空间。此外,您不必维护重复的事件。假设你有一个url为X_is_的档案X,由于某些原因,需要更改为X的url不在这里,如果没有标准化,你将不得不更改所有与X相关的帖子。但是,如果url仅存储在配置文件中,则只需更改一次
另一种方法是利用已经存在的关系,即use profileurl。但是,如果您想强制引用完整性,那么需要稍微修改table_profile和table_post,然后按原样插入/加载就可以了
范例
这是一个基于您描述的模式但利用外键约束的示例。此外,还提供了一种使用关系档案URL的替代方案
DROP TABLE IF EXISTS table_post;
DROP TABLE IF EXISTS table_post_alt;
DROP TABLE IF EXISTS table_profile;
CREATE TABLE IF NOT EXISTS table_profile (
profile_id INTEGER PRIMARY KEY,
profileurl TEXT UNIQUE,
subCount INTEGER,
userName,
profileDesc TEXT
);
CREATE TABLE IF NOT EXISTS table_post (
post_id INTEGER PRIMARY KEY,
profile_id INTEGER REFERENCES table_profile(profile_id),
post_url TEXT,
postText TEXT,
pubDate TEXT,
commentCount INTEGER,
likeCount INTEGER,
profileurl
);
CREATE TABLE IF NOT EXISTS table_post_alt (
post_id INTEGER PRIMARY KEY,
profile_id INTEGER,
post_url TEXT,
postText TEXT,
pubDate TEXT,
commentCount INTEGER, likeCount INTEGER, profileurl REFERENCES table_profile(profileurl));
INSERT OR IGNORE INTO table_profile VALUES
(null,'url1',10,'user1','blah1')
,(null,'url2',100,'user2','blah2')
,(null,'url3',10,'user3','blah3')
/* etc.... */
,(null,'url2',100,'user2','blah2') /* purposeful duplicate (ignored) */
;
INSERT OR IGNORE INTO table_post VALUES
(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url2'),'post_url1','post text 1st post','2020-04-01',5,7,'url2')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url1'),'post_url2','post text 2nd post','2020-04-01',5,7,'url1')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url1'),'post_url3','post text 3rd post','2020-04-01',5,7,'url1')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url3'),'post_url4','post text 4th post','2020-04-01',5,7,'url3')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url2'),'post_url5','post text 5th post','2020-04-01',5,7,'url2')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url1'),'post_url6','post text 6th post','2020-04-01',5,7,'url1')
/* etc .... */
;
INSERT OR IGNORE INTO table_post_alt VALUES
(null,'does not matter','post_url1','post text 1st post','2020-04-01',5,7,'url2')
,(null,'does not matter','post_url2','post text 2nd post','2020-04-01',5,7,'url1')
,(null,'does not matter','post_url3','post text 3rd post','2020-04-01',5,7,'url1')
,(null,'does not matter','post_url4','post text 4th post','2020-04-01',5,7,'url3')
,(null,'does not matter','post_url5','post text 5th post','2020-04-01',5,7,'url2')
,(null,'does not matter','post_url6','post text 6th post','2020-04-01',5,7,'url1')
;
SELECT * FROM table_profile
JOIN table_post ON table_profile.profileUrl = table_post.profileUrl;
SELECT * FROM table_profile
JOIN table_post_alt ON table_profile.profileUrl = table_post_alt.profileUrl;
运行上述操作将导致使用您的查询:-
并使用仅为替代表名修改的查询:-
注意:值无关紧要已用于表明,由于FK是profileurl,因此配置文件Id不匹配无关紧要。您可以使用与第一个选项相同的方法来获取正确的值,但数据未完全正常化,它不在原始文件中,因为您有两次出现profileurl。
非常感谢。这正是我所需要的,它现在可以工作了!感谢您的辛勤工作,事实上,我还没有想过要更改profileUrl,并在post表中留下孤儿,以及数据库中的数据重复问题。我会考虑让我的数据正常化,再次感谢大家!
DROP TABLE IF EXISTS table_post;
DROP TABLE IF EXISTS table_post_alt;
DROP TABLE IF EXISTS table_profile;
CREATE TABLE IF NOT EXISTS table_profile (
profile_id INTEGER PRIMARY KEY,
profileurl TEXT UNIQUE,
subCount INTEGER,
userName,
profileDesc TEXT
);
CREATE TABLE IF NOT EXISTS table_post (
post_id INTEGER PRIMARY KEY,
profile_id INTEGER REFERENCES table_profile(profile_id),
post_url TEXT,
postText TEXT,
pubDate TEXT,
commentCount INTEGER,
likeCount INTEGER,
profileurl
);
CREATE TABLE IF NOT EXISTS table_post_alt (
post_id INTEGER PRIMARY KEY,
profile_id INTEGER,
post_url TEXT,
postText TEXT,
pubDate TEXT,
commentCount INTEGER, likeCount INTEGER, profileurl REFERENCES table_profile(profileurl));
INSERT OR IGNORE INTO table_profile VALUES
(null,'url1',10,'user1','blah1')
,(null,'url2',100,'user2','blah2')
,(null,'url3',10,'user3','blah3')
/* etc.... */
,(null,'url2',100,'user2','blah2') /* purposeful duplicate (ignored) */
;
INSERT OR IGNORE INTO table_post VALUES
(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url2'),'post_url1','post text 1st post','2020-04-01',5,7,'url2')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url1'),'post_url2','post text 2nd post','2020-04-01',5,7,'url1')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url1'),'post_url3','post text 3rd post','2020-04-01',5,7,'url1')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url3'),'post_url4','post text 4th post','2020-04-01',5,7,'url3')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url2'),'post_url5','post text 5th post','2020-04-01',5,7,'url2')
,(null,(SELECT profile_id FROM table_profile WHERE profileurl = 'url1'),'post_url6','post text 6th post','2020-04-01',5,7,'url1')
/* etc .... */
;
INSERT OR IGNORE INTO table_post_alt VALUES
(null,'does not matter','post_url1','post text 1st post','2020-04-01',5,7,'url2')
,(null,'does not matter','post_url2','post text 2nd post','2020-04-01',5,7,'url1')
,(null,'does not matter','post_url3','post text 3rd post','2020-04-01',5,7,'url1')
,(null,'does not matter','post_url4','post text 4th post','2020-04-01',5,7,'url3')
,(null,'does not matter','post_url5','post text 5th post','2020-04-01',5,7,'url2')
,(null,'does not matter','post_url6','post text 6th post','2020-04-01',5,7,'url1')
;
SELECT * FROM table_profile
JOIN table_post ON table_profile.profileUrl = table_post.profileUrl;
SELECT * FROM table_profile
JOIN table_post_alt ON table_profile.profileUrl = table_post_alt.profileUrl;