3

以下は私の質問です:

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

友達の投稿を検索し、評価と日付で並べ替えます。このクエリに実装されたウィンドウ関数により、テーブルのMAXフィールドに従って、各フレンドに対して返される行数を制限できFriendsます。

ただし、フィールドもありますMIN。これは、特定の友人のクエリから必要な投稿の最小数を指定するために使用されます。そんなことがあるものか?

また、これらのタイプのクエリには SQL が最適なオプションなのだろうか? 私はすでに Neo4j Graph データベースを試しました。これは良い解決策のように思えましたが、2 つの別々のデータベースを使用することは避けたいと思います。

SQLフィドル

スキーマ:

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
);

次のデータがあるとします。

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);

(post_id, title, rating, date, friend_id)したがって、可能であれば、次の条件との組み合わせを確認したいと考えています。

  1. id=2の友人からの 1 ~ 3 件の投稿
  2. id=3の友達からの 0 ~ 5 件の投稿
  3. id=4の友人からの 2 ~ 10 件の投稿

基本的に、私の友人がfriend_id=21 つ以上の記事を投稿している場合、少なくとも 2 つの記事が必要です。彼が 3 つ以上の記事を投稿した場合、私は 3 つを超えないようにします。

4

3 に答える 3

5

あなたがそんなに投稿するなら、私はあなたから毎日2〜5件の投稿が欲しいとしましょう. 1つだけ投稿していただいても構いません。投稿は1つだけとさせていただきます。

コメントでのあなたの説明はまだ合計されていません。この説明によると、あなたのmin番号は効果のないノイズになります。

これはあなたが書いたものではありませんが、これは理にかなっています:

投稿の最大表示スロット (外側) が与えられた場合、最初に各友人から投稿LIMITを取得したいと考えています(利用可能な場合)。minそれ以降に空きスロットがある場合は、フレンドごとに最大 までmaxの投稿で埋めてください。

例ではmin、友人 2 からの 1 件 ( ) の投稿が最優先でありmax - min、さらにスロットがまだ利用可能な場合は別の 2 件 ( ) の投稿です。

各優先度に十分なスロットがない場合、どの投稿がカットされるかは任意です。私は先に進み、それぞれの最初の投稿を最初に選択する必要があると想定しました。

残りは任意ですが、要件を定式化できれば簡単に解決できます。

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

SQL フィドル。

ノート

  • friends.user_idandposts.idが主キーであると仮定します。テーブル定義がそこにありません。

  • NOT NULL他のすべての列は、意味を成すように定義する必要があります。

  • LATERAL結合を使用maxして、サブクエリで友人ごとの投稿のみを選択します。

  • サブクエリrow_number()ではなくrank()、を使用します。両方を混同するのはよくある間違いです。

  • 言及dateしましたが、クエリには表示されませんでした。多分あなたは本当に欲しい:

    , row_number() OVER (ORDER  BY rating DESC NULLS LAST
                                 , date   DESC NULLS LAST) AS rn
    
  • DESC NULLS LASTratinganddateが NULL になる可能性があるためです。

  • Postgres では、次のように単純なブール式を使用できますORDER BY

    ORDER  BY (p.rn > f.min), p.rn
    

    これによりmin、友達ごとの投稿が最初になります。2 番目の項目 ( p.rn) は、各友達に平等な機会を与えます (最初の投稿が最初など)。

  • date識別子として使用しないでください。これは、標準 SQL の予約語であり、Postgres の基本型名です。

于 2015-05-03T10:59:53.933 に答える
0

neo4j/cypher の観点からすると、これは本当にやりたいことだと思います...

match (u:User {id: 1})-[r:FOLLOWS]->(p:Publisher)
with u, p, r
match p-[:PUBLISHED]-(i:Item)
with u, p, r, i
order by i.name
return u.name, p.name, i.name
skip 5
limit 2

最小値と最大値をパラメーター化し、実行時にそれらをバインドする必要があるだけです。これには、1 つではなく 2 つのクエリが含まれますが、これはまだエレガントなソリューションだと思います。skip以前にプロパティを含めようとしましlimitたが、cypher は明らかにそれをサポートしていません (まだ)。パラメータまたは符号なし整数が必要です。

match (u:User {id: 1})-[r:FOLLOWS]->(p:Publisher)
with u, p, r
match p-[:PUBLISHED]-(i:Item)
with u, p, r, i
order by i.name
return u.name, p.name, i.name
skip {min}
limit {max}
于 2015-05-02T12:36:46.203 に答える