sql server datetime to oracle时间戳问题

sqlserver datetime to oracle timestamp problems

所以我正在进行一个项目,将数据从 sql 服务器数据库移动到 oracle 数据库,日期让我很难过。为了进行数据移动,我有一个 python 脚本,它从 sql 服务器数据库中提取数据,然后 运行s 插入查询。

问题是日期看起来像这样 2016-06-01 05:45:06.003 但如果我删除小数秒它将违反主键,因为 2016-06-01 05:45:06 有很多记录但 [=] 只有一个11=] 所以它必须有毫秒。

我应该提到 oracle 中列的数据类型是 TIMESTAMP

如果我只是提取记录和 运行 我的插入 这只是一个基本的插入,具有这样的值 VALUES(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15)

这样做让我的约会看起来像这样 01-JUN-16 07.05.41.000000000 AM。这很好,但是对于每条记录,小数秒都是 000000,所以我失去了准确性,这让我违反了主键。

我认为解决方法是明确格式,因此我将插入语句值子句修改为这样 VALUES(TO_TIMESTAMP(:1, 'YYYY-MM-DD HH24:MI:SS,FF9'), :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15)。这更糟糕,因为它将每一行中的所有日期更改为 16-JUN-20 12.00.00.000000000 AM 我也尝试过 YYYY-MM-DD HH24:MI:SS,FF9 但这会产生相同的结果。

我确定我错过了这个愚蠢的东西,但对于我的生活我不知道它是什么。

自问以来,sql 服务器 table 上的列的数据类型是 DateTime,而在 oracle 服务器上,我目前将其设置为 TimeStamp(3) 但是我可以在 oracle 端更改数据类型。

我正在使用 cx_oracle 连接和 运行 插入。我可以确认在插入 运行 之前数据确实有毫秒数。

python:

def RunQuery():
    srccrsr.execute(query)
    return srccrsr.fetchall()

def RunQuery():
    srccrsr.execute(query)
    return srccrsr.fetchall()

def BuildBindList(recordsToWrite):
    closingRecords = []
    for rec in recordsToWrite:
        closingRecords.append((rec[0], rec[1], rec[2], rec[3], rec[4], rec[5], rec[6], rec[7], rec[8], rec[9], rec[10], rec[11], rec[12], rec[13], rec[14]))
    return closingRecords   

def write_to_table(recordsToWrite):  
    SQL = """INSERT INTO TRACE (DATETIME, ID, TZ, DOMAINID, EVENTNAME, REASONCODE, TARGETID, STATE, KEY, PERIPHERALKEY, RECOVERYKEY, DIRECTION, ROUTERDAY, ROUTERCKEY, ROUTERNUMBER)
            VALUES(TO_TIMESTAMP(TO_CHAR(:1), 'yyyy-mm-dd hh24:mi:ss.ff3'), :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15)"""
    try:
        trgtcrsr.prepare(SQL)
    except cx_Oracle.DatabaseError, exception:
        print ('Failed to prepare cursor')
        print Exception(exception)
        exit (1)
    try:
        trgtcrsr.executemany(None, recordsToWrite)        
    except cx_Oracle.DatabaseError, exception:
        print ('Failed to insert rows')
        print Exception(exception)
        exit (1)

    trgtcnn.commit()
    trgtcnn.close()
    source_connection.close()

def main():
    recordstowrite = BuildBindList(RunQuery())
    write_to_table(recordstowrite) 

if __name__ == "__main__":
    main()

您遇到的问题可能与您的 nls 格式设置有关。但是,我没有看到使用 to_timestamp:

的问题
with sample_data as (select '2016-06-01 05:45:06.003' col1 from dual union all
                     select '2016-06-01 12:55:06.638' col1 from dual union all
                     select '2016-06-02 11:53:24.827' col1 from dual)
select col1,
       to_timestamp(col1, 'yyyy-mm-dd hh24:mi:ss.ff3') col1_ts,
       to_char(to_timestamp(col1, 'yyyy-mm-dd hh24:mi:ss.ff3'), 'yyyy-mm-dd hh24:mi:ss.ff3') col1_ts_str
from   sample_data;

COL1                    COL1_TS                                            COL1_TS_STR                  
----------------------- -------------------------------------------------- -----------------------------
2016-06-01 05:45:06.003 01/06/2016 05:45:06.003000000                      2016-06-01 05:45:06.003      
2016-06-01 12:55:06.638 01/06/2016 12:55:06.638000000                      2016-06-01 12:55:06.638      
2016-06-02 11:53:24.827 02/06/2016 11:53:24.827000000                      2016-06-02 11:53:24.827  

(col1_ts 列是 oracle 存储的时间戳,以默认格式作为字符串返回(在不同的客户端上可能会有所不同,具体取决于他们是否弄乱了他们的 nls 格式) ,col1_ts_str 是以我请求的特定格式作为字符串返回的时间戳。

您应该通过在时间戳列上执行 to_char 检查是否正确输入了数据,例如

select to_char(your_timestamp_column, '<format>') ts_col
from   your_table;

This Oracle article 警告:

Fractional seconds of a date/time value passed as a bind variable will be truncated unless the setinputsizes() method is used between prepare() and execute()

文章的示例表明,要节省毫秒,您需要为 tval 参数指定输入大小:

ts = datetime.datetime.now()
cursor.prepare("INSERT INTO python_tstamps VALUES(:t_val)")

cursor.setinputsizes(t_val=cx_Oracle.TIMESTAMP)

cursor.execute(None, {'t_val':ts})
db.commit()