Oracle数据库查询结果为“ValueError:从日期时间列获取数据时出现“XXXX年超出范围”错误

n3ipq98p  于 2023-04-20  发布在  Oracle
关注(0)|答案(1)|浏览(490)
import pandas as pd
from io import StringIO
import boto3
import json
import datetime
import oracledb
import os

def DateTimeConverter(value):
    if value.year > 9999:
        return datetime.datetime.now()
    else:
        return value

def OutputHandler(cursor, name, defaulttype, length, precision, scale):
    print("OutputHandler: ", name, defaulttype, length, precision, scale)
    if defaulttype == oracledb.DB_TYPE_DATE:
        return cursor.var(oracledb.DB_TYPE_DATE, arraysize=cursor.arraysize, outconverter=DateTimeConverter)
    
def connect_to_db(user, password, host, port, service):
    try:
        conn = oracledb.connect(user=user, password=password,
                                dsn=host+":"+port+"/"+service, mode=oracledb.SYSDBA)
        conn.outputtypehandler = OutputHandler
        return conn
    except oracledb.DatabaseError as e:
        print('Error connecting to database: {}\n'.format(e))
        raise e

connection = connect_to_db("", "", "", "5500", "")

cursor = connection.cursor()

cursor.execute("select T$RGDT from T_ERPLNFP3.TBPTMM111100")

data = cursor.fetchall()

print("Row count: ", cursor.rowcount)

print(data[0])

cursor.close()

connection.close()

我尝试使用Python和oracledb模块从Oracle数据库中获取数据。表中的一列具有日期时间格式,列中的所有值均为'4712-01-01 00:00:00.000'。然而,当我运行代码时,我得到以下错误:

`File "src/oracledb/impl/thin/buffer.pyx", line 587, in oracledb.thin_impl.Buffer.read_date
File "src/oracledb/impl/thin/buffer.pyx", line 359, in oracledb.thin_impl.Buffer.parse_date
File ".eggs/Cython-0.29.33-py3.11-linux-x86_64.egg/Cython/Includes/cpython/datetime.pxd", line 120, in cpython.datetime.datetime_new
ValueError: year 60824 is out of range`

我不能更改源数据,所以我需要找到一种方法来获取数据,而不对数据库进行任何更改。当我在DB_Veawer或类似软件中运行相同的查询时,我得到的输出没有任何问题。
有人能帮助我理解为什么会发生这个错误,以及我如何使用Python和OracleDB模块获取数据而没有任何问题吗?任何帮助都将不胜感激。谢谢。

b4wnujal

b4wnujal1#

表中的一列具有日期时间格式
这是什么意思?它是哪种数据类型?我假设它不是DATE也不是TIMESTAMP而是VARCHAR2,并且值以字符串的形式存储在-你称之为-“日期时间格式”
并且所有列中的值为'4712-01-01 00:00:00.000'。
显然不是全部根据
ValueError:年份60824超出范围`
这个值- 60824 -听起来像我之前说过的,你把值存储为字符串,因为Oracle支持从-4713到+9999的年份(没有年份0)。例如:

SQL> select to_date('-5000', 'syyyy') from dual;
select to_date('-5000', 'syyyy') from dual
               *
ERROR at line 1:
ORA-01841: (full) year must be between -4713 and +9999, and not be 0

SQL>

你说过
当我在DB_Veawer或类似软件中运行相同的查询时,我得到的输出没有任何问题。
好吧,你确定你运行的查询返回了所有行吗?GUI工具通常返回前50或几百行,这意味着-如果存储了无效值 * 超出了初始范围 *,查询不会失败。
如果column包含无效值,你必须先找到它们,然后决定你想对它们做什么。如果是SQL,我可能会在CASE表达式中使用SUBSTR函数。例如:

SQL> alter session set nls_date_format = 'dd.mm.yyyy';

Session altered.

SQL> with test (col) as
  2    (select '60824-01-01' from dual union all
  3     select '4712-01-01'  from dual
  4    )
  5  select col,
  6    case when substr(col, 1, instr(col, '-') - 1) not between -4713 and 9999 then date '4712-01-01'
  7         else to_date(col, 'yyyy-mm-dd')
  8    end result
  9  from test;

COL         RESULT
----------- ----------
60824-01-01 01.01.4712    --> invalid year value set to 4712
4712-01-01  01.01.4712    --> valid

SQL>

也许你可以在Python中实现类似的东西;看不出来。
当然,它只是取决于你在该列中找到了什么新的 * 垃圾 *。因为它存储字符串,所以没有什么可以阻止像'12 cF-0x-3$'这样的值,它遵循“yyyy-mm-dd”格式,但这不是一个有效的日期值。
在我看来,这似乎是人们在将日期值存储到不适当的数据类型列中时遇到的另一个问题。

相关问题