PostgreSQL·国家地区表的设计

本文节选自《Netkiller Architect 手札》

4.22. PostgreSQL 所特有数据库设计

4.22.1. 国家地区表的设计

 +-----------+
 | city      |
 |-----------|
 |id         | <---+
 |name       |     |
 |description|    1:n
 |status     |     |
 |parent_id  | o---+
 +-----------+			

例 4.2. 递归查询实例 city 表

定义结构

	    	CREATE TABLE city
(
  id serial NOT NULL,
  name character varying,
  parent_id integer,
  status boolean,
  CONSTRAINT city_pkey PRIMARY KEY (id),
  CONSTRAINT city_parent_id_fkey FOREIGN KEY (parent_id)
      REFERENCES city (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);
ALTER TABLE city
  OWNER TO sys;	    	

插入数据

	    	INSERT INTO city (id, name, parent_id, status) VALUES (1, '广东', NULL, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (2, '湖南', NULL, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (3, '深圳', 1, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (4, '东莞', 1, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (5, '福田', 3, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (6, '南山', 3, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (7, '宝安', 3, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (8, '西乡', 7, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (9, '福永', 7, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (10, '龙华', 7, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (11, '长沙', 2, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (12, '湘潭', 2, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (13, '常德', 2, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (14, '桃源', 13, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (15, '汉寿', 13, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (16, '黑龙江', NULL, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (17, '伊春', 16, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (18, '哈尔滨', 16, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (19, '齐齐哈尔', 16, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (20, '牡丹江', 16, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (21, '佳木斯', 16, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (22, '民治', 10, NULL);
INSERT INTO city (id, name, parent_id, status) VALUES (23, '上塘', 10, NULL);	    	

查询

	    	WITH RECURSIVE path(id, name, path, idpath, parent_id, status) AS (
  SELECT id, name, '/' || name , '/' || id , parent_id, status FROM city WHERE parent_id is null
  UNION
  SELECT
    city.id,
    city.name,
    parentpath.path ||
      CASE parentpath.path
	WHEN '/' THEN ''
	ELSE '/'
      END || city.name,
    parentpath.idpath ||
     CASE parentpath.idpath
	WHEN '/' THEN ''
	ELSE '/'
      END || city.id,
    city.parent_id, city.status
  FROM city, path as parentpath
  WHERE city.parent_id = parentpath.id
)

SELECT * FROM path;	    	

结果输出

 id |   name   |           path            |    idpath    | parent_id | status
----+----------+---------------------------+--------------+-----------+--------
  1 | 广东     | /广东                     | /1           |           |
  2 | 湖南     | /湖南                     | /2           |           |
 16 | 黑龙江   | /黑龙江                   | /16          |           |
  3 | 深圳     | /广东/深圳                | /1/3         |         1 |
  4 | 东莞     | /广东/东莞                | /1/4         |         1 |
 11 | 长沙     | /湖南/长沙                | /2/11        |         2 |
 12 | 湘潭     | /湖南/湘潭                | /2/12        |         2 |
 13 | 常德     | /湖南/常德                | /2/13        |         2 |
 17 | 伊春     | /黑龙江/伊春              | /16/17       |        16 |
 18 | 哈尔滨   | /黑龙江/哈尔滨            | /16/18       |        16 |
 19 | 齐齐哈尔 | /黑龙江/齐齐哈尔          | /16/19       |        16 |
 20 | 牡丹江   | /黑龙江/牡丹江            | /16/20       |        16 |
 21 | 佳木斯   | /黑龙江/佳木斯            | /16/21       |        16 |
  5 | 福田     | /广东/深圳/福田           | /1/3/5       |         3 |
  6 | 南山     | /广东/深圳/南山           | /1/3/6       |         3 |
  7 | 宝安     | /广东/深圳/宝安           | /1/3/7       |         3 |
 14 | 桃源     | /湖南/常德/桃源           | /2/13/14     |        13 |
 15 | 汉寿     | /湖南/常德/汉寿           | /2/13/15     |        13 |
  8 | 西乡     | /广东/深圳/宝安/西乡      | /1/3/7/8     |         7 |
  9 | 福永     | /广东/深圳/宝安/福永      | /1/3/7/9     |         7 |
 10 | 龙华     | /广东/深圳/宝安/龙华      | /1/3/7/10    |         7 |
 22 | 民治     | /广东/深圳/宝安/龙华/民治 | /1/3/7/10/22 |        10 |
 23 | 上塘     | /广东/深圳/宝安/龙华/上塘 | /1/3/7/10/23 |        10 |
(23 rows)	    	

原文发布于微信公众号 - Netkiller(netkiller-ebook)

原文发表时间:2016-10-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏乐沙弥的世界

Oracle大表清理truncate .. reuse storage

a、通过上述测试,当使用reuse storage与普通方式并无明显差异 b、truncate table 是ddl操作,无法回滚 c、尽管无明显性能差...

764
来自专栏杨建荣的学习笔记

oracle坏块修复实例

最近几天发现库里有坏块了,环境是11gR2, linux平台的64位的库。以下是我的修复办法,基于dbms_repair做的在线修复,也可以基于备份rman来修...

3209
来自专栏杨建荣的学习笔记

巧用shell脚本分析数据库用户(r2第4天)

在数据库维护中,可能对于一个陌生的schema,需要了解它的一些情况,可以使用如下的脚本来很快得到一个报告,里面包含了详尽的信息。 用户占用的空间,权限,角色和...

3217
来自专栏文渊之博

利用PowerShell复制SQLServer账户的所有权限

问题   对于DBA或者其他运维人员来说授权一个账户的相同权限给另一个账户是一个很普通的任务。但是随着服务器、数据库、应用、使用人员地增加就变得很枯燥乏味又耗时...

2478
来自专栏JackieZheng

可视化工具gephi源码探秘(一)

  今天在老大和小梁的鼓舞和忽悠下(^_^),我决定还是把之前下载好的gephi源码好好利用起来,不在朝三暮四的想d3js或是什么vizster,用心去选择一个...

1895
来自专栏乐沙弥的世界

Linux script 命令记录(数据库)操作步骤

    对DBA而言,经常碰到升级数据库或是apply patch,以及有些时候需要运行大量的脚本。对于这些操作我们希望现在在屏幕同时又输出的文件以备后续查询过...

1024
来自专栏程序员宝库

电商系统设计之订单

用户交易将经历一段艰辛的历程,一般用户感觉不到,实际程序是经历了一段生死离别。具体付款流程如下:

1062
来自专栏杨建荣的学习笔记

关于exp/imp的总结学习(r4笔记第26天)

关于exp/imp,是很常用的数据导出导入工具,在10g开始推出的数据泵datapump相当于是exp/imp的补充和升级版本。在后续章节再做一个总结。 exp...

2907
来自专栏乐沙弥的世界

导入导出 Oracle 分区表数据

导入导入Oracle 分区表数据是Oracle DBA 经常完成的任务之一。分区表的导入导出同样普通表的导入导出方式,只不过导入导出需要考

895
来自专栏Grace development

电商系统设计之订单

用户交易将经历一段艰辛的历程,一般用户感觉不到,实际程序是经历了一段生死离别。具体付款流程如下

602

扫码关注云+社区