SA: можно ли указать столбец 'year' для столбца Date? - PullRequest
2 голосов
/ 05 апреля 2011

У меня есть класс со столбцом Date в sqlalchemy-0.7. Могу ли я иметь column_property или что-то подобное, что даст мне год и позволит мне легко фильтровать по нему? Как бы я это написал?

IE, я хотел бы иметь (декларативный синтаксис):

class Foo(Base):
    id   = Column(Integer, primary_key=True)
    date = Column(Date(), nullable=False)
    year = column_property(something here)

# later on
q = session().query(Foo).filter_by(year=2011)

1 Ответ

5 голосов
/ 05 апреля 2011

Конечно, вы можете определить такое свойство:

year = column_property(extract('year', date))

Но тебе это действительно нужно? Вы можете фильтровать по году без такого свойства, определенного переписав условие фильтра:

query(Foo).filter(extract('year', Foo.date)==2011)

Обновление

Хотя это решение выглядит простым, оно также имеет недостаток: такое условие в предложении WHERE никогда не будет использовать поле индекса на дату. Имея много рядов и высокую селективность условий, это сильно повлияет на производительность. Таким образом, вы можете переписать условие, которое вызовет RANGE INDEX SCAN вместо FULL TABLE SCAN (как предложено в комментарии Саймона):

start = datetime.date(year, 1, 1)
end = datetime.date(year, 12, 31)
query(Foo).filter(Foo.date.between(start, end))

Определение свойства с таким поведением также возможно, вам просто нужно переопределить компаратор:

class YearComparator(ColumnProperty.Comparator):
    def __eq__(self, year):
        if isinstance(year, int):
            column = self.prop.columns[0].get_children()[0].expr
            start = datetime.date(year, 1, 1)
            end = datetime.date(year, 12, 31)
            return column.between(start, end)
        else:
            # It can be a column or exression which we can't handle such way
            return ColumnProperty.Comparator.__eq__(self, year)
    # __lt__, __gt__ etc. are very similar to __eq__

def year_property(date_column, **kwargs):
    kwargs.setdefault('comparator_factory', YearComparator)
    return column_property(extract('year', date_column), **kwargs)

class Foo(Base):
    __tablename__ = 'Foo'
    id = Column(Integer, primary_key=True)
    date = Column(Date, index=True)
    year = year_property(date)
...