【问题标题】:Why difference in Query response from Oracle using SQL Developer vs Python cx_Oracle library?为什么使用 SQL Developer 与 Python cx_Oracle 库的 Oracle 查询响应存在差异?
【发布时间】:2021-09-07 10:04:12
【问题描述】:

当我在 Oracle SQL Developer 中运行以下查询时,它运行良好并返回了我所期望的结果。

select to_timestamp(TRUNC(SYSDATE,'HH') - interval '1' hour, 'mm-dd-yyyy hh24:mi:ss') from dual

但是当我使用 cx_Oracle 在 Python 中运行它时,如下代码所示,它失败并带有以下附加的回溯。

代码:

import pandas as pd
import pyodbc
import cx_Oracle
from datetime import date, datetime
import boto3
from io import StringIO
import dateutil.relativedelta
import traceback


dsn_tns = cx_Oracle.makedsn('xyz', '1521', service_name='ABCD')
conn = cx_Oracle.connect(user=testUser', password='user123', dsn=dsn_tns)
extraction_query = '''select to_timestamp(TRUNC(SYSDATE,'HH') - interval '1' hour, 'mm-dd-yyyy hh24:mi:ss') from dual '''

完整的回溯如下:

Error in execution: Traceback (most recent call last):
File "C:\Users\AB\AppData\Local\Programs\Python\Python37\lib\site-packages\pandas\io\sql.py", line 1595, in execute
cur.execute(*args)
cx_Oracle.DatabaseError: ORA-01843: not a valid month



During handling of the above exception, another exception occurred:



Traceback (most recent call last):
File "oracle_query.py", line 30, in <module>
df_extracted_data =pd.read_sql(extraction_query,con=conn)
File "C:\Users\AB\AppData\Local\Programs\Python\Python37\lib\site-packages\pandas\io\sql.py", line 410, in read_sql
chunksize=chunksize,
File "C:\Users\AB\AppData\Local\Programs\Python\Python37\lib\site-packages\pandas\io\sql.py", line 1645, in read_query
cursor = self.execute(*args)
File "C:\Users\AB\AppData\Local\Programs\Python\Python37\lib\site-packages\pandas\io\sql.py", line 1610, in execute
raise_with_traceback(ex)
File "C:\Users\AB\AppData\Local\Programs\Python\Python37\lib\site-packages\pandas\compat\__init__.py", line 46, in raise_with_traceback
raise exc.with_traceback(traceback)
File "C:\Users\AB\AppData\Local\Programs\Python\Python37\lib\site-packages\pandas\io\sql.py", line 1595, in execute
cur.execute(*args)
pandas.io.sql.DatabaseError: Execution failed on sql 'select to_timestamp(TRUNC(SYSDATE,'HH') - interval '1' hour, 'mm-dd-yyyy hh24:mi:ss') from dual ': ORA-01843: not a valid month

注意:连接已经过测试,可以通过 python 进行任何其他查询。

【问题讨论】:

    标签: python python-3.x oracle oracle-sqldeveloper cx-oracle


    【解决方案1】:

    看起来你使用了错误的函数;不是to_timestamp,而是to_char(如果您的目标是将结果格式化为该格式掩码):

    SQL> select to_char(TRUNC(SYSDATE,'HH') - interval '1' hour, 'mm-dd-yyyy hh24:mi:ss') from dual
      2  /
    
    TO_CHAR(TRUNC(SYSDA
    -------------------
    06-23-2021 21:00:00
    
    SQL>
    

    为什么?因为结果——如果你省略“那个”函数,就是一个日期:

    SQL> select TRUNC(SYSDATE,'HH') - interval '1' hour from dual
      2  /
    
    TRUNC(SY
    --------
    23.06.21
    

    我的数据库设置是这样的——默认情况下——它显示为dd.mm.yy。如果我改变它:

    SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
    
    Session altered.
    

    然后结果看起来像我想要的:

    SQL> select TRUNC(SYSDATE,'HH') - interval '1' hour from dual
      2  /
    
    TRUNC(SYSDATE,'HH')
    -------------------
    23.06.2021 21:00:00
    
    SQL>
    

    因为你想在where子句中使用那个表达式:没问题,只要你比较date-to-date,比如下面的例子(sysdate是一个返回date数据类型值的函数) :

    SQL> select 'x' result
      2  from dual
      3  where sysdate > TRUNC(SYSDATE,'HH') - interval '1' hour;
               -------   ---------------------------------------
            this is DATE       and this is also DATE
    
    RESULT
    ----------
    x
    
    SQL>
    

    如果您将日期与其他东西进行比较,那么它是否会是值得怀疑的。

    【讨论】:

    • 不,我的目标是在谓词 (where) 子句中进行时间戳比较。完整的查询可以正常工作,包括 Oracle SQL Developer 中的子句,但不能在 Python 中工作。很奇怪。有什么线索吗?
    • 意外正在“工作”。您的数据库设置(或会话)使得 Oracle知道如何解释您提供给 to_timestamp 的值并返回结果。同时,我在答案中添加了更多信息;看一看。我相信 - 根据您的评论 - 您根本不需要 任何 功能。
    • 但是你给的那个,当我把它放在where子句中与日期时间字段进行比较时,它在python中给出了同样的错误,即使它在Oracle SQL Dev中运行良好。
    • 查看我发布的另一个关于 WHERE 子句的编辑。
    • Oracle 的date 本质上是一个没有小数秒的日期时间。大多数情况下,机器人需要明确地将其与时间戳一致,因为 oracle 可以比较日期和时间戳
    【解决方案2】:

    问题与不同的 nls 设置有关。只需比较 nls_session_parameters 的内容,比较数据格式即可。

    如果您进行隐式日期格式对话,nls_date_format 就会启动。

    永远不要依赖这些默认值,确保通过指定明确的模式或设置适合您应用的默认值来控制转化。它与 python 的关系不如其他客户端工具。

    【讨论】:

      【解决方案3】:

      没有给定的解决方案有效,然后我尝试调整函数并使用嵌套函数,最后以下在 Python 中成功运行:

      to_date(to_char(TRUNC(SYSDATE,'HH') - interval '1' hour, 'mm-dd-yyyy hh24:mi:ss'),'mm-dd-yyyy hh24:mi:ss')
      

      所有其他解决方案在 Python 中给出了与以下相同的错误:

      ORA-01843: 月份无效

      谁遇到这个问题,请继续使用上面的解决方案,它可以在谓词子句中工作。

      【讨论】:

      • to_dateto_timestamp 接受字符输入,但 trunc(sysdate, 'HH') 是日期。所以trunc(sysdate, 'HH') - interval '1' hour 仍然是一个日期。您不需要将其转换为 char 并返回
      • 你能用 Python 试试这个吗?运行查询时基本上会出现错误,因此双重显式转换为我们解决了这个问题。但我知道你说的完全有道理。
      • 我建议你回顾一下大答案。每当您在没有明确日期格式的情况下使用 to_char 或 to_date 或以某种方式将日期/字符串视为字符串/日期时,Oracle 将使用您的会话 NLS 设置。在 SQL Developer 中,这些意外地为您提供了很好的默认值,而在 Python 中却没有。您在此处的表达式可以简化为 TRUNC(SYSDATE,'HH') - interval '1' hour 而无需关心 to_date 或 to_char 因为 SYSDATE 是日期,TRUNC(SYSDATE,'HH') 是日期,date type - interval type 是日期,无需转换。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-20
      • 2022-10-13
      • 2021-04-12
      • 2021-03-31
      • 2012-06-14
      • 2011-04-06
      • 2021-04-24
      相关资源
      最近更新 更多