2016-06-20 6 views
0

私はSQL ServerデータベースからOracleデータベースにデータを移動するプロジェクトに取り組んでいます。日付は苦労しています。データの移動を行うために、私は、SQL Serverデータベースからデータを取り出し、挿入クエリを実行するpythonスクリプトを用意しています。sqlserver datetimeからoracleタイムスタンプの問題

問題は、日付はこの2016-06-01 05:45:06.003のように見えるが、私は小数秒を落とした場合、それはそれでミリ秒を持っている必要がありますので、そこにレコードのたくさん2016-06-01 05:45:06であるだけ2016-06-01 05:45:06.003 1つとして、それが主キーに違反するということです。私はちょうどレコードを引き、ちょうどこのVALUES(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15)

のような値を持つ基本的な挿入が得ることをやっている私の挿入を実行する場合、Oracleの列のためのデータ型はTIMESTAMP

で言及する必要があり

私の日付は01-JUN-16 07.05.41.000000000 AMのようになります。これは問題ありませんが、1レコードごとに分秒が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 Serverテーブルの列のデータ型は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() 
+1

まず、Pythonスクリプトで取得したデータにミリ秒のデータがあることを確認しましたか? Pythonスクリプトは値を文字列値またはタイムスタンプとして格納していますか? – MT0

+1

これはSQL ServerやOracleとはほとんど関係がありませんが、タイムスタンプをプライマリキーとして使用するのは良い考えではありません。いずれの場合でも、日付はフォーマットを持たず、バイナリ値です。それらをテキストに変換せずにパラメータ化されたクエリを使用する場合、あるデータベースから別のデータベースにそのまま値を渡すことができます。どのライブラリを使用していますか? –

+0

私はそれが良い考えではないことを十分に認識しています。しかし、私は安価な協同組合で、彼らはそれを変更したくありません。キーには他の列があります。 – user5999614

答えて

2

This Oracle articleことを警告:setinputsizes()メソッドは(準備()と実行の間に使用されていない場合、バインド変数として渡さ

日付/時刻の秒の小数部の値が切り捨てられます)

記事の例では、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() 
+0

位置指定引数付きのinputsizes()を使用すると構文エラーが発生し、名前付き引数に切り替えました。 'timestamp' d_val'を呼んでいます準備と実行の間に 'trgtcrsr.setinputsizes(d_val = cx_Oracle.TIMESTAMP)'があり、ORA-01830:入力フォーマット全体を変換する前に日付フォーマットのピクチャが終了しています ' – user5999614

+0

これは実際に問題。私はそれを動作させるには束を混乱させなければならなかったが、 'setinputsizes()'を使って固定した。 – user5999614

2

それは何を経験していることは、あなたの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列には応じて、異なるクライアントに異なる場合があり、デフォルトの形式の文字列(として返される神託によって保存されているタイムスタンプです彼らがnls形式で混乱しているかどうかについて)、col1_ts_strは、私が要求した特定の形式の文字列として返されるタイムスタンプです。

タイムスタンプの列にto_charを入力すると、データが正しく入力されていることを確認する必要があります。

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

SQL Developerでは 'to_timestamp(col1、 'yyyy-mm-dd hh24:mi:ss.ff3')'でselectを実行すると正しい結果が得られます。それがpythonスクリプトからの挿入で使用されているときは、それはしません。 – user5999614

+0

したがって、SQL Developerを使用して挿入を実行すると、Pythonで実行したときと同じ結果になりますか? – Boneist

+0

それはあまりにもそこで動作します。多分それはpython。私はPythonスクリプトをデバッグし、SQL Serverから取得したレコードを見ると、日付の値の型がdatetime.datetimeであると言われています。しかし、ミリ秒はまだそこにあります。 'datetime.datetime(2016,6,1,5,45,6,20000)' – user5999614