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;
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()
所以我正在进行一个项目,将数据从 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;
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()