postgresql 如何基于公共列值包括两个表中的列,但只包括左表中的行?

mbjcgjjk  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(1)|浏览(149)

我有两个表tb1tb2。* * tb2通过外键tk_id连接到tb1**。这是我的两张table的样子

    • tb1 *
Column      |            Type             | Collation | Nullable |                     Default                      
-----------------+-----------------------------+-----------+----------+--------------------------------------------------
 id              | integer                     |           | not null | nextval('tb2_id_seq'::regclass)
 created_at      | timestamp without time zone |           | not null | 
 modified_at     | timestamp without time zone |           | not null | 
 status          | double precision            |           | not null | 
 tk_id           | uuid                        |           | not null |
    • tb2**
Column     |            Type             | Collation | Nullable | Default 
----------------+-----------------------------+-----------+----------+---------
 id             | uuid                        |           | not null | 
 created_at     | timestamp without time zone |           | not null | 
 modified_at    | timestamp without time zone |           | not null | 
 destination_id | uuid                        |           | not null | 
 source_id      | uuid                        |           | not null | 
 tk_id          | uuid                        |           | not null |

现在,我需要从tb1获取所有行,当tk_id值与两行匹配时,它包含来自tb1tb2的列。
这就是我所尝试的:

select tb1.created_at, tb1.status, tb2.source_id, tb2.destination_id from tb1 
inner join tb2 on tb1.tk_id = tb2.tk_id where 
tb1.created_at > timezone('utc', now()) - interval '40 minutes';

但我的排太多了。通常在40min间隔内,会有大约800条记录,但在加入后,我得到了大约**100,000 +**条记录。

    • 编辑:**经过一些阅读和尝试,我在查询中做了一些更改,并设法将行数减少到预期的行数。这是我现在的查询
SELECT count(*) FROM tb1 LEFT OUTER JOIN (SELECT DISTINCT tk_id FROM tb2) t2 
ON tb1.tk_id = t2.tk_id where tb1.created_at > timezone('utc', now()) - 
interval '40 minutes';

但是现在我无法在select查询中获取tb2的列。
我做错了什么?

nhhxz33t

nhhxz33t1#

由于对于tb1中的单个行而言,tb2中显然有许多行,因此您需要定义**选择哪一行。或者是聚合?
此查询返回tb1中所有符合条件的行,并添加tb2中最后创建的 one 匹配行(如果有)中的列:

SELECT tb1.created_at, tb1.status, tb2.*
FROM   tb1
LEFT   JOIN LATERAL (
   SELECT tb2.source_id, tb2.destination_id
   FROM   tb2
   WHERE  tb2.tk_id = tb1.tk_id
   ORDER  BY created_at DESC, id DESC
   LIMIT  1
   ) tb2 ON true
WHERE  tb1.created_at > timezone('utc', now()) - interval '40 minutes';

添加id DESC作为决胜局,因为created_at可能不是唯一的。
适应你未公开的需求。
相关内容:

  • PostgreSQL中的LATERAL JOIN和subquery有什么区别?
  • SQL:两个没有重复的聚合函数

tb2(tk_id, created_at, id)上使用索引支持此查询。
显然,tb1(created_at)上还有另一个索引。甚至是tb1(created_at) INCLUDE (tk_id, status)上的覆盖索引。参见:

相关问题