SQLAlchemy: групповые запросы Результаты из двух столбцов по взаимному внешнему ключу - PullRequest
1 голос
/ 24 февраля 2020

Что я пытаюсь сделать:

У меня есть 3 таблицы в Postgres БД.

user
-----------------------
user_id   name      age  
-----------------------
001       Alice     25
002       Bob       32
003       Colin     31
004       Danny     40
laundry_task
-----------------------------
task_id   user_id   completed  
-----------------------------
101       001       true
102       003       false
103       001       true
cooking_task
-----------------------------
task_id   user_id   completed  
-----------------------------
201       001       true
202       002       true
203       003       false

Мне нужна SQLAlchemy, чтобы вернуть меня список кортежей, такой что:
[(001, 2, 1), (002, 0, 1)]
, где кортежи состоят из:
0) user_id
1) number_of_times_laundry_task_completed
2 ) number_of_times_cooking_task_completed

ИЛИ
[(001, 3), (002, 1)]
, где кортежи состоят из:
0) user_id
1) sum_of_times_boths_tasks_completed

Мне нужно это в одном запросе. (подзапросы в порядке)

Если в 1 из таблиц не назначены задачи , completed count должен быть установлен в 0. Если в обеих таблицах нет назначенных задач, кортеж должен либо выглядеть как (004, 0, 0) (или (004, 0)), либо вообще отсутствовать в списке.

Как это выглядит в 2 запросах:

laundry_tasks = (
    session.query(LaundryTask.user_id, func.count(LaundryTask.completed))
           .filter(LaundryTask.completed == True)
           .group_by(LaundryTask.user_id)
           .all()
) # Results in [(001, 2)]


cooking_tasks = (
    session.query(CookingTask.user_id, func.count(CookingTask.completed))
           .filter(CookingTask.completed == True)
           .group_by(CookingTask.user_id)
           .all()
) # Results in [(001, 1), (002, 1)]

# Add some Python parsing to merge two lists of tuples into the needed format...

То, что я пробовал и вроде работало (но не совсем):

Подзапросы:

laundry_tasks_query = (
    select([LaundryTask.user_id, func.count(LaundryTask.completed)])
    .where(LaundryTask.completed == True)
    .group_by(LaundryTask.user_id)
)

cooking_tasks_query = (
    select([CookingTask.user_id, func.count(CookingTask.completed)])
    .where(CookingTask.completed == True)
    .group_by(CookingTask.user_id)
)

final_query = laundry_tasks_query.union(cooking_tasks_query).alias('completed_tasks')
completed_tasks = session.query(final_query).all()

Результат: completed_tasks = [(001, 2), (001, 1), (002, 1)]
Не уверен, есть ли способ до group_by на union до выполнения запроса, все мои попытки закончились Exception с.

То, что я пробовал и не работало:

Сложить все в один запрос.

completed_tasks = (
    session.query(
         User.user_id, func.count(LaundryTask.completed), func.count(CookingTask.completed)
    )
    .filter(LaundryTask.completed == True)
    .filter(CookingTask.completed == True)
    .group_by(User.user_id)
    .all()
)

Я знаю, наивно и, как и ожидалось, возвращает какую-то ерунду, ака [(001, magic_number, magic_number), (002, magic_number, magic_number), (003, magic_number, magic_number), (004, magic_number, magic_number)], где magic_number - это то же целое число.

Если есть какие-либо другие способы получения нужного мне результата, я более чем открыт для предложений. Любая помощь приветствуется.

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