【问题标题】:sqlite3 different result in console compared to Python script与 Python 脚本相比,sqlite3 在控制台中的结果不同
【发布时间】:2020-04-24 00:45:32
【问题描述】:

下面是一个虚拟示例,用于演示查询结果有何不同,实际查询更为复杂,因此在此示例中查询结构可能显得过于矫枉过正。建立与 sqlite3 数据库的连接并添加这些记录以开始:

import sqlite3

connection = sqlite3.connect(
    'file:test_database',
    detect_types=sqlite3.PARSE_DECLTYPES,
    isolation_level=None,
    check_same_thread=False,
    uri=True
)

cursor = connection.cursor()

tableA_records = [(1, 202003), (2, 202003), (3, 202003), (4, 202004), (5, 202004), (6, 202004), (7, 202004), (8, 202004), ]
tableB_records = [(1, 202004), (2, 202004), (3, 202004), (4, 202004), (5, 202004),]

tableA_ddl = """
    create table tableA
    (
        ID           int,
        RunYearMonth int
    );
"""

tableB_ddl = """
    create table tableB
    (
        ID           int,
        RunYearMonth int
    );
"""

cursor.execute(tableA_ddl)
cursor.execute(tableB_ddl)

cursor.executemany("INSERT INTO tableA VALUES (?, ?)", tableA_records)
cursor.executemany("INSERT INTO tableB VALUES (?, ?)", tableB_records)

现在我们有两个表(A 和 B),分别有 8 条和 5 条记录。当日期为202004时,我想计算两者之间具有相同ID和日期的记录。

我现在有这个问题:

SELECT COUNT(*)
    FROM (
        SELECT *
        FROM `tableA`
        WHERE `RunYearMonth` = 202004
    ) AS `A`
    INNER JOIN (
        SELECT *
        FROM `tableB`
        WHERE `RunYearMonth` = 202004
    ) AS `B`
      ON `A`.`ID` = `B`.`ID`
      AND `A`.`RunYearMonth` = `B`.`RunYearMonth`

正如预期的那样,在 sqlite 控制台中运行时返回 2

但是,在 Python 中运行时,您会得到不同的结果。

q = """
SELECT COUNT(*)
    FROM (
        SELECT *
        FROM `tableA`
        WHERE `RunYearMonth` = 202004
    ) AS `map1`
    INNER JOIN (
        SELECT *
        FROM `tableB`
        WHERE `RunYearMonth` = 202004
    ) AS `map2`
      ON `map1`.`ID` = `map2`.`ID`
      AND `map1`.`RunYearMonth` = `map2`.`RunYearMonth`
"""
cursor.execute(q)
print(cursor.fetchall())

这将返回 5,它实际上忽略了子查询中的 WHERE 子句和它们具有相同 RunYearMonth 的连接条件,两者都有记录 1-5。

什么会导致这种差异? Python不是简单的把查询字符串传过去吗?

相关版本:

sqlite3.version == 2.6.0
sqlite3.sqlite_version == 3.31.1
sys.version == 3.6.5

【问题讨论】:

  • 我得到 2 用于在 Python 中运行的查询。我的 SQLite 版本是 3.22.0,我的 Python 版本是 3.8.0
  • @mechanical_meat 3.31引入了相关bug。

标签: sql python-3.x sqlite


【解决方案1】:

我使用您的第一个脚本创建了一个测试数据库,然后在 sqlite3 shell 中打开它。您的查询在其中返回 5,而不是您得到的 2。将其更改为显示所有行后,而不仅仅是计数,结果如下:

ID          RunYearMonth  ID          RunYearMonth
----------  ------------  ----------  ------------
1           202003        1           202004
2           202003        2           202004
3           202003        3           202004
4           202004        4           202004
5           202004        5           202004

我不确定为什么要包含表 A 中 RunYearMonth 为 202003 的那些行;我认为它们会被子查询的WHERE 过滤掉。

这似乎是 Sqlite3 中的一个错误 - 使用旧版本 (3.11.0) 会产生预期的结果,对查询进行轻微调整以删除 AND map1.RunYearMonth = map2.RunYearMonth 会在 3.31.1 上产生正确的结果。


无论如何,该查询可以被大量清理,如下所示:

SELECT count(*)
FROM tableA AS A
JOIN tableB AS B ON A.ID = B.ID
                AND A.RunYearMonth = B.RunYearMonth
WHERE A.RunYearMonth = 202004;

它确实返回了 2 的预期计数。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-07
  • 2018-09-19
  • 2021-05-27
  • 2021-07-26
  • 2021-05-25
相关资源
最近更新 更多