问题描述
- table_post(包含 Twitter 帖子的相关信息:喜欢、作者、URL 等...)
- table_profile(包含有关 Twitter 个人资料的信息:用户名、描述、关注者等...)
我正在使用 python 脚本创建两个单独的 CSV 文件,其中包含 table_post 和 table_profile 的行。
然后我使用另一个脚本将 CSV 文件传输到 sqlite 数据库。一切正常,直到我想用外键链接两个表。
我的 table_post 有这些列:post_ID(PK)、profile_ID(FK)、postUrl、postText、pubDate、commentCount、likeCount、profileUrl
我的表配置文件有这些列:profile_ID(PK)、profileUrl、subCount、userName、profileDesc
两个表都有 profileUrl,我想使用 profileUrl 列在 table_post.profile_ID 中插入相应的 table_profile.profile_ID。
SELECT * FROM table_profile
JOIN table_post ON table_profile.profileUrl = table_post.profileUrl;
我想使用 Python 和 sqlite3 在 post_ID 中插入相应的 profile_ID。 我能做什么 ? 在 sqlite 数据库中写入时是否需要写入 ID?如果是,如何?
我可以编写一个函数来检查 post_table 中的每一行并将其与 profile_ID 相关联吗?如果是,如何?
谢谢。
解决方法
您需要的是 UPDATE
语句而不是 INSERT
。
在将 CSV 文件传输到 SQLite 数据库后,您必须更新表 table_post
:
UPDATE table_post
SET profile_ID = (SELECT profile.profile_ID FROM profile WHERE profile.profileUrl = table_post.profileUrl)
如果您的 SQLite 版本是 3.33.0+,您可以使用 UPDATE...FROM
语法:
UPDATE table_post AS t
SET profile_ID = p.profile_ID
FROM profile AS p
WHERE p.profileUrl = t.profileUrl
,
如果您已经从 CSV 加载了两个表,并且您不使用或不希望使用外键约束,那么您可以简单地运行一个更新,例如
UPDATE table_post
SET profile_ID = (SELECT table_profile.profile
FROM table_profile
WHERE table_profile.profileurl = table_post.profileurl)
;
但是,如果您想使用外键约束来强制执行参照完整性,和/或如果您想规范化 profileurl(减少数据的重复),那么另一种方法是
- 读取配置文件 CSV 文件并插入/加载配置文件的和,
- 然后读取帖子的 CSV 文件并在插入期间使用子查询插入/加载帖子以解析帖子的 profile_ID。
-
除非关闭外键处理,否则插入/加载后的 UPDATE 将因外键约束异常而失败(请参阅 PRAGMA Foreign Keys)
- 您可能需要打开外键处理,因为默认情况下它是关闭的。
-
使用外键约束不仅可以强制执行参照完整性,而且可以从配置文件到帖子的级联更新和删除。例如。如果您要删除个人资料,则与该个人资料相关的所有帖子都将被删除,而不是外键异常。
- 在不使用外键约束的情况下删除个人资料可能会导致帖子孤立(让它们没有相关的个人资料)。
-
第一个提出的方法的关键是使用子查询
(SELECT profile_id FROM table_profile WHERE profileurl = 'url2')
设置 table_post profile_id 列。这将增加花费的时间(因此如果使用 UNIQUE 约束会减少,但代价是插入到配置文件表需要更长的时间,看到它们是插入配置文件的父项将不是一个因素)。 -
关于规范化;在您当前的模型中,您将 profileurl 存储在父(配置文件)和子项(帖子)中,但似乎不想将其用于关系,因此不需要将 profileurl 存储在帖子表中。可以释放多余的存储空间。此外,您不必维护重复的事件。假设您的个人资料 X 的 url 为 x_is_here 并且由于某种原因需要更改为 x 的 url 不在此处,您将不得不更改与 X 相关的所有帖子(如果未规范化)。但是,如果 url 仅存储在配置文件中,则只需更改一次。
另一种方法可能是利用已经存在的关系,即使用 profileurl。但是,如果您想强制执行参照完整性,则需要稍微修改 table_profile 和 table_post,按原样插入/加载就可以了。
示例
这是一个基于您所描述的架构的示例,但使用了外键约束。此外,还有一种使用 profileurl 来建立关系的替代方法。
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,profileurl REFERENCES table_profile(profileurl));
INSERT OR IGNORE INTO table_profile VALUES
(null,'url1',10,'user1','blah1'),(null,'url2',100,'user2','blah2'),'url3','user3','blah3')
/* etc.... */,'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'),(SELECT profile_id FROM table_profile WHERE profileurl = 'url1'),'post_url2','post text 2nd post','url1'),'post_url3','post text 3rd post',(SELECT profile_id FROM table_profile WHERE profileurl = 'url3'),'post_url4','post text 4th post','url3'),'post_url5','post text 5th post','post_url6','post text 6th post','url1')
/* etc .... */
;
INSERT OR IGNORE INTO table_post_alt VALUES
(null,'does not matter','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;
运行上述结果(使用您的查询):-
并且(使用仅针对备用表名修改的查询):-
- 注意值
does not matter
已用于表明由于 FK 是 profileurl,因此 profile_Id 不匹配 并不重要(您可以使用与第一个选项相同的方法来获取正确的值但是数据没有完全规范化,无论如何它都不是原始值,因为您有两次出现 profileurl)。