在 PostgreSQL 中使用 executemany() 在另一个表中插入外键

Posted

技术标签:

【中文标题】在 PostgreSQL 中使用 executemany() 在另一个表中插入外键【英文标题】:INSERT FOREIGN KEY in another table with executemany() in PostgreSQL 【发布时间】:2016-03-27 10:18:40 【问题描述】:

我尝试将语句表中代码列的行值作为公司表中的外键插入。我采取了以下步骤:

创建表格

cur.execute("CREATE TABLE IF NOT EXISTS companies (code INT NOT NULL PRIMARY KEY, short_name VARCHAR(255) NOT NULL, long_name VARCHAR(255) NOT NULL)")

cur.execute("CREATE TABLE IF NOT EXISTS statements (statement_id SERIAL NOT NULL PRIMARY KEY, statement_name VARCHAR(255) NOT NULL, code INT NOT NULL, FOREIGN KEY (code) REFERENCES companies_list (code))")

公司表中包含的代码列(即)

 code |
-----------
  113
  221
  344

下一步是将想要的数据插入到语句表中,如下所示:

statement_name = ["balance_sheet", "income_statement", "cash_flow"]

code = "SELECT code FROM companies_list WHERE code IS NOT NULL"

statements = [tuple((t,)) for t in zip(statement_name, code)]

query = "INSERT INTO statements (statement_name, code) VALUES %s"
cur.executemany(query, statements)

我收到以下错误:

psycopg2.DataError: invalid input syntax for integer: "S"
LINE 1: ...ents (statement_name, code) VALUES ('balance_sheet', 'S')

我想要得到的最终结果如下:

statement_id |   statement_name    |   code
---------------------------------------------
     1           balance_sheet         113
     2           income_statement      113
     3           cash_flow             113
     4           balance_sheet         221
     5          income_statement       221
     6           cash_flow             221

【问题讨论】:

【参考方案1】:

错误来自这一行:

code = "SELECT code FROM companies_list WHERE code IS NOT NULL"

这不会执行实际查询,它会将 SQL 选择语句字符串分配给 code 变量。下一行然后使用code 压缩语句名称,因为code 是一个字符串(可迭代),导致code 的前3 个字符与来自statement_name 的项目一起压缩,结果是:

[(('balance_sheet', 'S'),), (('income_statement', 'E'),), (('cash_flow', 'L'),)]

这就是'S' 的来源——它是code 字符串中“SELECT”的第一个字符。 'S' 是一个字符串,而不是statements 表的架构中定义的整数,因此会出现错误。

你可以看到cursor.mogrify()生成的查询:

>>> statement_name = ["balance_sheet", "income_statement", "cash_flow"]
>>> code = "SELECT code FROM companies_list WHERE code IS NOT NULL"
>>> statements = [tuple((t,)) for t in zip(statement_name, code)]
>>> query = "INSERT INTO statements (statement_name, code) VALUES %s"
>>> for args in statements:
...     print(cur.mogrify(query, args))
... 
INSERT INTO statements (statement_name, code) VALUES ('balance_sheet', 'S')
INSERT INTO statements (statement_name, code) VALUES ('income_statement', 'E')
INSERT INTO statements (statement_name, code) VALUES ('cash_flow', 'L')

解决此问题的一种方法是执行code 中包含的查询以获取公司代码列表,然后使用它来构造INSERT 查询:

import itertools

cur.execute("SELECT code FROM companies_list WHERE code IS NOT NULL")
codes = [row[0] for row in cur.fetchall()]
query = 'INSERT INTO statements (statement_name, code) VALUES (%s, %s)'
args = itertools.product(statement_name, codes)
cur.executemany(query, args)

这里itertools.product() 用于形成语句名称和公司代码的笛卡尔积。这是在模仿数据库连接功能,因此如果您的数据库中有可用的语句类型,那么使用 SQL 而非 Python 可能会更好。

【讨论】:

我的错,我是一般数据库的新手,我认为我在 executemany 中成功使用了查询,然后才能在查询中使用代码.. 所以现在如果这不起作用我该如何解决这个问题问题..最后一个表(语句)中所需的结果.. @T.M:您需要执行查询,否则获取公司代码列表。查看更新的答案。 我尝试了您的代码,但遇到了错误('NoneType' 对象没有属性 'fetchall').. 然后将其更改为 'symbols = cur.execute("SELECT symbols FROM Companies_list WHERE symbols IS NOT NULL") symbols = cur.fetchall()' 并面临另一个错误 (cur.executemany(query, args) TypeError: not all arguments convert during string formatting ) 对于psycopg2cursor.execute() 返回None,因此出现错误。我已经更新了代码来处理这个问题。

以上是关于在 PostgreSQL 中使用 executemany() 在另一个表中插入外键的主要内容,如果未能解决你的问题,请参考以下文章

在PostgreSQL中使用ltree处理层次结构数据

在 MAMP 中使用 Laravel 设置 PostgreSQL

在 PostgreSQL 和 Slick 中使用自动递增字段

在 EF6 中使用时态表 - PostgreSQL

PostgreSQL介绍以及如何开发框架中使用PostgreSQL数据库

如何在流式查询中使用外部数据库(postgresql)作为输入?