代码之家  ›  专栏  ›  技术社区  ›  Jess

如何查询postgresql/sql中数组字段的订阅

  •  0
  • Jess  · 技术社区  · 8 年前

    我的数据包括可以被分为多个类别(恐怖、戏剧、喜剧等)的书籍。用户可以订阅一个类别,我希望能够对具有指定类别的所有图书的books表执行分页查询。示例架构:

    CREATE TABLE IF NOT EXISTS books (
      bookid uuid PRIMARY KEY,
      categories uuid[],
      name text,
      author text,
      releasedate timestamp
    );
    
    CREATE TABLE IF NOT EXISTS categories (
      categoryid uuid PRIMARY KEY,
      name text
    );
    
    CREATE TABLE IF NOT EXISTS users (
      userid uuid PRIMARY KEY,
      name text
    );
    
    CREATE TABLE IF NOT EXISTS catsubscribers (
      categoryid uuid REFERENCES categories,
      userid uuid REFERENCES users,
      PRIMARY KEY (categoryid,  userid)
    );
    
    CREATE TABLE IF NOT EXIST bookcats (
      bookid uuid REFERENCES books,
      categoryid uuid REFERENCES categories,
      PRIMARY KEY (bookid, categoryid)
    );
    
    CREATE OR REPLACE FUNCTION getBooksBySubscribedCategory(me uuid, ofst integer, lim integer)
    RETURNS TABLE(bookid uuid, categories uuid[], name text, author text, releasedate timestamp) AS $$
      DECLARE cid RECORD;
      BEGIN
        FOR cid IN (SELECT categoryid FROM catsubscribers WHERE userid = me)
        LOOP
          RETURN QUERY SELECT bks.bookid, bks.categories, bks.name, bks.author, bks.releasedate
          FROM (SELECT bookid, categories, name, author, releasedate FROM books WHERE bookid IN (SELECT bookid FROM bookcats WHERE categoryid = cid ) AS bks
          ORDER BY releasedate DESC
          OFFSET ofst
          LIMIT lim;
        END LOOP;
        RETURN;
      END;
    $$ LANGUAGE plpgsql;
    

    此函数获取用户订阅的类别数组,并在bookcats连接表中循环每个类别和查询书籍。这是我的蛮力第一次尝试--很难看,我不确定是否因为循环而得到正确的分页。有更好的办法吗?

    2 回复  |  直到 8 年前
        1
  •  1
  •   Shivam Batra    8 年前

    你根本不需要循环,

    RETURN QUERY 
    SELECT bks.bookid, bks.categories, bks.name, bks.author, bks.releasedate
    from books bks join bookcats bc on bc.bookid = bks.bookid
    join catsubscribers cs on cs.categoryid = bc.categoryid
    where cs.userid = me 
    group by bks.bookid, bks.categories, bks.name, bks.author, bks.releasedate
    limit lim offset ofst
    
        2
  •  1
  •   nimish    8 年前

    OFFSET LIMIT 是经典的选择,但当您遇到性能问题时,还需要考虑其他因素: https://use-the-index-luke.com/blog/2013-07/pagination-done-the-postgresql-way https://use-the-index-luke.com/sql/partial-results/fetch-next-page 很好地概述了如何实现性能分页。

    结果是保持外部所需的页面状态,而不是偏移/限制,使用 WHERE filter,通过在 releasedate 在当前页面之前,并将其限制为页面大小。