Все, что мне нужно, это счет из таблицы A, сгруппированный по столбцу из таблицы B, но, конечно, мне нужен элемент из таблицы B, с которым связан каждый счетчик. Лучше объяснить кодом:
TableA и B являются объектами модели.
Я стараюсь следовать этому синтаксису, насколько это возможно. могу.
Пытаюсь запустить этот запрос:
sq = session.query(TableA).join(TableB).\
group_by(TableB.attrB).subquery()
countA = func.count(sq.c.attrA)
groupB = func.first(sq.c.attrB)
print session.query(countA, groupB).all()
Но это дает мне AttributeError (sq не имеет attrB)
Я новичок в SA, и мне трудно учиться. (ссылки на рекомендуемые образовательные ресурсы приветствуются!)
Ответ 1 · рейтинг 3 · zzzeek
Когда вы делаете подзапрос из оператора select, столбцы, к которым можно получить доступ из него, должны быть в предложении columns. Возьмем, к примеру, такое утверждение:
select x, y from mytable where z=5
Если бы мы хотели сделать подзапрос, то GROUP BY 'z', это было бы недопустимым SQL:
select * from (select x, y from mytable where z=5) as mysubquery group by mysubquery.z
Потому что "z" не находится в предложении столбцов "mysubquery" (это также незаконно, поскольку "x" и "y" также должны быть в GROUP BY, но это другой вопрос).
SQLAlchemy работает точно так же. Когда вы говорите query(..).subquery() или используете функцию alias() в основной выбираемой конструкции, это означает, что вы заключаете свой оператор SELECT в круглые скобки, давая ему (обычно сгенерированное) имя и давая ему новый .с. коллекция, в которой есть только те столбцы, которые находятся в предложении "columns", как в реальном SQL.
Итак, здесь вам нужно убедиться, что TableB, по крайней мере, столбец, с которым вы имеете дело извне, доступен. Вы также можете ограничить предложение columns только теми столбцами, которые вам нужны:
sq = session.query(TableA.attrA, TableB.attrB).join(TableB).\
group_by(TableB.attrB).subquery()
countA = func.count(sq.c.attrA)
groupB = func.first(sq.c.attrB)
print session.query(countA, groupB).all()
Обратите внимание, что приведенный выше запрос, вероятно, работает только в MySQL, так как в общем SQL недопустимо ссылаться на любые столбцы, которые не являются частью агрегатной функции или частью GROUP BY, когда используется группировка. У MySQL в этом отношении более расслабленная (и неаккуратная) система.
edit: если вы хотите получить результаты без нулей:
import collections
letter_count = collections.defaultdict(int)
for count, letter in session.query(func.count(MyClass.id), MyClass.attr).group_by(MyClass.attr):
letter_count[letter] = count
for letter in ["A", "B", "C", "D", "E", ...]:
print "Letter %s has %d elements" % letter_count[letter]
обратите внимание, что letter_count[someletter] по умолчанию равен нулю, если в противном случае не заполнено.