寻找下一个生日来庆祝
Find next birthdays to celebrate
我的 phoenixframework 项目中有一个用户模型,其生日属性包含 Timex.Ecto.Date 值。
defmodule MyProject.User do
use MyProject.Web, :model
schema "users" do
field :active, :boolean
field :birthday, Timex.Ecto.Date
field :login, :string
field :email, :string
field :password, :string, virtual: true
field :password_hash, :string
field :name, :string
field :nickname, :string
timestamps
end
# ... changeset and other code ...
end
现在我尝试查找所有将在从现在起的未来 30 天内庆祝生日的用户。假设有一个出生日期为 1980-02-01 的用户记录。今天是 2017-01-13。
我现在拥有的:
{:ok, date_from} =
Timex.local
|> Timex.Ecto.Date.cast
{:ok, date_to} =
Timex.local
|> Timex.add(Timex.Duration.from_days(30))
|> Timex.Ecto.Date.cast
MyProject.Repo(from(u in MyProject.User, where: u.birthday >= ^date_from, where: u.birthday <= ^date_to))
因为年份不能用。我必须如何构建 ecto 查询?
我不知道用 Ecto
明确执行此操作的任何可能性,但以下原始 SQL 应该适用于 MySQL(仅 WHERE
子句):
WHERE DAY(bd) > DAY(NOW()) AND MONTH(db) = MONTH(NOW())
OR DAY(bd) <= DAY(NOW()) AND MONTH(db) = MOD(MONTH(NOW()), 12) + 1
对于 PostgreSQL 将 DAY(XXX)
更改为 EXTRACT(DAY FROM XXX)
:
WHERE EXTRACT(DAY FROM bd) > EXTRACT(DAY FROM NOW()) ....
这些子句可以按原样用于 Ecto
个片段。
在 PostgreSQL 中,我会使用 age
来获取出生日期和现在之间的间隔,将其截断为年份,将其添加到出生日期以获得下一个生日,然后查看如果在接下来的 30 天内:
postgres=# select current_date;
date
------------
2017-01-14
(1 row)
postgres=# select '2000-01-20'::date + date_trunc('year', age('2000-01-20'::date)) + interval '1 year' <= current_date + interval '30 days';
?column?
----------
t
(1 row)
postgres=# select '2000-02-20'::date + date_trunc('year', age('2000-02-20'::date)) + interval '1 year' <= current_date + interval '30 days';
?column?
----------
f
(1 row)
对于 Ecto,这应该看起来像(未经测试):
from(u in User, where: fragment("? + date_trunc('year', age(?)) + interval '1 year' <= current_date + interval '30 days'", u.birthday, u.birthday))
现在将间隔更改为 '1 month'
也很简单,PostgreSQL 将正确地添加当月的天数,并为您提供生日在 1 个月内而不是 30 天内的用户。
我的 phoenixframework 项目中有一个用户模型,其生日属性包含 Timex.Ecto.Date 值。
defmodule MyProject.User do
use MyProject.Web, :model
schema "users" do
field :active, :boolean
field :birthday, Timex.Ecto.Date
field :login, :string
field :email, :string
field :password, :string, virtual: true
field :password_hash, :string
field :name, :string
field :nickname, :string
timestamps
end
# ... changeset and other code ...
end
现在我尝试查找所有将在从现在起的未来 30 天内庆祝生日的用户。假设有一个出生日期为 1980-02-01 的用户记录。今天是 2017-01-13。
我现在拥有的:
{:ok, date_from} =
Timex.local
|> Timex.Ecto.Date.cast
{:ok, date_to} =
Timex.local
|> Timex.add(Timex.Duration.from_days(30))
|> Timex.Ecto.Date.cast
MyProject.Repo(from(u in MyProject.User, where: u.birthday >= ^date_from, where: u.birthday <= ^date_to))
因为年份不能用。我必须如何构建 ecto 查询?
我不知道用 Ecto
明确执行此操作的任何可能性,但以下原始 SQL 应该适用于 MySQL(仅 WHERE
子句):
WHERE DAY(bd) > DAY(NOW()) AND MONTH(db) = MONTH(NOW())
OR DAY(bd) <= DAY(NOW()) AND MONTH(db) = MOD(MONTH(NOW()), 12) + 1
对于 PostgreSQL 将 DAY(XXX)
更改为 EXTRACT(DAY FROM XXX)
:
WHERE EXTRACT(DAY FROM bd) > EXTRACT(DAY FROM NOW()) ....
这些子句可以按原样用于 Ecto
个片段。
在 PostgreSQL 中,我会使用 age
来获取出生日期和现在之间的间隔,将其截断为年份,将其添加到出生日期以获得下一个生日,然后查看如果在接下来的 30 天内:
postgres=# select current_date;
date
------------
2017-01-14
(1 row)
postgres=# select '2000-01-20'::date + date_trunc('year', age('2000-01-20'::date)) + interval '1 year' <= current_date + interval '30 days';
?column?
----------
t
(1 row)
postgres=# select '2000-02-20'::date + date_trunc('year', age('2000-02-20'::date)) + interval '1 year' <= current_date + interval '30 days';
?column?
----------
f
(1 row)
对于 Ecto,这应该看起来像(未经测试):
from(u in User, where: fragment("? + date_trunc('year', age(?)) + interval '1 year' <= current_date + interval '30 days'", u.birthday, u.birthday))
现在将间隔更改为 '1 month'
也很简单,PostgreSQL 将正确地添加当月的天数,并为您提供生日在 1 个月内而不是 30 天内的用户。