我使用 Postgres 数据库。该数据库有一个包含用户的表,用户有生日(日期字段)。现在我想让所有在下周过生日的用户....
我的第一次尝试:SELECT id FROM public.users WHERE id IN (lange reeks) AND birthdate > NOW() AND birthdate < NOW() + interval '1 week'
但这并没有结果,显然是因为过年了。我该如何解决这个问题?
有谁知道 PG 在 29-02 岁生日时会发生什么情况?
最佳答案
我们可以使用一个 postgres 函数以一种非常好的方式来做到这一点。
假设我们有一个表people
,dob
列中有出生日期,这是一个日期,我们可以创建一个函数来索引此列忽略年份。 (感谢 Zoltán Böszörményi ):
CREATE OR REPLACE FUNCTION indexable_month_day(date) RETURNS TEXT as $BODY$
SELECT to_char($1, 'MM-DD');
$BODY$ language 'sql' IMMUTABLE STRICT;
CREATE INDEX person_birthday_idx ON people (indexable_month_day(dob));
现在,我们需要查询表和索引。例如,获取任何一年四月生日的所有人:
SELECT * FROM people
WHERE
indexable_month_day(dob) >= '04-01'
AND
indexable_month_day(dob) < '05-01';
有一个陷阱:如果我们的开始/结束时间跨过一年边界,我们需要更改查询:
SELECT * FROM people
WHERE
indexable_month_day(dob) >= '12-29'
OR
indexable_month_day(dob) < '01-04';
为了确保我们匹配闰日生日,我们需要知道我们是将它们向前或向后“移动”一天。在我的例子中,只匹配这两天更简单,所以我的一般查询如下:
SELECT * FROM people
WHERE
indexable_month_day(dob) > '%(start)%'
%(AND|OR)%
indexable_month_day(dob) < '%(finish)%';
我有一个 Django 查询集方法,它使这一切变得更加简单:
def birthday_between(self, start, finish):
"""Return the members of this queryset whose birthdays
lie on or between start and finish."""
start = start - datetime.timedelta(1)
finish = finish + datetime.timedelta(1)
return self.extra(where=["indexable_month_day(dob) < '%(finish)s' %(andor)s indexable_month_day(dob) > %(start)s" % {
'start': start.strftime('%m-%d'),
'finish': finish.strftime('%m-%d'),
'andor': 'and if start.year == finish.year else 'or'
}]
def birthday_on(self, date):
return self.birthday_between(date, date)
现在,我可以做如下事情:
Person.objects.birthday_on(datetime.date.today())
只在前一天匹配闰日生日,或者只在后一天匹配:你只需要将 SQL 测试更改为 `>=' 或 '<=',而不调整开始/结束在 python 函数中。
关于postgresql - Postgres 生日选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6913719/