每组的最小行数

nic*_*ted 3 sql postgresql neo4j greatest-n-per-group sql-limit

以下是我的查询:

SELECT *
FROM (
    SELECT f.max, f.min, p.user_id, p.id, p.title, p.rating,
    RANK() OVER (
        PARTITION BY p.user_id
        ORDER BY p.rating DESC, p.id DESC
    ) AS rnk
    FROM posts AS p
    INNER JOIN friends AS f ON (p.user_id = f.friend_id)
    WHERE f.user_id=1
) AS subq
WHERE (subq.rnk <= subq.max)
LIMIT 10
Run Code Online (Sandbox Code Playgroud)

它会搜索我朋友的帖子,按照评分和日期排序.在此查询中实现的窗口函数允许我根据表上的MAX字段限制为每个朋友返回的行数Friends.

但是,我还有一个字段MIN,用于指定给定朋友的查询所需的最小帖子数.怎么可能?

我也想知道SQL是否是这些类型查询的最佳选择?我已经尝试过Neo4j Graph数据库,虽然它似乎是一个很好的解决方案,但我宁愿避免使用2个独立的数据库.

SQLFiddle

架构:

CREATE TABLE friends(
    user_id int,
    friend_id int,
    min int,
    max int
);

CREATE TABLE posts(
   id int,
   title varchar(255),
   rating int,
   date date,
   user_id int
);
Run Code Online (Sandbox Code Playgroud)

假设我们有以下数据:

INSERT INTO friends VALUES
  (1,2,1,3)
, (1,3,0,5)
, (1,4,2,10);

INSERT INTO posts VALUES
  (1,  'posts1',  2,  now(), 2)
, (2,  'posts2',  1,  now(), 2)
, (3,  'posts3',  5,  now(), 2)
, (4,  'posts4',  2,  now(), 2)
, (5,  'posts5',  11, now(), 2)
, (6,  'posts6',  7,  now(), 2)
, (7,  'posts7',  3,  now(), 2)
, (8,  'posts8',  4,  now(), 3)
, (9,  'posts9',  1,  now(), 3)
, (10, 'posts10', 0,  now(), 3)
, (11, 'posts11', 7,  now(), 3)
, (12, 'posts12', 3,  now(), 3)
, (13, 'posts13', 2,  now(), 3)
, (14, 'posts14', 4,  now(), 4)
, (15, 'posts15', 9,  now(), 4)
, (16, 'posts16', 0,  now(), 4)
, (17, 'posts17', 3,  now(), 4)
, (18, 'posts18', 2,  now(), 4)
, (19, 'posts19', 1,  now(), 4)
, (20, 'posts20', 2,  now(), 4);
Run Code Online (Sandbox Code Playgroud)

因此(post_id, title, rating, date, friend_id),如果可能,我希望看到具有以下条件的组合:

  1. 来自朋友的1到3个帖子id= 2
  2. 来自朋友的0到5个帖子之间id= 3
  3. 来自朋友的2到10个帖子id= 4

所以基本上,如果我的朋友friend_id=2发布了1篇或更多文章,我至少想要其中2篇.如果他发表了3篇以上的文章,我希望不超过3篇.

Erw*_*ter 5

假设我每天都要发来2-5个帖子,如果发帖那么多的话.如果你只张贴一张,那就没关系,我将只有一张贴子.

在评论中的解释仍然没有加起来.min根据此解释,您的号码将是无效的噪音.

这不是你写的,但这是有道理的:

鉴于帖子的最大显示位置(外部LIMIT),我想min首先从每个朋友那里获得帖子(如果有的话).如果之后有免费插槽,请填写max每位朋友的帖子.

在示例中,如果有更多的插槽仍然可用,那么min将从具有最高优先级的朋友2发布1()帖子,而另一个2(max - min)发布.

如果每个优先级没有足够的插槽,那么哪些帖子可以进行剪切是任意的.我继续并假设应首先选择每个帖子的第一个帖子,等等.

其余的仍然是任意的,但如果您设法制定要求,可以轻松解决.

SELECT *
FROM   friends f
,  LATERAL (
   SELECT *
        , row_number() OVER (ORDER  BY rating DESC NULLS LAST, id DESC) AS rn
   FROM   posts p
   WHERE  user_id = f.friend_id  -- LATERAL reference
   ORDER  BY rating DESC NULLS LAST, date DESC NULLS LAST
   LIMIT  f.max  -- LATERAL reference
   ) p
WHERE  f.user_id = 1
ORDER  BY (p.rn > f.min)  -- minimum posts from each first
        , p.rn
LIMIT  10;  -- arbitrary total maximum
Run Code Online (Sandbox Code Playgroud)

SQL小提琴.

笔记