【问题标题】:Python Cx_Oracle; How Can I Execute a SQL Insert using a list as a parameterPython Cx_Oracle;如何使用列表作为参数执行 SQL 插入
【发布时间】:2019-02-06 22:01:50
【问题描述】:

我生成了一个 ID 号列表。我想执行一个插入语句,从一个表中获取 ID 值在我的列表中的所有记录,并将这些记录插入到另一个表中。

我发现了这个 cx_Oracle 函数,而不是运行多个执行语句(据我所知是可能的),它据说可以使用单个语句和列表参数执行所有内容。 (它还避免了在传递参数之前 SQL 语句的笨拙格式)但是我认为我需要在将列表作为参数传递之前更改它。只是不确定如何。

我引用了这个网页: https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-executemany.html

ids = getIDs()
print(ids)

[('12345',),('24567',),('78945',),('65423',)]

sql = """insert into scheme.newtable
     select id, data1, data2, data3
     from scheme.oldtable
      where id in (%s)"""
cursor.prepare(sql)
cursor.executemany(None, ids)

我希望 SQL 语句执行如下:

插入到 scheme.newtable select id, data1, data2, data3 from scheme.oldtable where id in ('12345','24567','78945','65423')

相反,我收到以下错误: ORA-01036: 非法变量名称/编号

编辑: 我发现了这个 StackOverflow:How can I do a batch insert into an Oracle database using Python? 我更新了我的代码以预先准备语句并将列表项更新为元组,但我仍然遇到同样的错误。

【问题讨论】:

    标签: python-2.7 cx-oracle


    【解决方案1】:

    您将executemany() 用于批处理 DML,例如当您想要将大量值插入表中作为运行多个插入语句的有效等效项时。 https://blogs.oracle.com/opal/efficient-and-scalable-batch-statement-execution-in-python-cx_oracle中有cx_Oracle例子讨论

    但是你在做什么

    insert into scheme.newtable
         select id, data1, data2, data3
         from scheme.oldtable
          where id in (%s)
    

    是另一回事 - 您正在尝试使用 IN 子句中的多个值执行一个 INSERT 语句。为此,您可以使用普通的execute()

    由于 Oracle 将绑定数据与 SQL 区分开来,因此您不能将多个值传递给单个绑定参数,因为数据被视为单个 SQL 实体,而不是值列表。您可以使用您拥有的%s 字符串替换语法,但这对 SQL 注入攻击是开放的。

    Oracle 语言接口有多种通用技术,请参阅https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein 了解可以重写为 Python 语法的解决方案。

    【讨论】:

    • 我明白我在哪里弄糊涂了。谢谢你的澄清。所以我还是要做sql格式化。这有效:placeholders = ','.join(":%d" % i for i,_ in enumerate(ids))cursor.execute(sql % placeholders, ids)
    【解决方案2】:

    使用临时表保存id(批量插入)

    cursor.prepare('insert into temp_table values (:1)')
    dictList = [{'1': x} for x in ids]
    cursor.executemany(None, dictList)
    

    然后将选定的值插入新表中

    sql="insert into scheme.newtable (selectid, data1, data2, data3 from scheme.oldtable inner join temp_table on scheme.oldtable.id = temp_table.id)"
    cursor.execut(sql,connection)
    

    oracle中创建临时表的脚本

    CREATE GLOBAL TEMPORARY TABLE temp_table
    (
      ID  number
    );
    commit
    

    我希望这有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 1970-01-01
      • 2018-10-28
      • 2019-09-16
      相关资源
      最近更新 更多