我有以下查询,我需要实现一个Mailer,它需要发送给今天生日的所有客户。这种情况每天都会发生。现在,我需要实现的只是使用PostgresSQL查询来选择Birthday客户端,而不是用PHP过滤它们。
数据库中存储的日期格式为YYYY-MM-DD,例如1984-03-13
我有以下查询
SELECT cd.firstname,
cd.surname,
SUBSTRING(cd.birthdate,6),
cd.email
FROM client_contacts AS cd
JOIN clients AS c ON c.id = cd.client_id
WHERE SUBSTRING(birthdate,6) = '07-20';
有没有比我上面做的更好的方法来做这个查询?
您可以将where子句设置为:
WHERE
DATE_PART('day', birthdate) = date_part('day', CURRENT_DATE)
AND
DATE_PART('month', birthdate) = date_part('month', CURRENT_DATE)
如果重要的话,年龄函数会让你解决闰年的问题:
where age(cd.birthdate) - (extract(year from age(cd.birthdate)) || ' years')::interval = '0'::interval
如果你想要性能,你实际上也可以用一个任意的起点(例如'epoch'::date
(将上面的内容包装成一个函数,并在上面使用一个索引:
create or replace function day_of_birth(date)
returns interval
as $$
select age($1, 'epoch'::date)
- (extract(year from age($1, 'epoch'::date)) || ' years')::interval;
$$ language sql immutable strict;
create index on client_contacts(day_of_birth(birthdate));
...
where day_of_birth(cd.birthdate) = day_of_birth(current_date);
(请注意,从技术上讲,它不是不可变的,因为日期取决于时区。但创建索引需要不可变的部分,如果你不到处更改时区,这是安全的。(
编辑:我刚刚测试了一下以上内容,实际上索引建议在2月29日不起作用。2月29日的出生日为1月28日,虽然正确,但需要将其添加到1月1日,才能获得当年的有效出生日期。
create or replace function birthdate(date)
returns date
as $$
select (date_trunc('year', now()::date)
+ age($1, 'epoch'::date)
- (extract(year from age($1, 'epoch'::date)) || ' years')::interval
)::date;
$$ language sql stable strict;
with dates as (
select d
from unnest('{
2004-02-28,2004-02-29,2004-03-01,
2005-02-28,2005-03-01
}'::date[]) d
)
select d,
day_of_birth(d),
birthdate(d)
from dates;
d | day_of_birth | birthdate
------------+---------------+------------
2004-02-28 | 1 mon 27 days | 2011-02-28
2004-02-29 | 1 mon 28 days | 2011-03-01
2004-03-01 | 2 mons | 2011-03-01
2005-02-28 | 1 mon 27 days | 2011-02-28
2005-03-01 | 2 mons | 2011-03-01
(5 rows)
因此:
where birthdate(cd.birthdate) = current_date
@Jordan的答案是正确的,但如果日期格式是字符串,它就不起作用。如果它是字符串,您可以使用to_date函数对其进行类型转换。然后应用datepart函数。
如果出生日期(DOB(是1982年4月20日,则查询为:
SELECT * FROM public."studentData" where date_part('day',TO_DATE("DOB", 'DD/MM/YYYY'))='20'
AND date_part('month',TO_DATE("DOB", 'DD/MM/YYYY'))='04';
或
EXTRACT(MONTH FROM TO_DATE("DOB", 'DD/MM/YYYY'))='04' AND EXTRACT(DAY FROM TO_DATE("DOB", 'DD/MM/YYYY'))='20'
我在表名("studentData"(和字段名("DOB"(上加了双引号,因为它是字符串。
归功于@Jordan
WHERE date_part('month', cd.birthdate) = '07' AND date_part('day', cd.birthdate) = '20'
你可以在这里阅读更多关于的信息
WHERE 0 = extract(DAY FROM age(dob)) + extract (MONTH FROM age(dob))
尝试使用以下内容:
WHERE EXTRACT(DOY FROM TIMESTAMP cd.birthdate) = EXTRACT(DOY FROM TIMESTAMP CURRENT_TIMESTAMP)
IMO的最佳方法是使用to_char(birthday, 'MM-DD') in (?)
,只需将一些日期范围映射到'MM-DD'
,而不是?
。除非你必须支持非常大的日期范围,否则这个解决方案非常简单、干净、防bug。
您要做的是,使用SQL手动提取希望的人员详细信息,然后手动单独发送愿望。如果我建议你一个更好的方法呢?
将愿望细节提取为excel,让许愿应用程序处理一切。
至少它只需要两件东西excel文件,其中包含愿望详细信息(日期、姓名、电子邮件(和一个配置文件(application.properties(,就可以了。
此外,还有各种在本地运行应用程序的选项(命令行、前台、后台、docker、windows调度器、unix cron等(Cloud。
应用程序是高度可配置的,您可以配置各种细节,如:
- 工作簿加载选项
- 可随愿望发送的图像选项
- SMTP配置
-
其他应用程序级配置,如何时发送愿望、迟来的愿望、日志记录等。
免责声明:我是应用程序的所有者