Использование вывода функции в предложении SQLAlchemy join - PullRequest
0 голосов
/ 04 ноября 2018

Я пытаюсь перевести довольно короткий фрагмент SQL в запрос sqlAlchemy ORM. SQL использует Postgres generate_series для создания набора дат, и моя цель - создать набор массивов временных рядов, распределенных по одному из столбцов.

Таблицы (упрощенные) очень просты:

counts:
-----------------
count   (Integer)
day     (Date)
placeID (foreign key related to places)

"counts_pkey" PRIMARY KEY (day, placeID)

places:
-----------------
id
name   (varchar)

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

    array_agg    |    name
-----------------+-------------------
 {NULL,0,7,NULL} | A Place
 {NULL,1,NULL,2} | Some other place
 {5,NULL,3,NULL} | Yet another

Я могу сделать это довольно легко, взяв CROSS JOIN в диапазоне дат и мест и соединив его с количеством:

SELECT array_agg(counts.count), places.name 
FROM generate_series('2018-11-01', '2018-11-04', interval '1 days') as day 
CROSS JOIN  places 
LEFT OUTER JOIN counts on counts.day = day.day AND counts.PlaceID = places.id 
GROUP BY places.name;

Что я не могу понять, так это как заставить SQLAlchemy сделать это. После долгих поисков я обнаружил старую ветку групп Google , которая почти работает, что приводит к этому:

date_list = select([column('generate_series')])\
.select_from(func.generate_series(backthen, today, '1 day'))\ 
.alias('date_list')

time_series = db.session.query(Place.name, func.array_agg(Count.count))\
.select_from(date_list)\
.outerjoin(Count, (Count.day == date_list.c.generate_series) & (Count.placeID == Place.id ))\
.group_by(Place.name)

Это создает дополнительный выбор для временного ряда, но выдает ошибку базы данных:

Существует запись для таблицы "place", но на нее нельзя ссылаться из этой части запроса.

Итак, мой вопрос: как бы вы сделали это в sqlalchemy. Кроме того, я открыт для идеи, что это сложно, потому что мой подход с SQL является хладнокровным.

1 Ответ

0 голосов
/ 04 ноября 2018

Проблема заключается в том, что, учитывая конструкцию запроса, SQLAlchemy создает запрос в соответствии с

SELECT ...
FROM places,
     (...) AS date_list LEFT OUTER JOIN count ON ... AND count."placeID" = places.id
...

Есть 2 FROM списка: places и объединение. Элементы не могут перекрестно ссылаться друг на друга 1 , и, следовательно, ошибка из-за places.id в ON -пункте.

SQLAlchemy не поддерживает явный CROSS JOIN, но, с другой стороны, CROSS JOIN эквивалентен INNER JOIN ON (TRUE). Вы также можете отказаться от переноса выражения функции в подзапрос и использовать его как есть, присвоив ему псевдоним :

date_list = func.generate_series(backthen, today, '1 day').alias('gen_day')

time_series = session.query(Place.name, func.array_agg(Count.count))\
    .join(date_list, true())\
    .outerjoin(Count, (Count.day == column('gen_day')) &
                      (Count.placeID == Place.id ))\
    .group_by(Place.name)

1 : За исключением вызова функции FROM -элементов или использования LATERAL.

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