我刚刚开始学习SQL,因此如果这个问题有点虚假,我深表歉意。
我有两个表:
direct_messages
users
direct_messages
表如下所示:
receiverId
和senderId
是我的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
中只有一个,并获得最新的消息。就像典型的邮件收件箱一样。
答案 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条消息:
可以通过以下查询来实现:
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
表结合起来以获取消息。