如何 "join" postgres 中的两个表
how to "join" two tables in postgres
我有两个table包含几乎相同的东西。但是他们从不同的来源获得数据,在完美世界中它们是相同的。实际上 - 他们不同。目标是找到匹配的记录并相互连接,然后不匹配的记录就是结果。
first_table:
id1, date1, value1
second_table:
id2、date2、value2
我创建第三个table"joiner":
id1,id2
现在使用这个法术:
INSERT INTO joiner (SELECT id1,id2 FROM first_table,second_table WHERE value1=value2 and date1=date2 ORDER BY date1,date2,id1,id2);
(排序很重要,因为有时候会漏掉一些包,所以我得稍后再补充)
一切都会很好,但是...有时会有多个记录具有相同的值和日期,并且无法识别它。公认的解决方案是首先从 first_table 加入,第一个从 second_table 加入,第二个从 first_table 加入,第二个从 second_table 加入,等等
问题来了。
因为连接器在每一列上都有唯一键 - 插入会引发 unique_violation 错误,因为示例结果是:
id1|id2
-------
a1| b1
a1| b2
a2| b1
a2| b2
如果我使用 SELECT 不同的 id1,id2 当然没有任何变化 (a1,b1)!=(a1,b2)
如果我在 (id1) id1,id2 上使用 SELECT distinct - 结果有时是:
id1|id2
-------
a1| b1
a2| b1
我尝试使用 WHERE NOT EXISTS (SELECT 1 FROM first_table f WHERE f.id1<>first_table.id1) AND NOT EXISTS (SELECT 1 FROM second_table s WHERE s.id2<>second_table.id2) - 仍然没有
我尝试使用 EXCEPTION 添加函数,但这也是错误的 - 因为它引发了异常但 joiner 仍然是空的...
有什么想法吗?
更新
我不知道为什么有些人不加评论就对我的问题投反对票。也许是因为它不够清楚 - 所以特别是对于那些例子:
first_table:
id1, value1, date1
1,10, 2015-03-01
2,11, 2015-03-01
3,10, 2015-03-01
4,14, 2015-03-02
second_table:
id2, value2, date2
1,10, 2015-03-01
2,11, 2015-03-01
3,10, 2015-03-01
4,15, 2015-03-02
预期加入者
id1, id2
1,1
2,2
3,3
如您所见,id1=4 和 id2=4 没有连接符 - 因为值不同(审核员需要手动检查和修复)。
并且 id1=1 和 id1=3 存在问题 - 相同,因此没有唯一性的连接器看起来像:
id1, id2
1,1
1,3
2,2
3,1
3,3
这是错误的。
您的问题的解决方案是使用 row_number()
枚举每个 table.
中常见 date/value 对的值
您的查询也可以通过其他方式改进:
- 使用
insert
时,始终列出列。
- 学习使用正确的显式
join
语法。简单规则:永远不要在 from
子句中使用逗号。
- 使用 table 别名指定列的来源。
查询是:
INSERT INTO joiner(id1, id2)
SELECT id1, id2
FROM (select ft.*, row_number() over (partition by value1, date1 order by value1) as seqnum
from first_table ft
) ft JOIN
(select st.*, row_number() over (partition by value2, date2 order by value2) as seqnum
from second_table st
) st
ON ft.value1 = st.value2 and ft.date1 = st.date2 and ft.seqnum = st.seqnum
ORDER BY ft.date1, st.date2, ft.id1, st.id2;
我认为 order by
不重要,但我保留它是因为您认为它相关。
我有两个table包含几乎相同的东西。但是他们从不同的来源获得数据,在完美世界中它们是相同的。实际上 - 他们不同。目标是找到匹配的记录并相互连接,然后不匹配的记录就是结果。
first_table:
id1, date1, value1
second_table:
id2、date2、value2
我创建第三个table"joiner":
id1,id2
现在使用这个法术:
INSERT INTO joiner (SELECT id1,id2 FROM first_table,second_table WHERE value1=value2 and date1=date2 ORDER BY date1,date2,id1,id2);
(排序很重要,因为有时候会漏掉一些包,所以我得稍后再补充)
一切都会很好,但是...有时会有多个记录具有相同的值和日期,并且无法识别它。公认的解决方案是首先从 first_table 加入,第一个从 second_table 加入,第二个从 first_table 加入,第二个从 second_table 加入,等等
问题来了。
因为连接器在每一列上都有唯一键 - 插入会引发 unique_violation 错误,因为示例结果是:
id1|id2
-------
a1| b1
a1| b2
a2| b1
a2| b2
如果我使用 SELECT 不同的 id1,id2 当然没有任何变化 (a1,b1)!=(a1,b2) 如果我在 (id1) id1,id2 上使用 SELECT distinct - 结果有时是:
id1|id2
-------
a1| b1
a2| b1
我尝试使用 WHERE NOT EXISTS (SELECT 1 FROM first_table f WHERE f.id1<>first_table.id1) AND NOT EXISTS (SELECT 1 FROM second_table s WHERE s.id2<>second_table.id2) - 仍然没有
我尝试使用 EXCEPTION 添加函数,但这也是错误的 - 因为它引发了异常但 joiner 仍然是空的...
有什么想法吗?
更新 我不知道为什么有些人不加评论就对我的问题投反对票。也许是因为它不够清楚 - 所以特别是对于那些例子:
first_table:
id1, value1, date1
1,10, 2015-03-01
2,11, 2015-03-01
3,10, 2015-03-01
4,14, 2015-03-02
second_table:
id2, value2, date2
1,10, 2015-03-01
2,11, 2015-03-01
3,10, 2015-03-01
4,15, 2015-03-02
预期加入者
id1, id2
1,1
2,2
3,3
如您所见,id1=4 和 id2=4 没有连接符 - 因为值不同(审核员需要手动检查和修复)。
并且 id1=1 和 id1=3 存在问题 - 相同,因此没有唯一性的连接器看起来像:
id1, id2
1,1
1,3
2,2
3,1
3,3
这是错误的。
您的问题的解决方案是使用 row_number()
枚举每个 table.
您的查询也可以通过其他方式改进:
- 使用
insert
时,始终列出列。 - 学习使用正确的显式
join
语法。简单规则:永远不要在from
子句中使用逗号。 - 使用 table 别名指定列的来源。
查询是:
INSERT INTO joiner(id1, id2)
SELECT id1, id2
FROM (select ft.*, row_number() over (partition by value1, date1 order by value1) as seqnum
from first_table ft
) ft JOIN
(select st.*, row_number() over (partition by value2, date2 order by value2) as seqnum
from second_table st
) st
ON ft.value1 = st.value2 and ft.date1 = st.date2 and ft.seqnum = st.seqnum
ORDER BY ft.date1, st.date2, ft.id1, st.id2;
我认为 order by
不重要,但我保留它是因为您认为它相关。