我有一个 postgresql 数据库,我正在尝试查询,这是我当前的代码:
SELECT r.id, r.band_id, r.title, r.imageURL, v.rating, b.name AS bandname, l.price
FROM records r
JOIN bands b ON b.id=r.band_id
LEFT JOIN (SELECT record_id, AVG(rating)::NUMERIC(10,1) as rating
FROM reviews
GROUP BY record_id) v
ON v.record_id = r.id
LEFT JOIN (SELECT record_id, MIN(price) as price
FROM listings
GROUP BY record_id) l
ON l.record_id = r.id
感觉比需要的要慢得多、笨重得多。
SELECT r.id, r.band_id, r.title, r.imageURL, b.name AS bandname,
MIN(l.price) AS price, AVG(rating)::NUMERIC(10,1) as rating
FROM records r
JOIN bands b ON b.id=r.band_id
JOIN listings l ON l.record_id = r.id
JOIN reviews v ON v.record_id = r.id
GROUP BY r.id, r.band_id, r.title, r.imageURL, b.name
是我想要使用的查询,因为它看起来更好并且我认为会更有效,但是,最大的问题是该查询不会包含在每个评论中至少没有一个对应行的任何记录,并且清单表。我不明白为什么会这样。
我已经在几个不同的其他变体中尝试了上面的代码,这里的目标是获取记录的所有信息以及基于连接数据库的平均评级、最低价格和乐队名称,同时保留不包含的记录目前有任何相关评论或列表。 我是一个业余爱好者,但感觉我很好地掌握了子查询的工作原理,以及为什么需要 GROUP BY 语句而没有它们,但我很难理解为什么第二个代码片段省略了对应关系中至少没有一行的记录,而不是仅将其提供为 NULL。我也很难接受我可能不得不使用更长、更丑陋且(据我所知)更慢的查询来满足我的需求。
您的第二个查询根本不会给您正确的结果。
您直接的问题只需将两个
JOIN
更改为 LEFT JOIN
即可解决,但这仍然会给您带来无效结果,因为它会导致两个一对多关系之间出现笛卡尔交叉连接。换句话说,只有当只涉及单个一对多关系而不是多个关系时,才能使用这样的 GROUP BY
查询。
您可以使用
LATERAL
连接稍微简化现有查询(在 SQL Server 中这将是 OUTER APPLY
)。
SELECT
r.id,
r.band_id,
r.title,
r.imageURL,
v.rating,
b.name AS bandname,
l.price
FROM records r
JOIN bands b ON b.id = r.band_id
LEFT JOIN LATERAL (
SELECT AVG(rating::NUMERIC(10,1)) as rating -- prob need to convert BEFORE averaging
FROM reviews rv
WHERE rv.record_id = r.id
) ON 1=1
LEFT JOIN LATERAL (
SELECT MIN(price) as price
FROM listings l
WHERE l.record_id = r.id
) ON 1=1