【问题标题】:is is possible to run two sql inserts back to back in a loop?是否可以在一个循环中背靠背运行两个 sql 插入?
【发布时间】:2021-06-30 06:38:38
【问题描述】:

假设你有一个类似于的数据循环

for tree in trees:
    tree_type = [t_type]
    tree_owner = [t_owner]

所以循环的一个结果看起来像

magnolia
Bill

您的两个表如下所示,_id 列是自动递增的 PKs

tree_header

tree_header_id tree_type
25 spruce

tree_detail

tree_detail_id tree_id tree_owner
2 25 Susan
3 25 Roger

是否可以使用循环来串联运行两个插入,以将每个结果插入到两个表中

Insert into tree_header(tree_type) values(tree_type)

last_id = last id inserted into header

Insert into tree_detail(tree_id, tree_owner) values(last_id, tree_owner)

【问题讨论】:

标签: python postgresql sql-insert


【解决方案1】:

你实际上可以做到这一点是一个单一的声明。该技术是创建一个 CTE 来接收参数。在这种情况下,树类型和所有者数组。然后第二个 CTE 插入 tree_header 并返回生成的 id。最后,将参数与生成的标头连接起来。见Demo

with parms (tree, owners) as
     ( values ('<tree type>', array ['<Owner_Array>']) )
   , make_tree as
     ( insert into tree_header(tree_type)
         select tree from parms
         returning tree_id, tree_type
     )
insert into  tree_detail(owner_name, tree_id)
   select unnest (p.Owner_Array), mt.tree_id
     from parms p 
     join make_tree mt on (mt.tree_type = p.tree);

现在,由于我不编写您的晦涩语言(Python?),因此我的翻译方式并不完全正确。但我猜是这样的:

import psycopg2

class MyData():
    def __init__(self, host="10.0.80.85", db="hhh", user="postgres", password="5bebfakee11"):
        self.conn = psycopg2.connect(host=host, database=db, user=user, password=password)
        self.cur = self.conn.cursor() 
            
    def close(self):
        self.cur.close()
        self.conn.close()


 db = MyData()
 statement = "with parms (tree, owners) as                   \
                  ( values ('%',  array [%]) )               \
                , make_tree as                               \
                  ( insert into tree_header(tree_type)       \
                      select tree from parms                 \ 
                      returning tree_id, tree_type           \ 
                  )                                          \
             insert into  tree_detail(owner_name, tree_id)   \
                select unnest (p.owners), mt.tree_id         \
                  from parms p                               \ 
                  join make_tree mt on (mt.tree_type = p.tree);"

 db.cur.execute(statement, (last_header_id,list_owner_array))
 
 db.conn.commit()
 db.close()

注意:该语句没有返回任何内容,它要么是 Postgres 抛出的,要么是异常的。

【讨论】:

  • 我的代码是 Python,是的。 CTE 在某些情况下可以工作,但我不完全确定它是否可以在我的情况下工作。我正在这样做 - 1. 通过流从 API 中提取数据并将其放入 list() 2. 循环遍历返回的数据并为每个对象执行两次插入。所以基本上,我有一个循环遍历从 api 返回的每个对象,在该循环中,我将一些值插入到标题中,然后将其他值插入到细节中。细节与 FK 联系起来。在表之间创建一对多关系。有道理?我真的很感谢你写的!大量的好信息!
  • 您将查看从 API 中提取的内容,但只需要 1 条语句即可完成机器人插入。这意味着为每个对象调用 1 次服务器而不是 2 次(或 3 次 - 不确定 last_header_id = db.cur.fetchone()[0])。另外,作为建议,在所有对象写入后使用 1 次提交,而不是在每个对象后使用一次提交
  • 我会测试它并告诉你。如果它有效,我会有一些关于分解它的问题。我不知道你说的单次提交是什么意思?我已经做了一个提交。
  • 我已经阅读了您的答案,并对其进行了研究。如果这是一个 SP,您的解决方案将有效。但是当谈到在 Python 中使用它时,将多行插入到我的两个表之一中变得更加困难。这意味着,详细信息表将有多行绑定到标题的单行。因此,一次插入详细信息将一次插入多行。您的方法还引入了 SQL 注入,因为您在查询中直接拥有值。我的解决方案打破了价值观。不过,对于像 SP 这样的东西,你是一个很好的解决方案。
【解决方案2】:

这就是答案。这允许您创建循环、设置变量并将其传递给值。因此,如果您有一个从任何地方返回的数据集 - 只需通过它进入一个循环并将您的数据值分配给变量并将它们传递给插入。这也将值分开,并且可以在任一插入下插入多行。

import psycopg2

class MyData():
    def __init__(self, host="10.0.80.85", db="hhh", user="postgres", password="5bebfakee11"):
        self.conn = psycopg2.connect(host=host, database=db, user=user, password=password)
        self.cur = self.conn.cursor() 
            
    def close(self):
        self.cur.close()
        self.conn.close()


db = MyData()
insert = "INSERT INTO hhh.header (col1, col2) VALUES (%s, %s) RETURNING header_id;"
db.cur.execute(insert, ('variant1', 'true' ,))

last_header_id = db.cur.fetchone()[0]

insert = "INSERT INTO hhh.detail (header_id) VALUES (%s)"
db.cur.execute(insert, (last_header_id,))

db.conn.commit()
db.close()

【讨论】:

    猜你喜欢
    • 2012-11-19
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    • 2021-10-29
    • 2017-07-21
    • 2010-09-15
    • 1970-01-01
    相关资源
    最近更新 更多