使用 PostgreSQL 将两个选择查询的结果添加到一个表行中

Posted

技术标签:

【中文标题】使用 PostgreSQL 将两个选择查询的结果添加到一个表行中【英文标题】:Adding the results of two select queries into one table row with PostgreSQL 【发布时间】:2013-12-05 14:49:46 【问题描述】:

我试图将两个不同的选择语句的结果返回到 PostgreSQL 中的一行。例如,我有两个查询,每个查询都返回相同的行数:

从table1中选择tableid1、tableid2、tableid3

+----------+----------+----------+
| tableid1 | tableid2 | tableid3 |
+----------+----------+----------+
|        1 |        2 |        3 |
|        4 |        5 |        6 |
+----------+----------+----------+ 

从table2中选择table2id1、table2id2、table2id3、table2id4

+-----------+-----------+-----------+-----------+
| table2id1 | table2id2 | table2id3 | table2id4 |
+-----------+-----------+-----------+-----------+
|         7 |         8 |         9 |        15 |
|        10 |        11 |        12 |        19 |
+-----------+-----------+-----------+-----------+

现在我想连接这些表以保持相同的行数。我不想加入任何价值观。期望的结果如下所示:

+----------+----------+----------+-----------+-----------+-----------+-----------+
| tableid1 | tableid2 | tableid3 | table2id1 | table2id2 | table2id3 | table2id4 |
+----------+----------+----------+-----------+-----------+-----------+-----------+
|        1 |        2 |        3 |         7 |         8 |         9 |        15 |
|        4 |        5 |        6 |        10 |        11 |        12 |        19 |
+----------+----------+----------+-----------+-----------+-----------+-----------+

我可以对上面的两个查询(select * from table1)和(select * from table2)做些什么来返回上面想要的结果。

谢谢!

【问题讨论】:

您需要按某列排序的行吗?我的意思是你介意在结果的第一行有tableid1 = 4,在第二行有tableid1 = 1? 是的,我将结果反馈到 java 中,我需要按设定的顺序引用列。我实际上正在做类似 (select tableid1, tableid2, tableid3 from table1) 和 (select table2id1, table2id2, table2id3, and table2id4 from table2) 所以如果它们可以保持相同的顺序,那就太好了 @user2255175 在那些SELECTs 中没有没有排序。数据库服务器可以按照它想要的任何顺序返回它们。你需要一个ORDER BY 子句。目前只是靠运气以某种特定的顺序回来。 ...实际上,无论您做什么,您都正在进行连接。您实际上是在问“我如何在不进行联接的情况下进行联接”。 【参考方案1】:

您可以使用row_number() 进行连接,但我不确定您是否能保证行的顺序与表格中的顺序相同。所以最好在over() 子句中添加一些顺序。

with cte1 as (
   select
       tableid1, tableid2, tableid3, row_number() over() as rn
   from table1
), cte2 as (
   select
       table2id1, table2id2, table2id3, table2id4, row_number() over() as rn
   from table2
)
select *
from cte1 as c1
    inner join cte2 as c2 on c2.rn = c1.rn

【讨论】:

如果在SELECTs 或row_number() 窗口子句中没有ORDER BY 子句,则此结果非常不可靠。 @user2255175 现在的工作就像一个魅力。这将在以后破裂,并可怕地破裂。它基本上只是为每个表动态生成一个主键,基本上随机为每一行选择一个键,然后加入这些行。为什么不首先在表上拥有正确的主键【参考方案2】:

你不能得到你想要的,因为你写了这个问题。您的两个SELECTs 没有任何ORDER BY 子句,因此数据库可以按照感觉的任何顺序返回行。如果它当前匹配,它只会偶然匹配,并且会在您UPDATE 一行后立即停止匹配。

您需要一个键列。然后你需要加入关键列。其他任何东西都试图在不实际使用连接的情况下发明不可靠和不安全的连接。

坦率地说,这似乎是一个非常狡猾的架构。许多像这样编号的整数列,以及连接它们的愿望,可能是您应该考虑使用整数数组或使用具有外键关系的边表的标志。

样本数据以防其他人想玩:

CREATE TABLE table1(tableid1 integer, tableid2 integer, tableid3 integer);
INSERT INTO table1 VALUES (1,2,3), (4,5,6);

CREATE TABLE table2(table2id1 integer, table2id2 integer, table2id3 integer, table2id4 integer);
INSERT INTO table2 VALUES (7,8,9,15), (10,11,12,19);

根据你实际在做什么,你可能真的想要数组。

我认为您可能需要阅读以下两篇文章:

Join 2 sets based on default order

How keep data don't sort?

这解释了 SQL 表只是没有顺序。因此,您无法按特定顺序获取它们。

请勿使用以下代码,这是危险的,仅作为概念验证包含在其中

碰巧你可以使用集合返回函数hack来非常低效地做你想做的事。如果在SELECTs 中没有ORDER BY,它会非常丑陋和*完全不安全,但为了完整起见,我会包含它。我猜。

CREATE OR REPLACE FUNCTION t1() RETURNS SETOF table1 AS $$ SELECT * FROM table1 $$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION t2() RETURNS SETOF table2 AS $$ SELECT * FROM table2 $$ LANGUAGE sql;
SELECT (t1()).*, (t2()).*;

如果您在任何实际代码中使用它,那么小猫会哭泣。如果表中的行数不同,它会产生疯狂而奇怪的结果,并且它会产生一开始看起来正确但随后会随机出现错误的行。

理智的方法是正确添加主键,然后进行连接。

【讨论】:

以上是关于使用 PostgreSQL 将两个选择查询的结果添加到一个表行中的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL 查询把多条记录合并一条

选择 Count (distinct col) 查询以显示结果中的行数和列数 - postgresql

如何在 postgresql 中使用不同的返回数据执行多个选择查询?

postgresql关于in和exists使用

将查询结果存储在变量中以在 Postgresql 中的另一个查询中使用

PostgreSQL:根据哪个为空,选择两个字段之一