【问题标题】:Postgres Materialized Path Search using Bookshelf使用书架的 Postgres 物化路径搜索
【发布时间】:2014-09-23 17:45:18
【问题描述】:

假设我正在使用物化路径来存储管理链:

  Table: User
  id           name             management_chain
  1            Senior VP        {1}
  2            Middle Manager   {1,2}
  3            Cubicle Slave    {1,2,3}
  4            Janitor          {1,2,4}

如果给定一个返回其所有直接下属的用户 ID,我如何构造一个查询,例如,给定中间经理,它应该返回 Cubicle Slave 和 Janitor,给定高级副总裁,它应该返回中间经理。换句话说,什么是获取所有记录的好方法,其中management_chain 包含在倒数第二个位置查询的 id(假设最后一项代表用户自己的 id)。

也就是说,我如何表示下面的SQL:

SELECT *
FROM USER u 
WHERE u.management_chain @> {stored_variable, u.id}

我现在的 JS:

 var collection = Users.forge()
    .query('where', 'management_chain', '@>', [req.user.id, id]);

出现哪些错误

ReferenceError: id is not defined

【问题讨论】:

    标签: sql postgresql bookshelf.js knex.js materialized-path-pattern


    【解决方案1】:

    假设 management_chain 是一个整数数组 (int[]),您可以执行以下操作(在普通 SQL 中)

    select *
    from (
      select id,
             name,
             '/'||array_to_string(management_chain, '/') as path
      from users
    ) t
    where path like '%/2/%';
    

    这是可行的,因为array_to_string() 不会将分隔符附加到字符串的末尾。因此,如果路径包含序列/2/,则意味着该路径“下方”有更多节点。 2 是 management_chain 中最后一个 id 的节点将以 /2 结尾(没有尾随 /)并且不会包含在结果中。

    表达式不会使用索引,因此这对于大型表可能不可行。

    但是我不知道这会如何转化为 JS 的东西。

    SQLFiddle 示例:http://sqlfiddle.com/#!15/75948/2

    【讨论】:

      【解决方案2】:

      递归查找

      作为一个例子,看看这段代码:

      CREATE VIEW
          mvw_pre_import_cellpath_check
          (
              pkid_cell,
              id_cell  ,
              id_parent,
              has_child,
              id_path  ,
              name_path,
              string_path
          ) AS WITH RECURSIVE cell_paths
          (
              pkid_cell,
              id_cell  ,
              id_parent,
              id_path  ,
              name_path
          ) AS
          (
           SELECT
                      tbl_cell.pkid                     ,
                      tbl_cell.cell_id                  ,
                      tbl_cell.cell_parent_id           ,
                      ARRAY[tbl_cell.cell_id]   AS "array",
                      ARRAY[tbl_cell.cell_name] AS "array"
                 FROM
                      ufo.tbl_cell
                WHERE
                      (((
                                  tbl_cell.cell_parent_id IS NULL)
                              AND (
                                  tbl_cell.reject_reason IS NULL))
                          AND (
                              tbl_cell.processed_dt IS NULL))
        UNION ALL
           SELECT
                      tbl_cell.pkid                             ,
                      tbl_cell.cell_id                          ,
                      tbl_cell.cell_parent_id                   ,
                      (cell_paths_1.id_path || tbl_cell.cell_id),
                      (cell_paths_1.name_path || tbl_cell.cell_name)
                 FROM
                      (cell_paths cell_paths_1
                 JOIN
                      ufo.tbl_cell
                   ON
                      ((
                              tbl_cell.cell_parent_id = cell_paths_1.id_cell)))
                WHERE
                      (((
                                  NOT (
                                      tbl_cell.cell_id = ANY (cell_paths_1.id_path)))
                              AND (
                                  tbl_cell.reject_reason IS NULL))
                          AND (
                              tbl_cell.processed_dt IS NULL))
          )
       SELECT
              cell_paths.pkid_cell,
              cell_paths.id_cell  ,
              cell_paths.id_parent,
              (
               SELECT
                          COUNT(*) AS COUNT
                     FROM
                          ufo.tbl_cell x
                    WHERE
                          ((
                                  cell_paths.id_cell = x.cell_id)
                              AND (
                                  EXISTS
                                  (
                                   SELECT
                                              1
                                         FROM
                                              ufo.tbl_cell y
                                        WHERE
                                              (
                                                  x.cell_id = y.cell_parent_id))))) AS has_child,
              cell_paths.id_path                                                                ,
              cell_paths.name_path                                                              ,
              array_to_string(cell_paths.name_path, ' -> '::text) AS string_path
         FROM
              cell_paths
         ORDER BY
              cell_paths.id_path;
      

      在寻找递归 CTE 时,还有很多关于 SO 的示例。 但与您的示例相反,在我的示例中,顶级单元(经理)具有 parent_id = NULL。这些是不同分支的起点。

      HTH

      【讨论】:

      • 我看不出这与问题中提出的表结构至少有远程关系。
      猜你喜欢
      • 2012-06-07
      • 1970-01-01
      • 1970-01-01
      • 2015-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-03
      相关资源
      最近更新 更多