如何在postgresql中创建嵌套的实体化视图?

时间:2014-03-31 14:31:06

标签: sql postgresql nested-sets

我有分层的父子数据。我希望有一个嵌套的视图,我可以查询该数据。似乎将这个嵌套集视图保存到表中最安全的方法是它实际上是原始数据的postgresql视图。

raw_data (
    id INTEGER PRIMARY KEY,
    parent INTEGER NULL
)

我正在寻找一种方法来转换raw_data nested_set_view作为视图创建语句的一部分。

nested_set_view (
    id INTEGER PRIMARY KEY,
    lft INTEGER NOT NULL,
    rgt INTEGER NOT NULL
)

出于某种原因,我想象如果nested_set_view就像

那样可能会更容易或更有效率
nested_set_view (
    id INTEGER PRIMARY KEY,
    lft INTEGER NOT NULL,
    rgt INTEGER NOT NULL,
    root INTEGER NOT NULL
)

1 个答案:

答案 0 :(得分:0)

CAVEAT(S)

  1. 验证您的Postgres版本是否支持实体化视图!
  2. 请记住,您无法(直接)更新实体化视图
  3. 这就是我们如何实现一个与你提议的结构非常相似的结构

    以下代码块创建实体化视图:

    WITH
        RECURSIVE cell_paths
        (
            id_cell  ,
            id_parent,
            id_path  ,
            name_path
        ) AS
        (
         SELECT
                    tbl_cell.pkid                  ,
                    tbl_cell.fk_parent             ,
                    ARRAY[tbl_cell.pkid]      AS "array",
                    ARRAY[tbl_cell.cell_name] AS "array"
               FROM
                    tbl_cell
              WHERE
                    (
                        tbl_cell.fk_parent IS NULL)
      UNION ALL
         SELECT
                    tbl_cell.pkid                          ,
                    tbl_cell.fk_parent                     ,
                    (cell_paths_1.id_path || tbl_cell.pkid),
                    (cell_paths_1.name_path || tbl_cell.cell_name)
               FROM
                    (cell_paths cell_paths_1
               JOIN
                    tbl_cell
                 ON
                    ((
                            tbl_cell.fk_parent = cell_paths_1.id_cell)))
              WHERE
                    (
                        NOT (
                            tbl_cell.pkid = ANY (cell_paths_1.id_path)))
        )
    SELECT
            cell_paths.id_cell  ,
            cell_paths.id_parent,
            (
             SELECT
                        COUNT(*) AS COUNT
                   FROM
                        tbl_cell x
                  WHERE
                        ((
                                cell_paths.id_cell = x.pkid)
                            AND (
                                EXISTS
                                (
                                 SELECT
                                            1
                                       FROM
                                            tbl_cell y
                                      WHERE
                                            (
                                                x.pkid = y.fk_parent))))) 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;
    

    每当我们需要更新视图时,都会调用以下函数

    CREATE OR REPLACE FUNCTION "public"."fn_refresh_mvw_cellpath" ()  RETURNS trigger
    VOLATILE
    AS $dbvis$
    BEGIN
                        REFRESH MATERIALIZED VIEW mvw_cellpath;
                        RETURN NEW;
                        END;
    $dbvis$ LANGUAGE plpgsql
    

    从功能定义可以看出,我们决定每当对表进行更改时都必须更新视图。在这种情况下我们的表tbl_cell

    CREATE TRIGGER "tr_refresh_mvw_cellpath"
      AFTER INSERT OR DELETE OR UPDATE ON tbl_cell
      FOR EACH STATEMENT
    EXECUTE PROCEDURE fn_refresh_mvw_cellpath()
    

    此触发器将在每次更新或插入tbl_cell时执行刷新视图调用。这样我们可以保证物化视图是最新的。当然,您需要决定运行刷新的成本是否值得。可能你只需要每天更新一次视图或....

    希望这有帮助。

    (激动人心:我的第一篇文章是stackoverflow。希望我以正确的方式做到了。)