为什么我的横向连接中的 LIMIT 被忽略了?

Why is the LIMIT in my lateral join being ignored?

我有一个 table 像这样:

create table cars (
    id serial primary key,
    au_rating integer,
    year integer
);

insert into cars (au_rating, year) VALUES 
  (1,2019),
  (1,2020),
  (1,2016),
  (2,2016),
  (2,2019),
  (3,2020),
  (3,2018),
  (3,2017),
  (3,2019),
  (3,2020),
  (0,2020),
  (0,2006)
;

我想 select 每个组中的第 N 个元素使用 JOIN LATERAL(类似于此:):

SELECT cars_outer.id, cars_top.au_rating, cars_top.year
FROM cars cars_outer
JOIN LATERAL (
    SELECT * FROM cars cars_inner
    WHERE cars_inner.au_rating = cars_outer.au_rating
    ORDER BY ABS(cars_inner.year - 2019)
    LIMIT 2
) cars_top on true
ORDER BY cars_outer.au_rating DESC

然而,由于我只希望在每组 au_rating 中最多有 2 行,我为横向连接提供了一个 LIMIT 2,但它似乎被忽略了 - 为什么?

http://sqlfiddle.com/#!17/c0704/5

如果您想要每个评分组的前 2 条记录,那么我建议使用 window 函数进行过滤。

你似乎想要的逻辑是:

select (c.c).*
from (
    select c, row_number() over(partition by au_rating order by year) rn
    from cars c
) c
where rn <= 2

我不确定您如何定义“前 2 名”记录。这按年份对记录进行排序,因此每个 au_rating 得到两个 oldest 记录。您可以将 order by 子句更改为您的实际需求。

Demo on DB Fiddle:

id | au_rating | year
-: | --------: | ---:
12 |         0 | 2006
11 |         0 | 2020
 3 |         1 | 2016
 1 |         1 | 2019
 4 |         2 | 2016
 5 |         2 | 2019
 8 |         3 | 2017
 7 |         3 | 2018

GMB 对您接受的 window 函数的回答是最好的。

LIMIT 在您的 LATERAL JOIN 查询中得到了尊重。问题是记录重复,而您省略了 DISTINCT.

更新

我没有提到您想要 cars_top.id 而不是 cars_outer.id,并且 DISTINCT 意味着 order_by 列必须在结果中。

SELECT DISTINCT cars_top.id, cars_top.au_rating, cars_top.year
    FROM cars cars_outer
    JOIN LATERAL (
        SELECT * FROM cars cars_inner
        WHERE cars_inner.au_rating = cars_outer.au_rating
        ORDER BY ABS(cars_inner.year - 2019)
        LIMIT 2
    ) cars_top on true
  ORDER BY cars_top.au_rating DESC

您的查询完全您所请求的。对于您 table 中的每辆车,它会返回匹配的汽车。

您可以通过让第一个“table”仅标识您想要的评级来做您想做的事:

SELECT cars_top.au_rating, cars_top.year
FROM (SELECT DISTINCT au_rating FROM cars
     ) cars_outer CROSS JOIN LATERAL
     (SELECT *
      FROM cars cars_inner
      WHERE cars_inner.au_rating = cars_outer.au_rating
      ORDER BY ABS(cars_inner.year - 2019)
      LIMIT 2
     ) cars_top 
ORDER BY cars_outer.au_rating DESC;

请注意,如果您使用 CROSS JOIN LATERAL,则不需要 ON 子句。