創建擴展
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;