我的phoenixframework项目中有一个用户模型,其中包含一个包含Timex.Ecto.Date值的birthday属性。
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年1月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查询?
答案 0 :(得分:2)
我不知道有可能使用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
个片段。
答案 1 :(得分:2)
在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天内生日的用户。