псевдоним, присоединенный к sqlalchemy, не имеет столбцов из обеих таблиц

Все, что мне нужно, это счет из таблицы 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, и мне трудно учиться. (ссылки на рекомендуемые образовательные ресурсы приветствуются!)


person Paul    schedule 29.09.2011    source источник
comment
FIRST() не является стандартной функцией sql, к какой СУБД вы подключаетесь?   -  person SingleNegationElimination    schedule 29.09.2011
comment
@TokenMacGuy Хорошо. Ну, мой вопрос применим, если вы замените «первый» на «макс», но нет причин сравнивать все значения, которые должны быть одинаковыми. Я использую движок mySQL.   -  person Paul    schedule 29.09.2011


Ответы (1)


Когда вы делаете подзапрос из оператора 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] по умолчанию равен нулю, если в противном случае не заполнено.

person zzzeek    schedule 29.09.2011
comment
Поскольку first не работает, можете ли вы придумать недорогой/идиоматический способ получить сгруппированное значение? Это тесно связано с этим вопросом: stackoverflow.com/questions/7585892/ (я буду рад задать еще один вопрос, если вы считаете, что это оправдано) - person Paul; 30.09.2011
comment
этот другой вопрос довольно неудобен тем, что вы хотите 0 для значений, которых не существует. Если бы вы могли просто получать строки из БД, заполнять их структурой и просто устанавливать 0 для тех, которых нет в результирующем наборе, это было бы намного менее неловко. В противном случае, чтобы получить его прямо как SQL, вам нужно создать искусственный список A, B, C и т. д., поэтому эти UNION существуют. - person zzzeek; 30.09.2011
comment
Я готов отказаться от запроса на возврат 0, если я могу получить его как чистый синтаксис SA ORM. - person Paul; 30.09.2011