Python执行带IF判断的PostgreSQL写入语句加载数据报错
问题描述
我正尝试使用Python将某地方报社的一系列推文存储到PostgreSQL数据库中。手动通过PgAdmin加载数据时SQL查询运行完全正常,但使用Python自动化执行该流程时出现问题,希望大家可以帮忙排查代码问题。
相关代码
Python逻辑代码
def obtiene_tweets(usuario, auth = auth_titter(), cantidad = 100): fuente = obtiene_id(usuario) # 连接Twitter API api = tweepy.API(auth) # 打开数据库连接 conn = psycopg2.connect(dbname = config.DB_NAME, user = config.DB_USER, password = config.DB_PASSWORD, host = config.DB_HOST) # 遍历拉取推文并存库 cur = conn.cursor() for tweet in tweepy.Cursor(api.user_timeline, screen_name = fuente.loc['usuario',].values[0], tweet_mode= 'extended').items(cantidad): full_text = tweet._json['full_text'] id = fuente.loc['id',].values[0] fecha = tweet._json['created_at'] try: hashtags = str(tweet._json['entities']['hashtags']).replace('[','') hashtags = hashtags.replace(']','') if hashtags == '': hashtags = 'Null' except: pass try: url = tweet._json['entities']['urls'][0]['expanded_url'] except: url = 'Null' try: likes = tweet._json['favorite_count'] rts = tweet._json['retweet_count'] except: pass cur.execute(sql_statements.CARGA_TWEETS, (full_text.replace("'","'"),id,full_text.replace("'","'"), fecha, hashtags, url, likes, rts)) cur.close() conn.close()
对应SQL语句
CARGA_TWEETS = """ DO $$ BEGIN IF EXISTS(SELECT tweet FROM tweets WHERE tweet = %s ) THEN raise notice 'Se encuentra el tweet'; ELSE insert into tweets(id_usuario, tweet, fecha, hashtags, urls, likes, rts) values(%s, %s, %s, %s, %s, %s, %s ); END IF; END $$ """
报错信息
Traceback (most recent call last): File "/media/mariano/Nuevo vol/CarpetaProtegida/Provincia/Propuestas/Proyectos/resumen-noticias/funciomes.py", line 121, in <module> obtiene_tweets('clarineconomico') File "/media/mariano/Nuevo vol/CarpetaProtegida/Provincia/Propuestas/Proyectos/resumen-noticias/funciomes.py", line 111, in obtiene_tweets cur.execute(sql_statements.CARGA_TWEETS, (full_text.replace("'",''),id,full_text.replace("'",''), fecha, hashtags, url, likes, rts)) psycopg2.errors.StringDataRightTruncation: value too long for type character varying(200) CONTEXT: SQL statement "insert into tweets(id_usuario, tweet, fecha, hashtags, urls, likes, rts) values(9, 'José Mujica: Me he puesto viejo sintiendo de crisis en Argentina y sin embargo, no sé cómo, pero siempre salen adelante url', 'Fri Aug 27 13:26:22 +0000 2021', 'Null', 'extended_url', 7, 1 )" PL/pgSQL function inline_code_block line 8 at SQL statement
解决方案
报错的核心原因是你数据库中tweet字段设置的类型是character varying(200),仅支持最多200个字符的存储,而现在要插入的推文内容长度已经超出了这个限制,你可以选择两种方案解决:
- 调整数据库字段类型:把
tweet字段的类型从varchar(200)改成text类型,PostgreSQL的text类型没有固定长度限制,完全可以适配最长的推文内容,修改字段的SQL语句如下:
ALTER TABLE tweets ALTER COLUMN tweet TYPE text;
如果还有其他字段比如urls、hashtags也有超长的可能,也可以同步改成text类型。
- 入库前截断内容:如果你不需要存储完整的推文内容,也可以在Python代码中对要入库的字符串做截断处理,比如把推文内容限制到199个字符:
full_text = tweet._json['full_text'][:199]
另外现有代码还有两个可以优化的点:
- 不需要手动替换单引号,psycopg2的参数化查询会自动处理特殊字符的转义,你写的
full_text.replace("'","'")完全没有任何作用,可以直接删掉替换逻辑。 - 你现在写的PL/pgSQL的
DO块对参数化传递的支持不好,更推荐直接用PostgreSQL原生的INSERT ... ON CONFLICT语法实现存在就跳过的逻辑,性能更好也更稳定,前提是你要给tweet字段加唯一索引。
内容的提问来源于stack exchange,提问作者Mariano Radusky Giobellina
相关产品推荐
相关产品推荐

