更新冲突邮政的多列



我必须编写一个查询以更新记录,如果它存在其他插入记录。我正在进行此更新/插入Postgres DB。我已经研究了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中的简单"替换为"语句。

您问题的直接答案是,您要进行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中使用光标。这是适当文档的链接: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));

第三

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;
$$;

希望这会有所帮助;(

最新更新