Найти - Пользователи
Полная версия: Запрос к базе данных (поиск по дате)
Начало » Python для новичков » Запрос к базе данных (поиск по дате)
1 2 3
romario82
Всем здравствуйте.

Есть база данных контактов с датами рождения.
Нужно получить из БД людей у которых день рождение в ближайшие 7 дней.
Формат даты в БД - год-месяц-день.
Так я получаю дельту в 7 дней.
 today = date.today()
delta = today + timedelta(days=7)
Но год у всех контактов разный.
Как реализовать запрос к БД и делать выборку контактов по дельте (today, delta) не учитывая год, а только месяц и день?
Использую sqlalchemy.
py.user.next
Для каждой записи бери месяц и день, добавляй туда текущий год и потом с этой датой проделывай вычисления на попадание в срок.

Код просто выложи, где ты там не можешь добавить этот фильтр.
ZerG
и структуру бд - тоже неплохо было бы показать
romario82
Модель простая
 class DBContact(Base):
    __tablename__ = 'contacts'
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, nullable=False, index=True)
    surname = Column(String, nullable=False, index=True)
    email = Column(String, nullable=False, index=True)
    phone = Column(String, nullable=False, index=True)
    birthday = Column(String, nullable=False, index=True)
    text = Column(String, nullable=True, index=True)

Я сделал так
 current_date = datetime.now().date()
target_date = current_date + timedelta(days=7)
birthdays = session.query(DBContact).filter(
    (extract('month', DBContact.birthday) == current_date.month) &
    (extract('day', DBContact.birthday) >= current_date.day) &
    (extract('day', DBContact.birthday) <= target_date.day)
).all()
Вроде работает, но не знаю как будет вести себя на стыке месяцев.
И тут есть кто на fastapi собаку съел??? Есть вопрос.
Rodegast
 birthday = Column(String, nullable=False, index=True)


Вот как я получал бы клиентов на postgres-е, но только это тебе не поможет…
 SELECT
	id, "name", surname, email, phone, birthday, "text"
FROM
	contacts
WHERE
	numrange(
		  (SELECT EXTRACT(DOY FROM CURRENT_DATE))
		, (SELECT EXTRACT(DOY FROM CURRENT_DATE))+7
	) @> EXTRACT(DOY FROM TIMESTAMP birthday)
py.user.next
romario82
Я сделал так
  
current_date = datetime.now().date()
target_date = current_date + timedelta(days=7)
birthdays = session.query(DBContact).filter(
    (extract('month', DBContact.birthday) == current_date.month) &
    (extract('day', DBContact.birthday) >= current_date.day) &
    (extract('day', DBContact.birthday) <= target_date.day)
).all()
Когда выделил через extract() день и месяц, подай эти значения в новую дату, формируемую через модуль datetime, с сегодняшним годом. Когда она будет сформирована, тогда ты её сравнишь с target_date через операцию сравнения больше меньше.

Вот тебе пример
  
import datetime
 
def compare_dates(date1, date2):
    if date1 < date2:
        return -1
    elif date1 == date2:
        return 0
    else:
        return 1
 
def create_date(day, month):
    out = datetime.datetime(datetime.datetime.now().year, month, day)
    return out
 
current_date = datetime.datetime.now().date()
target_date = current_date + datetime.timedelta(days=7)
birthdays = session.query(DBContact).filter(
    compare_dates(
        create_date(
            extract('day', DBContact.birthday),
            extract('month', DBContact.birthday)
        ),
        target_date
    ) <= 0
).all()
Обрати внимание, как там что импортируется в нём.

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

Прочитай import this, там последней строкой указано как раз про это
  
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>>
Rodegast
> Вот тебе пример

Ой.. а не проще просто циклом данные из таблицы выбирать и их с датой сравнивать?
py.user.next
Rodegast
Ой.. а не проще просто циклом данные из таблицы выбирать и их с датой сравнивать?
Если там миллион данных, надо их фильтрануть сначала средствами СУБД, потому что в СУБД это всё оптимизированно, все эти операции. Для этого мы и делаем этот фильтр. А так-то он нафиг не нужен.

Что касается того, нужно ли это в СУБД делать всё, то я тебе так скажу. Вот ты заострился на PostgreSQL, типа там прикольно можно всё сделать и так далее, но вот завтра поступит команда “перевести это с PostgreSQL на MySQL или там MSSQL”, вот ты что делать будешь? переписывать сотни этих выборок с одного SQL-диалекта на другой или всё-таки ты используешь такую вот ORM типа Алхимии, которая автоматически это всё переведёт в правильные инструкции просто через одну замену драйвера где-то там в настройках?

Во-первых, вся эта фигня не относится к базе данных. То есть база данных должна просто информацию хранить (непротиворечиво, целостно, оптимально и так далее). А все вот эти анализы должны выполняться снаружи базы данных.
Во-вторых, из SQL-кода ты столько не выжмешь, сколько из питон-кода. Максимум, который там достигли в этих реляционных СУБД, - это хранимые процедуры, которые считаются чуть ли не чудом света каким-то, в то время как по сути они являются просто процедурами в какой-то там древней парадигме, которая особо ничего не даёт.
Rodegast
> Для этого мы и делаем этот фильтр. А так-то он нафиг не нужен.

Это всё верно, но только твой пример как раз в лучшем случаи упадёт, а в худшем будет по одной записи доставать и фильтровать через compare_dates.
py.user.next
Rodegast
Это всё верно, но только твой пример как раз в лучшем случаи упадёт, а в худшем будет по одной записи доставать и фильтровать через compare_dates.
Зато он не будет внутрь базы заносить логику, которая там быть не должно. А падает он или нет, это надо смотреть сначала. Преждевременной оптимизацией в его коде я бы не стал заниматься, судя по тому, что он делает. Сначала надо посмотреть; может, оно просто так работать будет. Если же оптимизировать, то далеко не факт, что большая часть его кода сохранится вообще. Там вообще, может, другой подход нужен изначально.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB