【问题标题】:Insert next value of sequence using cx_Oracle Cursor.executemany()使用 cx_Oracle Cursor.executemany() 插入序列的下一个值
【发布时间】:2020-05-23 22:57:13
【问题描述】:

我正在尝试使用 python 中的 cx_oracle 库来插入行,其中一个列值是名为 an_aj_s 的序列中的下一个值。

我创建了一个名为 insert_into_columns 的函数来执行此操作,对该函数的调用如下所示:

self.insert_into_columns('AN_JOB',
                         ('AJ_ID','AJ_JOBNAME', 'AJ_DESCRIPTION', 'AJ_CD_JOB_TYPE', 'AJ_CD_DATABASE','AJ_CD_JOB_STATUS', 'AJ_USR_ID', 'AJ_CREATE_DATE', 'AJ_EQUIP_COMPS_FLAG'),
                         [ ('an_aj_s.nextval', 'QlikManual_3', 'First Manually entered Test Job', 2, 0, 1  ,6 , dt.today().date(),  1)])

参数在哪里: insert_into_columns({Table Name}, {Columns to insert}, {row of values to insert})

当我调用该函数时,我收到一个错误无效号码: cx_Oracle.DatabaseError: ORA-01722: 无效号码

我确定问题出在序列上,因为如果我用数字替换序列,则插入成功。谁能告诉我在向表中插入行时如何调用我的序列?

我尝试使用 cur.setinputsizes() 设置输入大小,但它似乎不起作用。

附加信息:

我的函数生成的 SQL 语句如下所示:

INSERT INTO AN_JOB (AJ_ID,AJ_JOBNAME,AJ_DESCRIPTION,AJ_CD_JOB_TYPE,AJ_CD_DATABASE,AJ_CD_JOB_STATUS,AJ_USR_ID,AJ_CREATE_DATE,AJ_EQUIP_COMPS_FLAG) VALUES ( :1, :2, :3, :4, :5, :6, :7, :8, :9 )

生成语句的实际python函数如下所示:

 def insert_into_columns(self, table_name, columns, rows):
    sql = "INSERT INTO {table_name} ({column_names}) VALUES ({column_args} )"
    args_str = ''
    col_str  = ''
    for col_id in range(1, len(columns) + 1):
        args_str += ' :' + str(col_id)
        col_str += columns[col_id - 1]
        if col_id < len(columns):
            args_str += ','
            col_str += ','

    sql = sql.format(table_name=table_name, column_names =col_str,  column_args=args_str)
    print('Inserting rows into specified columns...')
    print(sql)

    with self.conn.cursor() as cur:
        cur.executemany(sql, rows)
        self.conn.commit()

【问题讨论】:

    标签: python oracle insert sequence cx-oracle


    【解决方案1】:

    在您的 SQL 语句中,您将所有值作为绑定变量传递。这通常很棒!但是 SQL 引擎不会解释绑定变量。所以对于AJ_ID 列,您不会像您想要的那样调用序列伪列an_aj_s.nextval,而是传递一个varchar2 字符串'an_aj_s.nextval'。 Oracle 需要一个数字,而不是字符串,因此您会收到 ORA-01722 错误。

    你需要修改你的函数,而不是这样:

    INSERT INTO AN_JOB (AJ_ID,AJ_JOBNAME,AJ_DESCRIPTION,AJ_CD_JOB_TYPE,AJ_CD_DATABASE,AJ_CD_JOB_STATUS,AJ_USR_ID,AJ_CREATE_DATE,AJ_EQUIP_COMPS_FLAG) 
    VALUES ( :1, :2, :3, :4, :5, :6, :7, :8, :9 )
    

    你正在生成这个:

    INSERT INTO AN_JOB (AJ_ID,AJ_JOBNAME,AJ_DESCRIPTION,AJ_CD_JOB_TYPE,AJ_CD_DATABASE,AJ_CD_JOB_STATUS,AJ_USR_ID,AJ_CREATE_DATE,AJ_EQUIP_COMPS_FLAG) 
    VALUES ( an_aj_s.nextval, :2, :3, :4, :5, :6, :7, :8, :9 )
    

    这有意义吗?有很多方法可以改变你的函数来做到这一点,但你还没有解释你的其他用例,所以我不想推荐任何特定的用例。

    或者,您可能会发现通过创建序列触发器在 Oracle 端执行此操作更容易。 SO上有很多例子(like this

    CREATE OR REPLACE TRIGGER an_job_id_trigger
    BEFORE INSERT ON an_job
    FOR EACH ROW
      WHEN (new.ID IS NULL)
    BEGIN
      :new.ID := an_aj_s.nextval;
    END;
    /
    

    这样,您可以完全从插入中省略 ID 列,触发器会处理它:

    INSERT INTO AN_JOB (AJ_JOBNAME,AJ_DESCRIPTION,AJ_CD_JOB_TYPE,AJ_CD_DATABASE,AJ_CD_JOB_STATUS,AJ_USR_ID,AJ_CREATE_DATE,AJ_EQUIP_COMPS_FLAG) 
    VALUES (:1, :2, :3, :4, :5, :6, :7, :8 )
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 2019-04-19
    • 1970-01-01
    相关资源
    最近更新 更多