Mik*_*ike 5 postgresql intervals date-of-birth
我使用Postgres数据库.此DB具有一个包含用户的表,该用户具有生日(日期字段).现在我想让所有在即将到来的一周里过生日的用户....
我的第一次尝试: 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ánBö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));
Run Code Online (Sandbox Code Playgroud)
现在,我们需要查询表和索引.例如,要让每个人在任何一年的4月份过生日:
SELECT * FROM people
WHERE
indexable_month_day(dob) >= '04-01'
AND
indexable_month_day(dob) < '05-01';
Run Code Online (Sandbox Code Playgroud)
有一个问题:如果我们的开始/结束时段超过一年的边界,我们需要更改查询:
SELECT * FROM people
WHERE
indexable_month_day(dob) >= '12-29'
OR
indexable_month_day(dob) < '01-04';
Run Code Online (Sandbox Code Playgroud)
为了确保我们匹配闰日生日,我们需要知道我们是否会向前或向后"移动"它们.就我而言,两天都匹配起来比较简单,所以我的一般查询看起来像:
SELECT * FROM people
WHERE
indexable_month_day(dob) > '%(start)%'
%(AND|OR)%
indexable_month_day(dob) < '%(finish)%';
Run Code Online (Sandbox Code Playgroud)
我有一个django queryset方法,使这更简单:
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)
Run Code Online (Sandbox Code Playgroud)
现在,我可以做以下事情:
Person.objects.birthday_on(datetime.date.today())
Run Code Online (Sandbox Code Playgroud)
仅在前一天或仅在后一天匹配闰日生日也是可能的:您只需要将SQL测试更改为"> ="或"<=",而不是调整python中的开始/结束功能.
我对此并不太有信心,但它似乎在我的测试中起作用。这里的关键是OVERLAPS运算符和一些日期算术。
我假设你有一张桌子:
create temporary table birthdays (name varchar, bday date);
Run Code Online (Sandbox Code Playgroud)
然后我往里面放了一些东西:
insert into birthdays (name, bday) values
('Aug 24', '1981-08-24'), ('Aug 04', '1982-08-04'), ('Oct 10', '1980-10-10');
Run Code Online (Sandbox Code Playgroud)
这个查询将为我提供下周生日的人:
select * from
(select *, bday + date_trunc('year', age(bday)) + interval '1 year' as anniversary from birthdays) bd
where
(current_date, current_date + interval '1 week') overlaps (anniversary, anniversary)
Run Code Online (Sandbox Code Playgroud)
它date_trunc会截断年份中的日期,因此它应该可以让您了解当前年份。我最终不得不增加一年。这对我来说表明我出于某种原因有一个一对一的情况。也许我只需要找到一种方法来对日期进行四舍五入。无论如何,还有其他方法可以进行此计算。age给出从日期或时间戳到今天的间隔。我正在尝试添加生日和今天之间的年份以获得当年的日期。
真正的关键是用来overlaps查找日期重叠的记录。我使用周年纪念日两次来获取时间点。
| 归档时间: |
|
| 查看次数: |
5598 次 |
| 最近记录: |