没有子查询的Python mysql更新导致子查询错误

时间:2017-04-17 12:55:32

标签: python mysql string subquery longtext

我有以下代码

conn = MySQLdb.connect(server, user, password, database, autocommit=True, charset='utf8')
    for e in list_to_updpate:
        nid = e[0]
        vid = e[1]
        text = e[2]
        delta = e[3]
        deleted = e[4]
        langcode = e[5]
        to_update = e[6]
        if (to_update == 1):
            with conn.cursor() as cursor:
                cursor.execute("""update node__body set body_value=%s 
                                     where entity_id=%s AND revision_id=%s AND
                                     delta=%s AND deleted=%s AND langcode=%s;""" , 
                               (MySQLdb.escape_string(text) , int(nid), 
                                int(vid), int(delta), int(deleted), langcode, ))
            conn.commit()
    conn.close()

我有要更新的条目列表,文本是长文本,可以包含UTF8表中的任何内容。

当我运行代码时,我注意到两件事:

  1. 它运行一段时间但没有任何更新。
  2. 在某些时候,它会因错误而崩溃:

    _mysql_exceptions.OperationalError: (1242, 'Subquery returns more than 1 row')
    
  3. 我无法掌握它,我确信只有一行得到更新,因为根据表定义,主键定义为(entity_id,revision_id,delta,deleted,langcode)

    注意:pymysql和python3.6上的MySQL-client重复此行为

    此致 T

2 个答案:

答案 0 :(得分:1)

找到答案:

事实证明,为了匹配mysql数据库的LONGTEXT,应该使用io.String()对象来传递文本。否则它的行为不符合预期。大多数情况下,您可以期望将一个简单的字符串映射到varchar,该字符串应该是最大长度。请注意,因为varchar可以是LONG TEXT的子集,所以如果查询提交,则不会引发错误,如果将输入提交到DB,则会裁剪输入。为什么在这个特殊情况下,它从未承诺(见问题中的讨论)对我来说仍然不清楚。现在工作代码:

conn = MySQLdb.connect(server, user, password, database, autocommit=True, charset='utf8')
for e in list_to_update:
    cursor = conn.cursor()
    nid = e[0]
    vid = e[1]
    text = e[2]
    delta = e[3]
    deleted = e[4]
    langcode = e[5]
    to_update = e[6]
    if to_update == 1:
        cursor.execute(
            "update node__body set body_value=%s where entity_id=%s AND revision_id=%s AND delta=%s AND deleted=%s AND langcode=%s",
            (io.StringIO(text), nid, vid, delta, deleted, langcode))
        conn.commit()
    cursor.close()
conn.close()

注意这是Python3。对于Python2,请使用StringIO.String()

希望有所帮助,
托多尔

答案 1 :(得分:0)

在发布代码之前,我想指出一些事项。

首先,不需要escape_string,因为execute会为你做,只要你在元组中包含参数作为第二个元素。

我怀疑你的问题在光标周围。似乎在提交任何内容之前正在打开,使用和关闭。

如果没有任何元素违反了更新列表中所有元素所需的光标,我建议采用这种方法。

conn = MySQLdb.connect(server, user, password, database, autocommit=True, charset='utf8')
cursor = conn.cursor()
for e in list_to_update:
    nid = e[0]
    vid = e[1]
    text = e[2]
    delta = e[3]
    deleted = e[4]
    langcode = e[5]
    to_update = e[6]

    if to_update == 1:
        cursor.execute("update node__body set body_value=%s where entity_id=%s AND revision_id=%s AND delta=%s AND deleted=%s AND langcode=%s" , 
                               (text , nid, vid, delta, deleted, langcode))
        conn.commit()
    cursor.close()
    conn.close()

如果您只需要在一端进行一次提交,则只需编辑提交行,删除一个缩进。 另请注意,我已添加cursor.close,因为我没有使用with方法。