我必须写一个查询来更新记录,如果它存在,否则插入它。我正在进行更新/插入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)
但是,这个引发了一个错误,其中参数的数量在execute函数中。那我怎么通过?此外,我试图使用这种方式传递参数,因为使用赋值(=)对于20列来说是一件费力的事情。
有没有其他替代方法来做到这一点?就像在mysql中简单的“替换成”语句一样。
你的问题的直接答案是,你做一个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, ...})
此表单有利于可读性,仅传递参数一次,并且如果列数在将来发生变化,则易于维护(增加列等)。
编辑2
所以,经过几次交流:你的问题似乎是如何在pymysql中使用cursor.execute函数。这是相应文档的链接: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'类型是可能的,但我不认为这是它的哲学。
原帖
我不太确定你想说的“两个地方输入都是动态的”,所以我会在这里放下一些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;
$$;
希望这可以帮助 ;)