sqlite3 отличается в консоли от сценария Python - PullRequest
0 голосов
/ 24 апреля 2020

Ниже приведен фиктивный пример, демонстрирующий отличие результатов запроса, реальный запрос является более сложным, поэтому в этом примере структура запроса может показаться излишней. Установите соединение с базой данных 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.

У меня есть этот запрос сейчас:

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

1 Ответ

1 голос
/ 24 апреля 2020

Я создал тестовую базу данных, используя ваш первый скрипт, а затем открыл ее в оболочке sqlite3. Ваш запрос возвращает 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...