下面是一个虚例来演示查询结果的不同,真实的查询比较复杂,所以在这个例子中,查询结构可能会显得矫枉过正。建立一个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条记录。我想统计两者之间ID和日期相同的记录,当日期为 202004
.
我现在有这个查询。
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`
这和预期一样,返回 2
当在 sqlite 控制台中运行时。
但在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
我使用你的第一个脚本创建了一个测试数据库,然后在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为2023003的记录会被包含在内 我想它们应该被子查询的过滤掉了 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个数。