本来想用上一篇文章
中说的方法,强行在mysql上实现的,无奈还是太麻烦,相当一部分SQL需要改造,由于是新产品,干脆来个釜底抽薪,换PostgreSQL得了!
由于现在PostgreSQL用的人少,不想这么优秀的数据库被大家(尤其中国的程序员)忽视,把自己的一点心得贡献一下,希望能对PostgreSQL推广起点作用吧!
废话不说,看代码吧(测试表、测试数据都包含了,你准备好psql环境,直接执行就能看到效果):
另:编写的这四个函数,原则是尽量通用,因此把表名和自关联字段名作为参数传递进来。
-- postgresql 8.3
--
-- 测试用表和数据
--
DROP TABLE IF EXISTS test_tree;
CREATE TABLE test_tree (
id BIGINT NOT NULL PRIMARY KEY ,
name VARCHAR(64),
description VARCHAR(2048),
parent_id BIGINT REFERENCES test_tree(id)
);
-- 01-02-04-10
-- -11
-- -05-07
-- -08
-- -03-06-09
-- -12
INSERT INTO test_tree VALUES (1, '名字1', '描述1', null );
INSERT INTO test_tree VALUES (2, '名字2', '描述2', 1 );
INSERT INTO test_tree VALUES (3, '名字3', '描述3', 1 );
INSERT INTO test_tree VALUES (4, '名字4', '描述4', 2 );
INSERT INTO test_tree VALUES (5, '名字5', '描述5', 2 );
INSERT INTO test_tree VALUES (6, '名字6', '描述6', 3 );
INSERT INTO test_tree VALUES (7, '名字7', '描述7', 5 );
INSERT INTO test_tree VALUES (8, '名字8', '描述8', 5 );
INSERT INTO test_tree VALUES (9, '名字9', '描述9', 6 );
INSERT INTO test_tree VALUES (10, '名字10', '描述10', 4 );
INSERT INTO test_tree VALUES (11, '名字11', '描述11', 4 );
INSERT INTO test_tree VALUES (12, '名字12', '描述12', 6 );
CREATE LANGUAGE PLPGSQL;
--
-- 自关联表的向下递归
--
DROP FUNCTION IF EXISTS all_progeny_pk(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT);
CREATE OR REPLACE FUNCTION all_progeny_pk(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT) RETURNS SETOF BIGINT AS $PROC$
DECLARE
record_child RECORD; -- 直接子记录
record_childs_progeny RECORD; -- 直接子记录的后代
BEGIN
-- 遍历顺序:深度优先;输出顺序:父在前,子在后
FOR record_child IN EXECUTE $$SELECT t.$$ || pkFieldName || $$ AS pk FROM $$ || tableName || $$ AS t WHERE t.$$ || parentPkFieldName || $$ = '$$ || thisPk || $$' ORDER BY t.$$ || pkFieldName LOOP
RETURN NEXT record_child.pk;
FOR record_childs_progeny IN SELECT * FROM all_progeny_pk(tableName, pkFieldName, parentPkFieldName, record_child.pk) AS pk LOOP
RETURN NEXT record_childs_progeny.pk;
END LOOP;
END LOOP;
RETURN;
END;
$PROC$ LANGUAGE PLPGSQL;
COMMENT ON FUNCTION all_progeny_pk(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT) IS '查找某张自关联表中,某记录的所有子孙的主键(不包含自己)';
select * from all_progeny_pk('test_tree', 'id', 'parent_id', 1) AS pk;
DROP FUNCTION IF EXISTS all_progeny_pk_with_self(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT);
CREATE OR REPLACE FUNCTION all_progeny_pk_with_self(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT) RETURNS SETOF BIGINT AS $PROC$
DECLARE
record_progeny RECORD;
BEGIN
RETURN NEXT thisPk;
FOR record_progeny IN SELECT * FROM all_progeny_pk(tableName, pkFieldName, parentPkFieldName, thisPk) AS pk LOOP
RETURN NEXT record_progeny.pk;
END LOOP;
RETURN;
END;
$PROC$ LANGUAGE PLPGSQL;
COMMENT ON FUNCTION all_progeny_pk_with_self(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT) IS '查找某张自关联表中,某记录的所有子孙的主键(包含自己)';
select * from all_progeny_pk_with_self('test_tree', 'id', 'parent_id', 1) AS pk;
--
-- 自关联表的向上递归
--
DROP FUNCTION IF EXISTS all_ancestor_pk(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT);
CREATE OR REPLACE FUNCTION all_ancestor_pk(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT) RETURNS SETOF BIGINT AS $PROC$
DECLARE
record_parent RECORD; -- 直接父记录
record_parents_ancestor RECORD; -- 直接父记录的祖先
BEGIN
-- 输出顺序:父在前,子在后
FOR record_parent IN EXECUTE $$SELECT t.$$ || parentPkFieldName || $$ AS pk FROM $$ || tableName || $$ AS t WHERE t.$$ || pkFieldName || $$ = '$$ || thisPk || $$' ORDER BY t.$$ || pkFieldName LOOP
IF record_parent.pk IS NOT NULL THEN
FOR record_parents_ancestor IN SELECT * FROM all_ancestor_pk(tableName, pkFieldName, parentPkFieldName, record_parent.pk) AS pk LOOP
RETURN NEXT record_parents_ancestor.pk;
END LOOP;
RETURN NEXT record_parent.pk;
END IF;
END LOOP;
RETURN;
END;
$PROC$ LANGUAGE PLPGSQL;
COMMENT ON FUNCTION all_ancestor_pk(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT) IS '查找某张自关联表中,某记录的所有祖先的主键(不包含自己)';
select * from all_ancestor_pk('test_tree', 'id', 'parent_id', 12) AS pk;
DROP FUNCTION IF EXISTS all_ancestor_pk_with_self(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT);
CREATE OR REPLACE FUNCTION all_ancestor_pk_with_self(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT) RETURNS SETOF BIGINT AS $PROC$
DECLARE
record_ancestor RECORD;
BEGIN
FOR record_ancestor IN SELECT * FROM all_ancestor_pk(tableName, pkFieldName, parentPkFieldName, thisPk) AS pk LOOP
RETURN NEXT record_ancestor.pk;
END LOOP;
RETURN NEXT thisPk;
RETURN;
END;
$PROC$ LANGUAGE PLPGSQL;
COMMENT ON FUNCTION all_ancestor_pk_with_self(tableName VARCHAR, pkFieldName VARCHAR, parentPkFieldName VARCHAR, thisPk BIGINT) IS '查找某张自关联表中,某记录的所有祖先的主键(包含自己)';
select * from all_ancestor_pk_with_self('test_tree', 'id', 'parent_id', 12) AS pk;
注意:调用函数时,可以使用 "select funciton();" 也可以写 "select * from function()" 在linux上无问题,windows下第一种报错。
分享到:
相关推荐
PostgreSQL数据库内核分析PostgreSQL数据库内核分析PostgreSQL数据库内核分析PostgreSQL数据库内核分析PostgreSQL数据库内核分析PostgreSQL数据库内核分析PostgreSQL数据库内核分析PostgreSQL数据库内核分析...
良好的数据库文档应包含表定义、字段信息、索引、视图、存储过程等。 3. **数据库表结构**:数据库表结构是数据库的核心组成部分,它定义了数据如何在表中组织。表结构包括表格名、字段名、数据类型、主键、外键、...
在Python中,通常会使用如`psycopg2`这样的库来连接和操作PostgreSQL数据库。`psycopg2`是Python的一个扩展模块,提供了与PostgreSQL数据库通信的接口。比对程序可能使用了SQL查询来获取数据库的表结构、索引、约束...
PostgreSQL数据库内核分析.pdf
PostgreSQL 是一个功能强大且广泛使用的开源关系数据库管理系统,但是在实际应用中,数据库崩溃或无法启动的情况时有发生。这时,如何恢复 PostgreSQL 数据库变得非常重要。下面将详细介绍如何恢复 PostgreSQL ...
PostgreSQL 中的存储过程可以使用函数来实现,函数可以封装一组 SQL 语句,以便于重复使用和提高效率。在 .NET 中,可以使用 Npgsql 组件来连接 PostgreSQL 数据库,并使用函数来查询数据。本文详细介绍了 ...
本文将深入探讨如何使用C#来操作PostgreSQL数据库。 首先,我们需要安装必要的库以在C#中与PostgreSQL进行交互。Npgsql是.NET Framework和.NET Core下的一个开源驱动,它允许C#应用程序无缝连接到PostgreSQL数据库...
PostgreSQL数据库内核分析 清晰版,完整415页
文档中提到的pg_dump是PostgreSQL提供的一个命令行工具,它专门用于导出数据库到一个SQL脚本文件中,或者归档文件(使用`-Fc`参数)。这个命令支持数据库的完全备份和部分备份。完全备份涉及整个数据库的数据和结构...
《PostgreSQL数据库内核分析》彭智勇 完整版44M
本套程序是在VS2005下C#开发,...在对PostgreSQL数据库进行操作时,用到了如何调用存储过程来完成各项操作。 将App_Data下的数据库文件导入到PostgreSQL 8.3版里面,库名为:HYGL 然后修改web.config中的配置即可使用
在 Matlab 中,使用 JDBC 连接 PostgreSQL 数据库需要下载对应的 JDBC 驱动程序,然后将其添加到 Matlab 的环境中。 知识点:PostgreSQL 的 JDBC 驱动程序 PostgreSQL 的 JDBC 驱动程序可以从官方网站下载,例如...
asp连接postgresql数据库 的源码
在Java编程中,连接到PostgreSQL数据库通常需要特定的驱动程序,这个驱动程序通常是以JAR(Java Archive)文件的形式存在。"连接postgresql数据库需要的jar包"指的是用于建立Java应用程序与PostgreSQL数据库之间通信...
使用 Bucardo 搭建 PostgreSQL 数据库双主同步 本文将指导您使用 Bucardo 搭建 PostgreSQL 数据库双主同步,涵盖 Bucardo 的介绍、搭建前准备、安装 Perl 和 PostgreSQL、安装依赖包等方面的知识点。 一、Bucardo ...
1.nacos服务,适配postgresql数据库。 2.提供nacos,postgresql的创建nacos数据库脚本。 3.nacos/conf/nacos-pg.sql数据库脚本文件。 4.nacos版本1.4.2。
将这个JAR文件添加到项目的类路径中,以便在Java程序中使用。 以下是一个简单的JDBC连接到PostgreSQL数据库并获取数据的步骤: 1. **导入所需的JDBC包**: 在Java源代码文件顶部,需要导入JDBC相关的类: ```...
在数据库设计中,递归查询是一种处理层级关系数据的关键技术,尤其在存在多级关联的数据结构时显得尤为重要。本文将深入探讨如何通过递归查询来解决这类问题,并着重讲解使用`WITH`语句来实现递归查询的方法,适用...
在Linux环境中,对PostgreSQL数据库进行定时备份是确保数据安全的重要步骤。PostgreSQL是一个功能强大的开源关系型数据库系统,广泛应用于各种规模的企业和项目。定时备份可以帮助我们在系统故障、误操作或其他不可...