创建扩展
root用户,使用"su postgres"切换到postgres
postgres=# create extension xx;
例如创建一个新的fdw(foreign-data-wrapper):
postgres=#create extension postgres_fdw;
查看安装的扩展
postgres=# select * from pg_extension;
或者
postgres=# \dx
postgres_fdw实例
:> psql product
product=# create extension postgres_fdw;
1,创建外部服务器对象
product=# create server inventory_foreign_server foreign data wrapper postgres_fdw options(host '192.168.223.14', dbname 'b2b_inventory',port '5432');
2,创建用户映射
product=# create user mapping for tomtop server inventory_foreign_server options(user 'tomtop', password 'tomtop');
3,建立外部表
product=# create foreign table cloud_inventory(id bigint, sku varchar(255), stock integer, warehouse_id integer, warehouse_name varchar(255), residue_num integer) server inventory_foreign_server options(table_name 't_product_inventory_total');
product=# create foreign table cloud_inventory_lock(sku varchar(255), stock_locked integer, warehouse_id integer, warehouse_name varchar(255), is_effective smallint) server inventory_foreign_server options(table_name 't_product_inventory_order_lock');
product=# create foreign table micro_inventory(sku varchar(255), warehouse_id integer, warehouse_name varchar(255), stock integer, account varchar(255)) server inventory_foreign_server options(table_name 't_product_micro_inventory_total');
product=# create foreign table micro_inventory_lock(sku varchar(255), stock_locked integer, warehouse_id integer, warehouse_name varchar(255), is_effective smallint, account varchar(255)) server inventory_foreign_server options(table_name 't_product_micro_inventory_order_lock');
建立后的表和本地表看起来是一样的;
使用tomtop用户:select * from cloud_inventory;
递归查询实例
数据表中,商品类目(t_category_base)是按父子级存的,类目的名称在t_category_name,现在需要拿到每个类目的树,比如"母婴产品=>奶粉=>爱他美",在展示第三级类目"爱他美"的时候,对应的类目树应该是"(母婴用品)(奶粉)(爱他美)",如下图
建表语句
CREATE TABLE "public"."t_category_base" (
"iid" SERIAL NOT NULL,
"iparentid" int4,
"cpath" varchar(255) COLLATE "default",
"ilevel" int4,
"iposition" int4,
"ichildrencount" int4
);
CREATE TABLE "public"."t_category_name" (
"iid" SERIAL NOT NULL,
"icategoryid" int4,
"ilanguageid" int4,
"cname" varchar(300) COLLATE "default",
"ctitle" varchar(300) COLLATE "default",
"cdescription" varchar(2000) COLLATE "default",
"ckeywords" varchar(2000) COLLATE "default",
"cmetatitle" varchar(500) COLLATE "default",
"cmetakeyword" varchar(2000) COLLATE "default",
"cmetadescription" varchar(2000) COLLATE "default",
"ccontent" varchar(8000) COLLATE "default",
"cnickname" varchar(32) COLLATE "default"
);
需要用到的是递归的关键字WITH RECURSIVE,下面是真实代码:
WITH RECURSIVE T
(id,
parentid,
categoryIdTree,
categoryNameTree,
level
)
AS (
SELECT
t_category_base.iid,
iparentid,
ARRAY[t_category_base.iid] AS categoryIdTree,
'(' || cname || ')' AS categoryNameTree,
1 AS level
FROM t_category_base, t_category_name
WHERE
iparentid = -1
AND t_category_base.iid = t_category_name.icategoryid
AND t_category_name.ilanguageid = 1
UNION ALL
SELECT
cb.iid,
cb.iparentid,
T.categoryIdTree ||cb.iid,
T.categoryNameTree || '(' || cb.cname || ')',
T.level + 1 AS level
FROM (
SELECT cb.iid, cb.iparentid, cn.cname
FROM t_category_base cb, t_category_name cn
WHERE cb.iid = cn.icategoryid
AND cn.ilanguageid = 1
) cb
JOIN T ON cb.iparentid = T.id
) select * from T;
pgsql的递归查询效率很高。
更复杂的递归实例
有一个更麻烦的业务场景,要展示商品和类目树的关系;
麻烦的是,商品和类目映射表中存数据的时候,sku会存所有级别的映射,而且某个商品可能属于两个三级类目,那这个sku在这个映射表中就会存在3+3行数据,如下图
上面递归查询结果T是平铺了所有的类目的父子级关系,所以映射表需要先过滤自己,只取关联的最后一级类目的id,这时候需要关联T来做操作.
t_product_category_mapper的建标语句:
WITH RECURSIVE T
(id,
parentid,
categoryIdTree,
categoryNameTree,
level
)
AS (
SELECT
t_category_base.iid,
iparentid,
ARRAY[t_category_base.iid] AS categoryIdTree,
'(' || cname || ')' AS categoryNameTree,
1 AS level
FROM t_category_base, t_category_name
WHERE
iparentid = -1
AND t_category_base.iid = t_category_name.icategoryid
AND t_category_name.ilanguageid = 1
UNION ALL
SELECT
cb.iid,
cb.iparentid,
T.categoryIdTree ||cb.iid,
T.categoryNameTree || '(' || cb.cname || ')',
T.level + 1 AS level
FROM (
SELECT cb.iid, cb.iparentid, cn.cname
FROM t_category_base cb, t_category_name cn
WHERE cb.iid = cn.icategoryid
AND cn.ilanguageid = 1
) cb
JOIN T ON cb.iparentid = T.id
) SELECT
pcm.csku,
T.categoryIdTree categoryIdTree,
T.categoryNameTree categoryNameTree
FROM T,
t_product_category_mapper pcm
WHERE
T.ID NOT IN (select iparentid from t_category_base)
AND pcm.icategory = T.ID
使用db_link
首选在对应的库要创建'db_link'扩展,create extension db_link,创建的方法在顶部第一部分
注意,根据 官方文档,db_link在使用之前,需要用SELECT dblink_connect语句建立连接,使用完要用SELECT dblink_disconnect关闭连接;
select dblink_connect('product_dblink','dbname=product host=127.0.0.1 port=5432 user=tomtop password=tomtop');
实例:
INSERT INTO t_product_base_mapper (
iid,
istatus,
distributorid,
preferdate,
orderby,
retailprice,
iwebsiteid,
ctitle,
csku,
masterimgurl,
warehouseno,
warehousename,
totalsales
) select
nextval('t_product_base_mapper_iid_seq'),
1,
1,
now(),
1,
T.price,
1,
T.title,
T.sku,
T.masterimgurl,
T.warehouseno,
T.warehousename,
0
from (
SELECT
*
FROM dblink('product_dblink',
'SELECT
DISTINCT pb.csku,
pb.fprice,
pt.ctitle,
gi.warehouse_id,
gi.warehouse_name,
pi.cimageurl
FROM
t_product_base pb
LEFT JOIN t_product_translate pt ON pb.csku = pt.csku
LEFT JOIN t_goods_inventory gi ON pb.csku = gi.sku
LEFT JOIN t_product_image pi ON pb.csku = pi.csku
AND pi.bbaseimage=true
AND pi.bsmallimage=true
AND iorder=(select MAX(iorder) from t_product_image where csku=pb.csku and bbaseimage=true)'
) AS t (
sku VARCHAR(20),
price float8,
title VARCHAR(200),
warehouseno VARCHAR(20),
warehousename VARCHAR(20),
masterimgurl VARCHAR(200))
where t.sku not in (select csku from t_product_base_mapper where iwebsiteid=1)
) T where T.warehouseno is not null;