创建收件箱邮件类型的查询

时间:2019-03-02 20:01:44

标签: sql postgresql

我刚刚开始学习SQL,因此如果这个问题有点虚假,我深表歉意。

我有两个表:

  1. direct_messages
  2. users

direct_messages表如下所示:

enter image description here

receiverIdsenderId是我的users表的外键。

我要实现的是一个典型的收件箱消息查询。含义每发送一条与登录用户receiverId相同的消息,就得到一条消息,并得到最新消息。

我已经尝试了将近一整天的时间,而我来的却很“远”:

SELECT *
FROM "direct_messages" tm
LEFT JOIN "users" tu ON "tm.senderId" = "tu.id"
WHERE "tm.createdAt"
ORDER BY "created_at" DESC
LIMIT 1;

但是我刚得到ERROR: column "tm.senderId" does not exist

我所能获得的所有帮助,我们深表感谢。谢谢!

编辑: 根据要求,我添加了一些示例数据:https://gist.github.com/Martinnord/f07bc62389f2ecd0df8e6716dd797a15

我想要获得的消息列表具有特定的receiverId,但是每个唯一的senderId中只有一个,并获得最新的消息。就像典型的邮件收件箱一样。

2 个答案:

答案 0 :(得分:1)

Double quoting everything in Postgresql may be considered harmful,因为how double quotes work。仅在可能与关键字混淆时才使用它们。

"tm.senderId"并不表示senderId别名中的tm。因为用引号.表示准确标识符tm.senderId。 Postgres正在表tm.senderId中寻找列direct_messages,但找不到它。

相反,您应该谨慎地{@ {1}}引用表/别名和列。

这将导致下一个陷阱,即套管。除非使用引号,否则Postgres将为您使用小写的列和表名。

"tm"."senderId"

请注意,甚至表描述test=# create table direct_messages ( senderId integer ); CREATE TABLE test=# \d direct_messages Table "public.direct_messages" Column | Type | Collation | Nullable | Default ----------+---------+-----------+----------+--------- senderid | integer | | | 都具有误导性。

它会对查询中未引用的表和列执行相同的操作。

"public.direct_messages"

但是,如果您引用它们,它将寻找完全匹配的内容。

test=# select * from direct_messages tm where tm.sEnDerID is not null;
 senderid 
----------
(0 rows)

查询中的列名没有歧义,因此请删除双引号。

test=# select * from direct_messages tm where tm."sEnDerID" is not null;
ERROR:  column tm.sEnDerID does not exist
LINE 1: select * from direct_messages tm where tm."sEnDerID" is not ...

test=# select * from direct_messages tm where tm."senderId" is not null;
ERROR:  column tm.senderId does not exist
LINE 1: select * from direct_messages tm where tm."senderId" is not ...
                                               ^
HINT:  Perhaps you meant to reference the column "tm.senderid".

test=# select * from direct_messages tm where tm."senderid" is not null;
 senderid 
----------
(0 rows)

(旁注:将camelCase SELECT * FROM direct_messages tm LEFT JOIN users tu ON tm.senderId = tu.id WHERE tm.createdAt ORDER BY created_at DESC LIMIT 1; 和snake_case createdAt混合在一起会令人困惑。为项目选择一种样式并坚持使用。)

答案 1 :(得分:1)

正如某些人在评论中提到的那样,双引号存在问题,他们解释了如何处理。
我将向您展示如何解决您遇到的sql问题。 我将创建一个示例messages表。

CREATE TABLE messages (
  id BIGSERIAL PRIMARY KEY ,
  sender_id BIGINT ,
  reciever_id BIGINT,
  message TEXT,
  sent_at TIMESTAMP
);

现在让我们用一些数据填充该表:

INSERT INTO messages (sender_id, reciever_id, message, sent_at) VALUES
  (1,3,'User 1 to user 3 1 hour ago', '2017-07-10 15:00:00'),
  (1,3,'User 1 to user 3 last','2017-07-10 16:00:00'),
  (2,3,'User 2 to user 3 2 hours ago','2017-07-10 14:00:00'),
  (2,3,'User 2 to user 3 last','2017-07-10 16:00:00');

现在,让我们说,我们要查找使用id 3发送给用户的所有最近的消息(通过sender_id)。

因此,根据输入数据,结果应返回2条消息:

  1. 从用户1到用户3,值“用户1到用户3最后”
  2. 从用户2到用户3,其值为“用户2最后到用户3”

可以通过以下查询来实现:

WITH sender_last_message_time AS (
SELECT sender_id, MAX(sent_at) sent_at FROM messages
WHERE reciever_id = 3
GROUP BY sender_id )
SELECT * FROM messages m
JOIN sender_last_message_time r ON m.sender_id = r.sender_id AND r.sent_at = m.sent_at;

说明:

我创建sender_last_message_time CTE来保存每个发件人的最后一条消息时间(由sender_id发送)。一旦有了sender_id和该sender_id的上一条消息的时间,我就将数据与messages表结合起来以获取消息。