【问题标题】:Psycopg execute_values without id没有 id 的 Psycopg execute_values
【发布时间】:2021-02-20 12:49:37
【问题描述】:

我尝试将行/元组列表插入到我的 postgresql 数据库中。所以我找到了函数execute_values() ...但是行自动获取id是行不通的。

我的代码:

query = "INSERT INTO "+ self.table + " VALUES %s"
execute_values(self.cursor,query, row)
self.con.commit()

我的数据库中的第一列是id,我的行元组的第一列是TEXT(数据库中的第二列也是TEXT)

所以我得到了错误:

psycopg2.errors.InvalidTextRepresentation: invalid input syntax for type integer: "blub"
LINE 1: INSERT INTO whales VALUES ('blub...

所以我猜是因为 id。

我也试过template,但结果也好不到哪里去:

database.py", line 204, in insert_row
execute_values(self.cursor,query, row, "(%(name)s,%(is_member)s)")
File "C:\Just\a\Path\env\lib\site-packages\psycopg2\extras.py", line 1289, in execute_values
parts.append(cur.mogrify(template, args))
TypeError: tuple indices must be integers or slices, not str

也许我读错了文档或者不理解模板...

现在的问题是: 我该如何处理?对于“正常”执行,我不需要添加 id。有没有办法用 execute_values() 做到这一点? 还是唯一的方法是先通过 select 获取 id 并将未使用的 id 也提供给 execute_values?

【问题讨论】:

  • 您应该指定数据所属的列:INSERT INTO foo (text_col_1, text_col_2) VALUES ...,假设 id 列自动递增。

标签: python postgresql psycopg2 execute


【解决方案1】:

在 Postgresql 中,对于有效的 SQL,INSERT 语句中的值列表必须与列表相对应 指定的列名。如果未指定列名列表,则指定 N 值列表 必须对应于表中的 first N 列,并带有指定 DEFAULT 的选项以插入 这些列的默认值。对于 Postgresql SERIAL 列,例如在 以下示例表:

    CREATE TABLE test_insert_with_serial_column (
        id SERIAL PRIMARY KEY,
        col1 VARCHAR,
        col2 VARCHAR
    );

以下 SQL 语句有效:

    -- Specifying only the col1 and col2 columns, SERIAL id column will "auto-increment"
    INSERT INTO test_insert_with_serial_column(col1, col2) VALUES ('one_text', 'other_text');

    
    -- Specifying values for all columns with DEFAULT for the SERIAL id column
    INSERT INTO test_insert_with_serial_column VALUES (DEFAULT, 'one_text', 'other_text');

但是,以下 SQL 无效:

    -- Failed to specify an integer value for the first SERIAL id column
    INSERT INTO test_insert_with_serial_column VALUES ('one_text', 'other_text');

这是因为one_text 将与SERIAL id 列相关联,因此, 类似于 OP 结果看到的错误消息。

psycopg2.extras.execute_values是一个辅助函数,可以用来插入多行 值列表(即值列表)更有效。输入 SQL 查询必须包含 单个 %s 占位符,它将被占位符的 template 替换。默认 template(即,如果指定了None)是占位符的简单位置序列 (即(%s, %s, ...)),占位符的数量等于要插入的值的数量 对于每一行。因此,调用execute_values:

execute_values(cur, "INSERT INTO test_insert_with_serial_column VALUES %s",
               [('one_text', 'other_text')])

产生与上述相同的无效 SQL。注意上面使用execute_values只插入 一行而不是多行与错误无关紧要。

这个问题有多种解决方案:

  1. 指定与输入查询中的值对应的列名
execute_values(cur, "INSERT INTO test_insert_with_serial_column (col1, col2) VALUES %s",
               [('one_text', 'other_text')])
  1. 提供一个template,为id 列指定一个DEFAULT
execute_values(cur, "INSERT INTO test_insert_with_serial_column VALUES %s",
               [('one_text', 'other_text')], template="(DEFAULT, %s, %s)")
  1. 将SERIAL 列声明为表中的最后一列
    CREATE TABLE test_insert_with_serial_column (
        col1 VARCHAR,
        col2 VARCHAR,
        id SERIAL PRIMARY KEY
    );

然后,调用:

execute_values(cur, "INSERT INTO test_insert_with_serial_column VALUES %s",
               [('one_text', 'other_text')])

有效。最后一个解决方案有点不合常规,但它利用了 if no list 列,则指定的N 值列表必须对应于 first N 表中的列。

【讨论】:

  • 让我无法使用前两个解决方案的问题是列可以是可变数量。我准备好的插入语句旨在用于具有不同列数的多个表。我认为避免该问题的唯一方法是使用您的第三种解决方案。
猜你喜欢
  • 2019-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-16
  • 2021-03-03
  • 2010-12-19
  • 2012-10-21
  • 1970-01-01
相关资源
最近更新 更多