【问题标题】:How to insert a variable value into table?如何将变量值插入表中?
【发布时间】:2019-09-26 18:46:12
【问题描述】:

假设我有以下文件.csv

DATE    Name    Email
26-Sep-19   Name1   Name1@email.com 
26-Sep-19   Name2   Name2@email.com 
26-Sep-19   Name3   Name3@email.com 

我正在尝试将 file.csv 中的值插入到表中

import cx_Oracle
import csv
import os
from datetime import datetime

con = cx_Oracle.connect(uname, pwd, hostname + ': ' + port + '/' + service)
cursor = con.cursor()

with open('file.csv', 'r') as csv_file:
    csv_reader = csv.reader(csv_file, delimiter=',')
    for lines in csv_reader:
        cursor.execute( "INSERT INTO table1 ( DATE,Name,Email) values (:1, :2, :3)", 
        (lines[0],lines[1],lines[2])  
cursor.close()
con.commit()
con.close()

我收到此错误:

(lines[0],lines[1],lines[2]) cx_Oracle.DatabaseError: ORA-01858: a 在需要数字的地方发现了非数字字符

经过一些调试,我能够将问题归结为日期问题,所以我用硬编码的日期代替了行 [0],它起作用了!

cursor.execute( "INSERT INTO table1 ( DATE,Name,Email) values (:1, :2, :3)", 
('26-Sep-19',lines[1],lines[2])  

为什么它不能与 lines[0] 变量一起使用,但使用硬编码的值却可以正常工作?

【问题讨论】:

  • lines[0]的值和'26-Sep-19'的格式一样吗?
  • @blhsing 是的

标签: python-2.6 cx-oracle


【解决方案1】:

日期的字符串格式必须符合 Oracle 的预期。您可以为您的会话设置NLS_DATE_FORMAT 参数,或者您可以简单地修改您的代码以执行以下操作:

cursor.execute("""
        insert into table1 (date, name, email)
        values (to_date(:1, 'dd-Mon-YY'), :2, :3)""",
        (lines[0], lines[1], lines[2]))

【讨论】:

  • 不起作用,仍然出现相同的非数字错误:/
  • 您是否从 CSV 文件中剥离(或跳过)标题行?如果您尝试使用名为 DATE 的列名,您可能会遇到其他问题。您可能需要在其周围使用双引号,具体取决于表的创建方式。
  • 别忘了数据文件里面应该有逗号,但是你会显示空格。
  • 我更新了答案中的代码以合并您的数据和@anthony 的日期转换
  • @Christopher Jones 我在这里错过了你的回复,尽管我一直在检查,因为我似乎没有被标记。我认为您的意思是对您的答案发表评论,因为它不需要标记。不过非常感谢!
【解决方案2】:

现在您已经解决了日期格式问题,考虑使用executemany() 来提高性能。比如:

使用 file.csv 包含:

26-Sep-19,Name1,Name1@email.com 
26-Sep-19,Name2,Name2@email.com 
26-Sep-19,Name3,Name3@email.com 

创建的表格如下:

create table table1 ("DATE" date, name varchar2(20), email varchar2(20));

然后这个文件使用@anthony 提到的日期转换工作:

# Set cursor sizes to match the table definition or known max data sizes
#   create table table1 ("DATE" date, name varchar2(20), email varchar2(20));
cursor.setinputsizes(None, 20, 20)

# Adjust the batch size to meet your memory and performance requirements
batchSize = 1000

with open('file.csv', 'r') as csv_file:
    csv_reader = csv.reader(csv_file, delimiter=',')
    i = 0
    data = []
    for line in csv_reader:
        data.append((line[0],line[1],line[2]))
        i = i + 1
        if (i % batchSize == 0):
            print('batch')
            cursor.executemany("""insert into table1 ("DATE",name, email) values (to_date(:1, 'DD-Mon-YY'), :2, :3)""", data)
            data = []
            i = 0
    if (i % batchSize != 0):
        print('final')
        cursor.executemany("""insert into table1 ("DATE",name, email) values (to_date(:1, 'DD-Mon-YY'), :2, :3)""", data)
    con.commit()

使用类似的脚本将一些行加载到世界另一端的数据库需要 4 秒(主要是连接时间成本),而使用 execute() 需要 36 秒

【讨论】:

  • 有趣!我确实看到 execute() 的执行速度很慢,尤其是 csv 文件中的 4k 左右的行。
  • executemany() 上的文档位于 cx-oracle.readthedocs.io/en/latest/user_guide/…
  • 嘿我试过你的答案,因为安东尼的答案对我不起作用,我仍然得到相同的非数字数字错误:/
  • 我尝试了硬编码的值并且它有效,但是没有硬编码的值它再次抱怨数字与非数字,就像我的任务中一样
  • 终于成功了!问题确实是标题行!日期前后需要双引号!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-28
  • 2013-06-16
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多