Как добавить строки, используя подзапросы в sqlalchemy? - PullRequest
1 голос
/ 16 ноября 2011

Я использую Postgresql с SQLAlchemy, но кажется, что sqlalchemy испытывает проблемы с добавлением строк при использовании подзапросов.

В моем примере я хочу обновить счетчик для определенного тега в таблице.

В SqlAlchemy класс запуска теста будет выглядеть следующим образом:

class TestRun( base ):
    __tablename__   = 'test_runs'

    id              = sqlalchemy.Column( 'id', sqlalchemy.Integer, sqlalchemy.Sequence('user_id_seq'), primary_key=True )
    tag             = sqlalchemy.Column( 'tag', sqlalchemy.String )
    counter         = sqlalchemy.Column( 'counter', sqlalchemy.Integer )

Код вставки должен выглядеть следующим образом:

tag = 'sampletag'
counterquery = session.query(sqlalchemy.func.coalesce(sqlalchemy.func.max(TestRun.counter),0) + 1).\
                            filter(TestRun.tag == tag).\
                            subquery()

testrun = TestRun()
testrun.tag = tag
testrun.counter = counterquery

session.add( testrun )
session.commit()

Проблема в том,выдает очень интересную ошибку при запуске этого кода, он пытается запустить следующий SQL-запрос:

'INSERT INTO test_runs (id, tag, counter) 
    VALUES (%(id)s, 
            %(tag)s, 
            SELECT coalesce(max(test_runs.counter), %(param_1)s) + %(coalesce_1)s AS anon_1 
               FROM test_runs 
               WHERE test_runs.tag = %(tag_1)s)' 
 {'coalesce_1': 1, 'param_1': 0, 'tag_1': 'mytag', 'tag': 'mytag', 'id': 267L}

Это выглядит разумно, за исключением того, что отсутствует скобка вокруг вызова SELECT.Когда я запускаю SQL-запрос вручную, он выдает мне ту же самую ошибку, что и sqlalchemy, пока я не введу круглые скобки вручную, что все исправит.Похоже на маловероятную ошибку, которую sqlalchemy забудет поставить в круглые скобки, когда это необходимо, поэтому мой вопрос - я пропускаю функцию для правильного использования подзапросов при добавлении строк с использованием sqlalchemy?

1 Ответ

7 голосов
/ 16 ноября 2011

Вместо использования subquery() вызов as_scalar() метод :

Возвращает полный оператор SELECT, представленный этим запросом, преобразованный в скалярный подзапрос.

Пример:

Модели с классификацией родительско-дочерних отношений:

class Parent(Base):
    __tablename__ = 'parents'
    id = Column(Integer, primary_key=True)
    counter = Column(Integer, nullable=False, default=0)

class Child(Base):
    __tablename__ = 'children'
    id = Column(Integer, primary_key=True)
    parent_id = Column(ForeignKey(Parent.id), nullable=False)
    parent = relationship(Parent)

Код для обновления counter поле:

parent.counter = session.query(func.count(Child.id))\
                    .filter_by(parent=parent).as_scalar()

Произведенный SQL (скопированный из журнала):

UPDATE parents SET counter=(SELECT count(children.id) AS count_1 
FROM children
WHERE ? = children.parent_id) WHERE parents.id = ?
...