postgresql 发生冲突时,请更新/不执行任何不适用于国外表格的操作

ipakzgxi  于 2023-02-18  发布在  PostgreSQL
关注(0)|答案(2)|浏览(191)

发生冲突时执行更新/不执行任何操作功能将在PostgreSQL9.5中提供。创建服务器外部表将在PostgreSQL9.2版本中提供。

当我对FOREIGN表使用ON CONFLICT DO UPDATE时,它不起作用,但当我对普通表运行相同的查询时,它起作用。查询如下所示。
//对于普通表

INSERT INTO app
 (app_id,app_name,app_date)
 SELECT
p.app_id,
p.app_name,
p.app_date  FROM app p
WHERE p.app_id=2422
ON CONFLICT (app_id) DO 
UPDATE SET app_date = excluded.app_date ;

O/P:查询返回成功:影响一行,执行时间为5毫秒。
//对于外表概念
// foreign_app 是外表,app 是普通表

INSERT INTO foreign_app
 (app_id,app_name,app_date)
 SELECT
p.app_id,
p.app_name,
p.app_date  FROM app p
WHERE p.app_id=2422
ON CONFLICT (app_id) DO 
UPDATE SET app_date = excluded.app_date ;

O/P:错误:没有与ON CONFLICT规范匹配的唯一约束或排除约束

有人能解释为什么会发生这种情况吗?

shyt4zoc

shyt4zoc1#

对外部表没有约束,因为PostgreSQL不能强制外部服务器上的数据完整性-这是由外部服务器上定义的约束来完成的。
为了达到你想要的目的,你必须坚持使用“传统”的方法(例如这个代码样本)。

iyzzxitl

iyzzxitl2#

我知道这是一个老问题,但在某些情况下,有一种方法可以使用ROW_NUMBER OVER(PARTION)来完成它。在我的例子中,我的第一个尝试是ON CONFLICT... DO UPDATE,但这不适用于外部表(如上所述;我的问题非常具体,因为我有一个外来表(f_zips),需要用尽可能好的邮政编码信息填充。我还有一个本地表 postcodes,其中包含非常好的数据,还有另一个本地表 zips,其中包含质量较低但更多的邮政编码信息。对于 postcodes 中的每一条记录,在 zips 中有对应的记录,但是邮政编码可能不匹配。2我希望 f_zips 保存最佳数据。
我用一个并集来解决这个问题,用 ind = 0 作为记录来自较好数据集的指示符,ind = 1 表示数据质量较差,然后我在一个分区上使用 row_number() 来得到答案(其中 get_valid_zip5() 是一个本地函数,返回5位数的邮政编码或空值):

insert into f_zips (recnum, postcode)
select s2.recnum, s2.zip5 from (
    select s1.recnum, s1.zip5, s1.ind, row_number() 
            over (partition by recnum order by s1.ind) as rn from (
        select recnum, get_valid_zip5(postcode) as zip5, 0 as ind
            from postcodes
            where get_valid_zip5(postcode) is not null
        union
        select recnum, get_valid_zip5(zip9) as zip5, 1 as ind
            from zips
            where get_valid_zip5(zip9) is not null
        order by 1, 3) s1 
) s2 where s2.rn = 1
;

我没有运行任何性能测试,但对我来说,这是在cron中运行的,不会直接影响用户。
验证超过900,000条记录(为简洁起见,省略SQL格式):

/* yes, the preferred data was entered when it existed in both tables */

select t1.recnum, t1.postcode, t2.zip9 from postcodes t1 join zips t2 on t1.recnum = t2.recnum where t1.postcode is not null and t2.zip9 is not null and t2.zip9 not in ('0') and length(t1.postcode)=5 and length(t2.zip9)=5 and t1.postcode <> t2.zip9 order by 1 limit 5;
  recnum  | postcode | zip9  
----------+----------+-------
 12022783 | 98409    | 98984
 12022965 | 98226    | 98225
 12023113 | 98023    | 98003

select * from f_zips where recnum in (12022783, 12022965, 12023113) order by 1;
  recnum  | postcode 
----------+----------
 12022783 |    98409
 12022965 |    98226
 12023113 |    98023

/* yes, entries came from the less-preferred dataset when they didn't exist in the better one */

select t1.recnum, t1.postcode, t2.zip9 from postcodes t1 right join zips  t2 on t1.recnum = t2.recnum where t1.postcode is null and t2.zip9 is not null and t2.zip9 not in ('0') and length(t2.zip9)= 5 order by 1 limit 3;
  recnum  | postcode | zip9  
----------+----------+-------
 12021451 |          | 98370
 12022341 |          | 98501
 12022695 |          | 98597

select * from f_zips where recnum in (12021451, 12022341, 12022695) order by 1;
  recnum  | postcode 
----------+----------
 12021451 |    98370
 12022341 |    98501
 12022695 |    98597

/* yes, entries came from the preferred dataset when the less-preferred one had invalid values */

select t1.recnum, t1.postcode, t2.zip9 from postcodes t1 left join zips t2 on t1.recnum = t2.recnum where t1.postcode is not null and t2.zip9 is null order by 1 limit 3;
  recnum  | postcode | zip9
----------+----------+------
 12393585 | 98118    |
 12393757 | 98101    |
 12393835 | 98101    |

select * from f_zips where recnum in (12393585, 12393757, 12393835) order by 1;
  recnum  | postcode 
----------+----------
 12393585 |    98118
 12393757 |    98101
 12393835 |    98101

相关问题