更新冲突 postgres 上的多个列
Update multiple columns on conflict postgres
我必须编写查询来更新记录(如果存在),否则将其插入。我正在将此 update/insert 放入 postgres 数据库中。我查看了 upsert 示例,其中大多数使用最多两个字段进行更新。但是,我想更新多列。示例:
query="""INSERT INTO table (col1,col2,col3,col4,col5,col6,col7,col8,col9,..col20) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
ON CONFLICT(col2) DO UPDATE SET (col1,col2,col3,col4,col5,col6,col7,col8,col9,..col20) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"""
在上面的查询中,假设 col2 是唯一键,我将插入和更新相同数量的列。我必须使用 pymysql(python 库) 执行此查询。在一个简单的插入语句中,我知道如何动态传递包含参数的元组。
cursor.execute(insert_query, data_tuple)
但在这种情况下,我有两个位置(插入和更新)输入都是动态的。考虑到上面的upsert查询,我将参数传递给游标的方式
cursor.execute(upsert_query,data_tuple,data_tuple)
但是,这个函数会抛出一个错误,执行函数中的参数数量过多。那我怎么过?此外,我正在尝试使用这种方式来传递参数,因为使用赋值(=)对于 20 列来说是一件费力的事情。
还有其他替代方法吗?就像 mysql.
中的简单 "replace into" 语句
编辑 2
所以,经过几次交流:你的问题似乎是如何在pymysql中使用cursor.execute函数。
这是相应文档的 link:https://pymysql.readthedocs.io/en/latest/modules/cursors.html
我从不在 python 中编写代码,但文档似乎对执行方法的用法非常准确:
execute(query, args=None)
Execute a query
Parameters:
query (str) – Query to execute.
args (tuple, list or dict) – parameters used with query. (optional)
Returns:
Number of affected rows
Return type:
int
If args is a list or tuple, %s can be used as a placeholder in the query. If args is a dict, %(name)s can be used as a placeholder in the query.
所以也许 'dict' 类型是可能的,但我不认为这是它的哲学。
原版post
我不太确定 'both places input to be dynamic' 你到底想说什么,所以我会在这里写一些 SQL 如果你有任何问题,请不要犹豫:)
首先进行一个小的初始化
CREATE TABLE test
(
id int,
value_1 varchar,
value_2 bit
);
ALTER TABLE test
ADD CONSTRAINT ck_test UNIQUE(id, value_1, value_2);
INSERT INTO test
VALUES
(1, 'test', cast(1 as bit))
, (2, 'test_2', cast(0 as bit));
第二个错误
INSERT INTO test
VALUES
(1, 'test', cast(1 as bit));
第三个UPSERT
INSERT INTO test
VALUES
(1, 'test', cast(1 as bit))
ON CONFLICT ON CONSTRAINT ck_test
DO
UPDATE
SETid = 3, value_1 = 'error';
这是在回答你的问题吗?或者它更像是一个字符串构建问题?
编辑
所以,我不喜欢其他语言,所以我会把它放在 plpgsql 中:
do language plpgsql $$
declare
query varchar;
id_insert int;
value_1_insert varchar;
value_2_insert bit;
id_update int;
value_1_update varchar;
value_2_update bit;
begin
id_insert := 4;
value_1_insert := 'test';
value_2_insert := cast(1 as bit);
id_update := id_insert;
value_1_update := 'error';
value_2_update := cast(0 as bit);
query := 'INSERT INTO test
VALUES
(
cast('||id_insert||' as int)
, '''||value_1_insert||'''
, cast('||value_2_insert||' as bit)
)
ON CONFLICT ON CONSTRAINT ck_test
DO
UPDATE
SET
id = cast('||id_update||' as int)
, value_1 = '''||value_1_update||'''
, value_2 = cast('||value_2_update||' as bit);';
execute query;
end;
$$;
希望对您有所帮助 ;)
您问题的直接答案是,您执行 tuple + tuple
来加倍元组。
cursor.execute(upsert_query, data_tuple + data_tuple)
其他选项:
如果你有单独的值并且你正在构造元组,你可以直接构造一个具有两倍数量的值的元组。
query="""INSERT INTO table (col1,col2,col3,col4,col5,col6,col7,col8,col9,..col20) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
ON CONFLICT(col2) DO UPDATE SET col1=%s, col3=%s, col4=%s, ..."""
cur.execute(query, (c1, c2, c3, ... c20, c1, c3, c4, ... c20))
您必须指定两次值(col2 除外)。
如果您已经有了您最初要求的元组,那么您将使用 +
将同一个元组合并两次。
如果你有单独的值而不是元组,你也可以使用像字典这样的命名参数。
query="""INSERT INTO table (col1,col2,col3,col4...) VALUES(%(c1)s, %(c2)s, %(c3)s, %(c4)s...) ON CONFLICT(col2) DO UPDATE SET col1=%(c1)s, col3=%(c3)s, col4=%(c4)s, ..."""
cur.execute(query, {'c1': c1val, 'c2': c2val, 'c3': c3val, 'c4': c4val, ...})
这种形式可读性好,只传一次参数,以后列数变化时也便于维护(增加列等)。
我必须编写查询来更新记录(如果存在),否则将其插入。我正在将此 update/insert 放入 postgres 数据库中。我查看了 upsert 示例,其中大多数使用最多两个字段进行更新。但是,我想更新多列。示例:
query="""INSERT INTO table (col1,col2,col3,col4,col5,col6,col7,col8,col9,..col20) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
ON CONFLICT(col2) DO UPDATE SET (col1,col2,col3,col4,col5,col6,col7,col8,col9,..col20) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"""
在上面的查询中,假设 col2 是唯一键,我将插入和更新相同数量的列。我必须使用 pymysql(python 库) 执行此查询。在一个简单的插入语句中,我知道如何动态传递包含参数的元组。
cursor.execute(insert_query, data_tuple)
但在这种情况下,我有两个位置(插入和更新)输入都是动态的。考虑到上面的upsert查询,我将参数传递给游标的方式
cursor.execute(upsert_query,data_tuple,data_tuple)
但是,这个函数会抛出一个错误,执行函数中的参数数量过多。那我怎么过?此外,我正在尝试使用这种方式来传递参数,因为使用赋值(=)对于 20 列来说是一件费力的事情。
还有其他替代方法吗?就像 mysql.
中的简单 "replace into" 语句编辑 2
所以,经过几次交流:你的问题似乎是如何在pymysql中使用cursor.execute函数。 这是相应文档的 link:https://pymysql.readthedocs.io/en/latest/modules/cursors.html
我从不在 python 中编写代码,但文档似乎对执行方法的用法非常准确:
execute(query, args=None)
Execute a query
Parameters:
query (str) – Query to execute.
args (tuple, list or dict) – parameters used with query. (optional)
Returns:
Number of affected rows
Return type:
int
If args is a list or tuple, %s can be used as a placeholder in the query. If args is a dict, %(name)s can be used as a placeholder in the query.
所以也许 'dict' 类型是可能的,但我不认为这是它的哲学。
原版post
我不太确定 'both places input to be dynamic' 你到底想说什么,所以我会在这里写一些 SQL 如果你有任何问题,请不要犹豫:)
首先进行一个小的初始化
CREATE TABLE test
(
id int,
value_1 varchar,
value_2 bit
);
ALTER TABLE test
ADD CONSTRAINT ck_test UNIQUE(id, value_1, value_2);
INSERT INTO test
VALUES
(1, 'test', cast(1 as bit))
, (2, 'test_2', cast(0 as bit));
第二个错误
INSERT INTO test
VALUES
(1, 'test', cast(1 as bit));
第三个UPSERT
INSERT INTO test
VALUES
(1, 'test', cast(1 as bit))
ON CONFLICT ON CONSTRAINT ck_test
DO
UPDATE
SETid = 3, value_1 = 'error';
这是在回答你的问题吗?或者它更像是一个字符串构建问题?
编辑 所以,我不喜欢其他语言,所以我会把它放在 plpgsql 中:
do language plpgsql $$
declare
query varchar;
id_insert int;
value_1_insert varchar;
value_2_insert bit;
id_update int;
value_1_update varchar;
value_2_update bit;
begin
id_insert := 4;
value_1_insert := 'test';
value_2_insert := cast(1 as bit);
id_update := id_insert;
value_1_update := 'error';
value_2_update := cast(0 as bit);
query := 'INSERT INTO test
VALUES
(
cast('||id_insert||' as int)
, '''||value_1_insert||'''
, cast('||value_2_insert||' as bit)
)
ON CONFLICT ON CONSTRAINT ck_test
DO
UPDATE
SET
id = cast('||id_update||' as int)
, value_1 = '''||value_1_update||'''
, value_2 = cast('||value_2_update||' as bit);';
execute query;
end;
$$;
希望对您有所帮助 ;)
您问题的直接答案是,您执行 tuple + tuple
来加倍元组。
cursor.execute(upsert_query, data_tuple + data_tuple)
其他选项:
如果你有单独的值并且你正在构造元组,你可以直接构造一个具有两倍数量的值的元组。
query="""INSERT INTO table (col1,col2,col3,col4,col5,col6,col7,col8,col9,..col20) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
ON CONFLICT(col2) DO UPDATE SET col1=%s, col3=%s, col4=%s, ..."""
cur.execute(query, (c1, c2, c3, ... c20, c1, c3, c4, ... c20))
您必须指定两次值(col2 除外)。
如果您已经有了您最初要求的元组,那么您将使用 +
将同一个元组合并两次。
如果你有单独的值而不是元组,你也可以使用像字典这样的命名参数。
query="""INSERT INTO table (col1,col2,col3,col4...) VALUES(%(c1)s, %(c2)s, %(c3)s, %(c4)s...) ON CONFLICT(col2) DO UPDATE SET col1=%(c1)s, col3=%(c3)s, col4=%(c4)s, ..."""
cur.execute(query, {'c1': c1val, 'c2': c2val, 'c3': c3val, 'c4': c4val, ...})
这种形式可读性好,只传一次参数,以后列数变化时也便于维护(增加列等)。