【问题标题】:Python Sqlite3 - how to work very very long WHERE IN() clausePython Sqlite3 - 如何工作非常长的 WHERE IN() 子句
【发布时间】:2013-09-09 08:39:39
【问题描述】:

[使用 Python3.x] 基本思想是我必须运行第一个查询来提取一长串 ID(文本)(大约一百万个 ID),并在另一个查询的 WHERE 语句中的 IN() 子句中使用这些 ID。我正在使用 python 字符串格式来实现这一点,并且如果 ID 的数量很小 - 比如 100k - 但效果很好,但是当集合确实大约有一百万个 ID 时会给我一个错误 (pyodbc.Error: ('08S01', '[08S01] [MySQL][ODBC 5.2(a) Driver][mysqld-5.5.31-MariaDB-log]MySQL server has gone away (2006) (SQLExecDirectW)'))。

我试着读了一下,并认为它可能与 SQLite 设置的默认(?)limits 有一些关系。另外我想知道我是否以正确的方式处理这个问题。

这是我的代码:

第 1 步:获取 ID

def get_device_ids(con_str, query, tb_name):

    local_con = lite.connect('temp.db')
    local_cur = local_con.cursor()

    local_cur.execute("DROP TABLE IF EXISTS {};".format(tb_name))
    local_cur.execute("CREATE TABLE {} (id TEXT PRIMARY KEY, \
        lang TEXT, first_date DATETIME);".format(tb_name))

    data = create_external_con(con_str, query)

    device_id_set = set()

    with local_con:
        for row in data:
            device_id_set.update([row[0]])
            local_cur.execute("INSERT INTO srv(id, lang, \
                first_date) VALUES (?,?,?);", (row))
        lid = local_cur.lastrowid
        print("Number of rows inserted into SRV: {}".format(lid))

    return device_id_set

第 2 步:使用“动态”IN() 子句生成查询

def gen_queries(ids):
    ids_list = str(', '.join("'" + id_ +"'" for id_ in ids))

    query = """
    SELECT      e.id,
                e.field2,
                e.field3
    FROM        table e
    WHERE       e.id IN ({})
    """.format(ids_list)

    return query

第 3 步:在另一个 INSERT 查询中使用该查询

这就是问题所在

def get_data(con_str, query, tb_name):

    local_con = lite.connect('temp.db')
    local_cur = local_con.cursor()

    local_cur.execute("DROP TABLE IF EXISTS {};".format(tb_name))
    local_cur.execute("CREATE TABLE {} (id TEXT, field1 INTEGER, \
        field2 TEXT, field3 TEXT, field4 INTEGER, \
        PRIMARY KEY(id, field1));".format(tb_name))

    data = create_external_con(con_str, query) # <== THIS IS WHERE THAT QUERY IS INSERTED

    device_id_set = set()

    with local_con:
        for row in data:
            device_id_set.update(row[1])
            local_cur.execute("INSERT INTO table2(id, field1, field2, field3, \
                field4) VALUES (?,?,?,?,?);", (row))
        lid = local_cur.lastrowid
        print("Number of rows inserted into table2: {}".format(lid))

非常感谢任何帮助!

编辑

This 可能是解决我的问题的正确方法,但是当我尝试使用 "SET SESSION max_allowed_packet=104857600" 时出现错误:SESSION variable 'max_allowed_packet' is read-only. Use SET GLOBAL to assign the value (1621)。然后,当我尝试将 SESSION 更改为 GLOBAL 时,我收到一条拒绝访问消息。

【问题讨论】:

  • 为什么 SQLite 会输出 MySQL 消息?您实际使用的是哪个数据库?
  • ID 似乎来自对数据库服务器的查询 (data = create_external_con(con_str, query))。这是您用于第二个查询的同一个数据库吗?那么诀窍就是根本不传输 ID,而是使用 JOINnested SQL query
  • 是的,这在技术上可以工作,但是表/模式位于不同的数据库中。因此,我需要以编程方式将所有内容连接在一起。外部连接到 MySQL 数据库

标签: python python-3.x sqlite


【解决方案1】:

将 ID 插入同一数据库中的(临时)表中,然后使用:

... WHERE e.ID IN (SELECT ID FROM TempTable)

【讨论】:

  • 这是不可能的。我无法将该表插入到与我尝试查询的数据库相同的数据库中。
猜你喜欢
  • 1970-01-01
  • 2021-05-23
  • 2014-06-14
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
  • 2011-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多