用pandas处理tushare数据入库的时候主键唯一无法插入更新的解决方法

该博客介绍了如何处理使用Pandas的to_sql函数向数据库插入数据时遇到的主键冲突问题。提供了两种方法:一是利用数据库的REPLACE命令更新临时表;二是先检查并删除已有相同主键的数据,再插入新数据。示例代码展示了如何检查和删除重复数据,确保数据更新的顺利进行。
摘要由CSDN通过智能技术生成

tushare数据接口与pandas是绑定的,本身是非常适合查询到之后就直接通过to_sql函数直接入库。但是往往我们会设置一个主键,在第一次插入之后,再更新数据带有已入库的数据就会在执行to_sql函数会报主键唯一,无法插入的错误了。

解决这个问题的办法有两种:

一种是参考https://blog.csdn.net/pz789as/article/details/105684498 这篇文章,将新的数据存入一个临时的表,然后再执行数据库的REPLACE命令,将临时表的数据更新到原表,再删除临时表。

另外一种方法是可以先在已入库的表中查找本次获取到的dataframe键值,如果有相同的则先将其删除,然后再用to_sql函数写入即可。

示例如下:

   

 def check_ts_code_in_table(self, table_name, ts_code):
        """
        检查指定的ts_code是否在表中
        :param table_name:表的名字,需要在DbTables中定义为sqlalchemy的Table对象
        :param ts_code: 需要查询的
        :return: 存在则返回True/False及查询到的列表对象
        """
        cmd = '%s_db.c.ts_code' % (table_name)
        obj = eval(cmd)  # 需要转换为对应的对象,不能直接为字符串
        s = select([obj]).where(obj == ts_code)

        rp = self.connection.execute(s)
        results = rp.fetchall()  # 返回一个包含查询结果的列表,列表内为元组数据,如[('510500.SH',), ('510500.SH',), ('510500.SH',)]
        if len(results) > 0:
            return True, results
        else:
            return False, results

    def check_ts_code_and_trade_date_in_table(self, table_name, ts_code, trade_date):
        """
        检查指定的ts_code、trade_date是否在表中
        :param table_name:表的名字,需要在DbTables中定义为sqlalchemy的Table对象
        :param ts_code: 需要查询的
        :return: 存在则返回True/False及查询到的列表对象
        """
        cmd1 = '%s_db.c.ts_code' % (table_name)
        obj1 = eval(cmd1)  # 需要转换为对应的对象,不能直接为字符串
        cmd2 = '%s_db.c.trade_date' % (table_name)
        obj2 = eval(cmd2)
        dd = (datetime.datetime.strptime(trade_date, "%Y%m%d")).strftime('%Y-%m-%d')
        # 查询方法1
        s = select([obj1, obj2]).where(and_(obj1 == ts_code, obj2 == dd))
        # sql_cmd='ts_code=\'%s\' and trade_date=\'%s\'' %(ts_code,trade_date)#查询方法2
        # s = select([obj1, obj2]).where(text(sql_cmd))

        rp = self.connection.execute(s)
        results = rp.fetchall()  # 返回一个包含查询结果的列表,列表内为元组数据,如[('510500.SH',), ('510500.SH',), ('510500.SH',)]
        # print(results)
        if len(results) > 0:
            return True, results
        else:
            return False, results
def process_duplicate_data_in_table(self, table_name, keys):
    """
    根据提供的主键值(ts_code、trade_date)删除表中对应的数据,以便pandas能够to_sql插入数据
    :param table_name: 表名,需要在DbTables中定义为sqlalchemy的Table对象
    :param keys: 主键值(ts_code、trade_date),主键为ts_code的只需要提供ts_code
    :return: 
    """
    # 检查键值
    key_num = len(keys)
    if key_num == 0:
        logger.error('have not give the keys')
        return
    elif key_num == 1:
        flag, results = self.check_ts_code_in_table(table_name, keys[0])
        if flag:
            # 有存在的键值数据,需要从表中删除对应数据
            cmd = '%s_db.c.ts_code' % (table_name)
            obj = eval(cmd)  # 需要转换为对应的对象,不能直接为字符串

            u = delete(eval('%s_db' % table_name)).where(obj == keys[0])
            self.connection.execute(u)
            # logger.info('the duplicate data in talbe: %s have been deleted, just do to_sql' % table_name)
            return
        else:
            # logger.info('there is no duplicate data in talbe: %s, just do to_sql' % table_name)
            return
    elif key_num == 2:
        flag, results = self.check_ts_code_and_trade_date_in_table(table_name, keys[0], keys[1])
        if flag:
            # 有存在的键值数据,需要从表中删除对应数据
            cmd = '%s_db.c.ts_code' % (table_name)
            obj1 = eval(cmd)  # 需要转换为对应的对象,不能直接为字符串

            cmd = '%s_db.c.trade_date' % (table_name)
            obj2 = eval(cmd)  # 需要转换为对应的对象,不能直接为字符串
            trade_date = (datetime.datetime.strptime(keys[1], "%Y%m%d")).strftime('%Y-%m-%d')
            u = delete(eval('%s_db' % table_name)).where(and_(obj1 == keys[0], obj2 == trade_date))
            self.connection.execute(u)
            # logger.info('the duplicate data in talbe: %s have been deleted, just do to_sql' % table_name)
            return
        else:
            # logger.info('there is no duplicate data in talbe: %s, just do to_sql' % table_name)
            return
    else:
        return

#调用示例:
df = self.ts_pro_obj.daily(trade_date=trade_dt)

for index in range(df.shape[0]):
     keys = df[['ts_code', 'trade_date']].loc[index].tolist()
     self.process_duplicate_data_in_table(self.table_name, keys)

 

注册tushare可以访问邀请链接:https://tushare.pro/register?reg=393205

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值