寻找下一个生日庆祝

时间:2017-01-13 21:48:12

标签: postgresql elixir phoenix-framework ecto

我的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查询?

2 个答案:

答案 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天内生日的用户。