Day: July 31, 2021

  • [บันทึกกันลืม] วิธีแก้ปัญหาข้อมูลประเภท timedelta64[ns] ใน Pandas ไม่สามารถเขียนลงฐานข้อมูล field ที่เป็น Time ได้

    เหตุ:

    import pymysql
    import pandas as pd
    import sqlalchemy
    
    import time
    import datetime
    
    conn = pymysql.connect(
            host="source.database.server",
            port=3306,
            user='username',
            password='password',
            database='databasename',
        )
    
    sql="""
       SELECT *
       FROM   table1
    """
    df1=pd.read_sql(sql,conn)
    df1.dtypes

    ผลคือ:

    .
    .
    .
    ref_visit_date                            object
    ref_visit_time                   timedelta64[ns]
    .
    .
    .
    

    ซึ่ง ref_visit_time นั้น ใน MySQL/MariaDB ใช้ชนิดเป็น Time

    เช่น 08:00:00 หมายถึง 8 นาฬิกา อะไรทำนองนั้น

    ปัญหา:

    อยู่ที่ตอนเอา Dataframe นี้ ไป Write ใส่อีก Table นึง

    host="destination.database.server"
    port=int(3306)
    user='user'
    password='password'
    dbname='databasename'
    db_string = f"mysql+pymysql://{user}:{password}@{host}:{port}/{dbname}"
    
    destination_conn = sqlalchemy.create_engine(db_string)
    
    df.to_sql('table2'
           , con=destination_conn
           , if_exists='append'
           , index=False
           , method='multi'
           , chunksize=10000)

    ซึ่ง table2 นั้น มีโครงสร้างเหมือนกับ table1 เลย โดยเฉพาะ ref_visit_time มีชนิดเป็น Time เช่นกัน

    แต่ถ้า run code นี้จะได้ Error/Warning ว่า

    UserWarning: the 'timedelta' type is not supported, and will be written as integer values (ns frequency) to the database.

    เหตุเพราะ แทนที่จะเก็บเป็น Time มันดันเปลี่ยนเป็น Integer ที่เป็นจำนวน Nanosecond แทนนั่นเอง

    วิธีแก้ไข

    ต้องตรวจสอบว่า มี column ใน destination table มีชนิดเป็น Time (timedelta64[ns]) ให้เอาไปบวกกับเวลาเริ่มต้น แล้ว เปลี่ยนชนิดเป็น Time แทน ดังนี้

    for column in df:
        if df[column].dtype == 'timedelta64[ns]':
            df[column]=df[column].apply(lambda x: (datetime.datetime.min+x).time())

    เราก็จะได้ข้อมูลที่ถูกต้องกลับมา

    ตามนั้นครับ