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