我已经阅读了UPSERTPostgreSQL 中的不同实现,但所有这些解决方案都相对较旧或相对奇特(例如,使用可写 CTE)。
而且我根本不是 psql 专家,无法立即找出这些解决方案是否过时,因为它们被很好地推荐,或者它们(好吧,几乎所有这些都是)只是不适合生产使用的玩具示例。
在 PostgreSQL 中实现 UPSERT 的最线程安全的方法是什么?
此问题与使用 PostgreSQL 9.2 或更高版本忽略重复插入有关。我问的原因是因为这段代码:
-- Ignores duplicates.
INSERT INTO
db_table (tbl_column_1, tbl_column_2)
VALUES (
SELECT
unnseted_column,
param_association
FROM
unnest( param_array_ids ) AS unnested_column
);
Run Code Online (Sandbox Code Playgroud)
代码不受检查现有值的影响。(在这种特殊情况下,用户并不关心插入重复项的错误——插入应该“正常工作”。)在这种情况下添加代码来显式测试重复项会带来复杂性。
在 PostgreSQL 中,我找到了几种忽略重复插入的方法。
创建一个捕获唯一约束违规的事务,不采取任何行动:
BEGIN
INSERT INTO db_table (tbl_column) VALUES (v_tbl_column);
EXCEPTION WHEN unique_violation THEN
-- Ignore duplicate inserts.
END;
Run Code Online (Sandbox Code Playgroud)
创建规则以忽略给定表上的重复项:
CREATE OR REPLACE RULE db_table_ignore_duplicate_inserts AS
ON INSERT TO db_table
WHERE (EXISTS ( SELECT 1
FROM db_table
WHERE db_table.tbl_column = NEW.tbl_column)) DO INSTEAD NOTHING;
Run Code Online (Sandbox Code Playgroud)
我的问题主要是学术性的:
希望为一系列物质计算最合适的计量单位,其中物质以不同(但兼容)的单位体积给出。
单位转换表存储各种单位以及这些单位之间的关系:
id unit coefficient parent_id
36 "microlitre" 0.0000000010000000000000000 37
37 "millilitre" 0.0000010000000000000000000 5
5 "centilitre" 0.0000100000000000000000000 18
18 "decilitre" 0.0001000000000000000000000 34
34 "litre" 0.0010000000000000000000000 19
19 "dekalitre" 0.0100000000000000000000000 29
29 "hectolitre" 0.1000000000000000000000000 33
33 "kilolitre" 1.0000000000000000000000000 35
35 "megalitre" 1000.0000000000000000000000 0
Run Code Online (Sandbox Code Playgroud)
按系数排序表明将parent_id子单元与其上级数值联系起来。
可以使用以下命令在 PostgreSQL 中创建此表:
CREATE TABLE unit_conversion (
id serial NOT NULL, -- Primary key.
unit text NOT NULL, -- Unit of measurement name.
coefficient numeric(30,25) NOT NULL DEFAULT 0, -- Conversion value.
parent_id integer …Run Code Online (Sandbox Code Playgroud) 使用 PostgreSQL 9.1,所以WITH ORDINAL(9.4 特性)不可用。
希望简化旋转二维数组的代码。
一个说明问题的工作,过于冗长的例子是:
SELECT
u.aspect,
u.preference
FROM (
SELECT
t.aspect_preference AS aspect,
-- Skip every second row
seq % 2 AS seq,
lead( aspect_preference, 1 ) OVER (ORDER BY t.seq) AS preference
FROM (
SELECT
unnest( '{ {"COLOUR_SCHEME", "RASPBERRY_BLISS"}, {"FONT", "TERMES_HEROS"}, {"LIST_LAYOUT", "BULLET_SNOWFLAKE"} }'::text[] ) aspect_preference,
-- Maintain array order after unnesting to a result set
generate_series( 1,
(array_ndims( '{ {"COLOUR_SCHEME", "RASPBERRY_BLISS"}, {"FONT", "TERMES_HEROS"}, {"LIST_LAYOUT", "BULLET_SNOWFLAKE"} }'::text[] ) *
array_length( '{ …Run Code Online (Sandbox Code Playgroud) 在PostgreSQL文档状态:
任何有副作用的函数都必须标记为 VOLATILE...
考虑以下函数:
CREATE OR REPLACE FUNCTION count_items()
RETURNS integer AS
$BODY$
DECLARE
v_result INTEGER DEFAULT 0;
BEGIN
SELECT
count( t.id )
INTO
v_result
FROM
some_table t;
RETURN v_result;
EXCEPTION
WHEN OTHERS THEN
PERFORM error_log_insert( SQLSTATE, SQLERRM, current_query() );
RETURN 0;
END;
$BODY$
LANGUAGE plpgsql STABLE
COST 10;
Run Code Online (Sandbox Code Playgroud)
由于error_log_insert更改数据库(对异常执行插入),这是否意味着该count_items函数具有副作用(尽管是间接的),因此不能声明STABLE,但必须声明VOLATILE?
换句话说,函数的稳定性或波动性是否也取决于它在其异常块中调用的函数?
如果是这种情况,那么您将如何STABLE在 PostgreSQL 中创建将所有异常记录到数据库表中的函数?
使用 Oracle,有许多工具可以帮助将开发更改迁移和应用到生产环境中(例如Embarcadero Change Manager)。这些工具可以配置为在几乎不需要人工干预的情况下执行任何数据库 DDL 升级。
我有运行 PostgreSQL 9.x 的开发和生产服务器。在将数据库 DDL 初始部署到生产服务器后,我将继续对开发数据库进行更改。这些更改将包括对存储过程的错误修复、对表的更改、附加序列、新视图、更多类型、更多表等。
以自动方式(或几乎自动)升级/迁移生产 PostgreSQL 数据库应用程序的 DDL 以使其在开发中进行新更改的步骤是什么?
谢谢!
postgresql ×6
plpgsql ×2
array ×1
constraint ×1
ddl ×1
duplication ×1
exception ×1
insert ×1
logs ×1
pivot ×1
upgrade ×1
upsert ×1