用于根据连接拆分表的SQL语句

时间:2010-03-20 18:02:58

标签: sql postgresql join sql-insert sql-delete

我有一个用于文章的主表,它通过连接表信息链接到表只有少量条目的标签。我想根据缺少某个标签的链接,通过删除行或创建只包含我想要的条目的新表来拆分Articles表。有几百万篇文章。我怎么能这样做?

并非所有文章都有任何标记,有些标记有很多标记。

示例:

table Articles
  primary_key id
table Info
  foreign_key article_id
  foreign_key tag_id
table Tags
  primary_key id

我很容易将那些确实具有匹配性的文章分开,所以我想也许我可以做到然后使用NOT IN语句但是运行速度很慢不清楚它是否会发生完。我用这些命令做到了:

INSERT INTO matched_articles SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5;
INSERT INTO unmatched_articles SELECT * FROM articles a WHERE a.id NOT IN (SELECT m.id FROM matched_articles m);

如果它有所作为,我就是Postgres。

3 个答案:

答案 0 :(得分:1)

您的查询看起来不错,但第一个应该是内连接,而不是左连接。如果你想尝试别的东西,请考虑一下:

INSERT INTO matched_articles 
SELECT * 
FROM articles a 
INNER JOIN info i ON a.id = i.article_id 
WHERE i.tag_id = 5;

INSERT INTO unmatched_articles 
SELECT * 
FROM articles a 
LEFT JOIN info i ON a.id = i.article_id AND a.id <> 5
WHERE a.id IS NULL

这可能会更快,但实际上,如果你只需要做一次就可以了。

答案 1 :(得分:1)

INSERT INTO matched_articles 
SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 

INSERT INTO unmatched_articles 
SELECT * FROM articles a WHERE a.id NOT IN (SELECT m.id FROM matched_articles m); 

这里有太多错误,我不知道从哪里开始。在你的第一个插入中确定你不需要左连接,实际上你实际上没有。它应该是

INSERT INTO matched_articles 
SELECT * FROM articles a INNER JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 

如果你需要一个左连接,你就会有

INSERT INTO matched_articles 
SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id AND i.tag_id = 5; 

当您将左连接右侧的内容放入where子句(搜索空值除外)时,您将其转换为内连接,因为它必须满足该条件,因此记录不要在右表中有一个匹配被删除。

现在可以使用左连接的特殊情况完成第二个语句,尽管你的工作会有效。

INSERT INTO matched_articles 
SELECT * FROM articles a 
LEFT JOIN info i ON a.id = i.article_id AND i.tag_id = 5
WHERE i.tag_id is null

这将为您提供info表中除了与articles表匹配的记录之外的所有记录。

接下来,您不应该在未指定要插入的字段的情况下编写插入符号。你也不应该使用select *编写一个select语句,特别是如果你有一个连接。这通常是草率的,懒惰的编码,应该修复。如果有人改变了其中一个表的结构而不改变另一个表的结构怎么办?这种情况对于维护是不利的,并且在具有连接的选择状态的情况下,它返回两次匹配(连接列)并且这浪费了服务器和网络资源。只是糟糕的编码太懒,指定你需要的东西,只有你需要的东西。因此,戒掉习惯,不要再为任何生产代码再做一次。

如果您当前的展示太慢,您也可以使用正确的索引修复它。两个表上的id字段都被索引了吗?另一方面,如果有数百万篇文章,那么插入它们需要时间。通常最好这样做一次可能是50000(如果这需要太长时间,则更少)。只需执行插入ina循环,选择顶部XXX记录,然后循环,直到受影响的行数为无。

答案 2 :(得分:1)

不确定,如果Postgres有临时表的概念 以下是如何做到这一点。

CREATE Table #temp
AS SELECT A.ID, COUNT(i.*) AS Total
FROM Articles A
LEFT JOIN info i
ON A.id = i.Article_ID AND i.Tag_ID = 5
GROUP BY A.ID

INSERT INTO Matched_Articles
SELECT A.*
FROM Articles A INNER JOIN #temp t
ON A.ID = t.Article_ID AND T.Total = 0

DELETE FROM #Temp
WHERE Total = 0

INSERT INTO UnMatched_Articles
SELECT A.*
FROM Articles AINNER JOIN #temp t
ON A.ID = t.Article_ID

请注意,我没有使用任何编辑器来尝试这一点 我希望这能给你提示我将如何处理这个问题。