按日期获取记录是30天的倍数

Getting records by date is multiples of 30 days

我有以下查询来获取需要每月提醒一次的约会(如果尚未完成)。 我想获取从当前日期到过去的 30、60、90、120 等...的记录。

SELECT
    a.*
FROM
    appointments a
WHERE
    DATEDIFF(CURDATE(), a.appointment_date) % 30 = 0

是否有另一种不使用 DATEDIFF 来实现此目的的方法?我想提高此查询的性能。

您可以使用以下查询,将约会的日期与今天的日期进行比较。
我们还测试我们是否是该月的最后一天,以便在月底到期的约会。例如,如果我们是 2 月 28 日(不是闰年),我们将接受一个月中的第几天 >= 28,即 29、30 和 31,否则会被遗漏。
这个方法和你现在的系统有同样的问题,周末的约会会错过。

select a.*
from appointements a,
(select 
  day(now()) today,
  case when day(now())= last_day(now()) then day(now()) else 99 end lastDay
) days
where d = today or d >= lastDay;

您只想要未来 30 天的约会?它们存储为 DATE 吗?还是DATETIME?好吧,这在任何一种情况下都有效:

SELECT ...
    WHERE appt_date >= CURDATE() + INTERVAL 30 DAY
      AND appt_date  < CURDATE() + INTERVAL 31 DAY

如果您有 INDEX(appt_date)(或任何以 appt_date 开头的索引 ),查询将是高效的。

DATE() 这样的东西不是“可搜索的”,并且阻止使用索引。

如果您的目标是唠叨客户,我在您的查询中看不到任何内容来防止一遍又一遍地唠叨每个人。这可能需要一个单独的“nag”table,其中可以删除满足该 nag 的客户。那么性能就不会成为问题,因为 table 会很小。

如果您最关心的是加快此查询的速度,我们可以添加一个 int 列来比较天数并为其建立索引。然后我们添加触发器来计算 Unix 时期开始之间的 datediff 的模数:01/01/1970(或任何其他日期,如果您愿意)并将结果存储在此列中。
这将占用少量存储空间 space,并减慢插入和更新操作的速度。当我们一次添加或修改一个约会时,这不会被注意到,我怀疑这是一般情况。
当我们查询我们的 table 时,我们计算今天的日期值,这将花费很少的时间,因为它只会完成一次,并将它与天数列进行比较,因为它被索引并且有不涉及计算。
最后,我们 运行 您当前的查询并使用 explain 查看它,即使我们已经为列 date_ 建立了索引,该索引也不能用于此查询。

CREATE TABLE appointments (
  id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, 
  date_ date,
  days int 
  );
CREATE INDEX ix_apps_days ON appointments (days);
✓

✓
CREATE PROCEDURE apps_day()
BEGIN
UPDATE appointments SET days = day(date_);
END
CREATE TRIGGER t_apps_insert BEFORE INSERT ON appointments
    FOR EACH ROW
BEGIN
SET NEW.days = DATEDIFF(NEW.date_, '1970-01-01') % 30 ;
END;
CREATE TRIGGER t_apps_update BEFORE UPDATE ON appointments
    FOR EACH ROW
BEGIN
SET NEW.days = DATEDIFF(NEW.date_, '1970-01-01') % 30 ;
END;
insert into appointments (date_) values ('2022-01-01'),('2022-01-01'),('2022-04-15'),(now());
update appointments set date_ = '2022-01-12' where id = 1;
select * from appointments
id | date_      | days
-: | :--------- | ---:
 1 | 2022-01-12 |   14
 2 | 2022-01-01 |    3
 3 | 2022-04-15 |   17
 4 | 2022-04-22 |   24
select 
 *
from appointments
where DATEDIFF(CURDATE() , '1970-01-01') % 30 = days;
id | date_      | days
-: | :--------- | ---:
 4 | 2022-04-22 |   24
explain
select  DATEDIFF(CURDATE() , '1970-01-01')
from appointments
where DATEDIFF(CURDATE() , '1970-01-01') = days;
id | select_type | table        | partitions | type | possible_keys | key          | key_len | ref   | rows | filtered | Extra      
-: | :---------- | :----------- | :--------- | :--- | :------------ | :----------- | :------ | :---- | ---: | -------: | :----------
 1 | SIMPLE      | appointments | null       | ref  | ix_apps_days  | ix_apps_days | 5       | const |    1 |   100.00 | Using index
CREATE INDEX ix_apps_date_ ON appointments (date_);
SELECT
    a.*
FROM
    appointments a
WHERE
    DATEDIFF(CURDATE(), a.date_) % 30 = 0
id | date_      | days
-: | :--------- | ---:
 4 | 2022-04-22 |   24
explain
SELECT
    a.*
FROM
    appointments a
WHERE
    DATEDIFF(CURDATE(), a.date_) % 30 = 0
id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra      
-: | :---------- | :---- | :--------- | :--- | :------------ | :--- | :------ | :--- | ---: | -------: | :----------
 1 | SIMPLE      | a     | null       | ALL  | null          | null | null    | null |    4 |   100.00 | Using where

db<>fiddle here

好的,让我们暂时搁置日期和 date-diff。从这个问题来看,这个人正在尝试寻找过去不一定在未来有另一个约会的所有约会。例如与博士进行 FOLLOW-UP 约会“一个月后再回来看看情况有何变化”。这让我想到 table 预约中可能有一些患者 ID。因此,这可能会将问题转化为查看过去 30、60 或 90 天前的情况,以查看未来是否安排了相应的预约。如果已经安排好,患者不需要电话提醒就可以进入办公室。

就是说,我会以不同的方式开始,让所有在过去 90 天内有预约的患者,看看他们是否已经(或没有)follow-up 预约在日程表上对于 follow-up。这样,办公室人员就可以与所述患者取得联系,从而获得日历。

首先获取过去 90 天内任何给定患者的所有最大预约。如果有人在 90 天前有约会,并且在 59 天有 follow-up,那么他们可能只关心最近的约会以确保有 follow-up.

select
      a1.patient_id,
      max( a1.appointment_date ) MostRecentApnt
   from 
      appointments a1
   WHERE
      a1.appointment_date > date_sub( a1.appointment_date, interval 90 day )
   group by
      a1.patient_id

现在,从这个固定的名单和开始日期开始,我们只关心离当前还有多少天最后一次约会。是 X 天吗?只需使用 datediff 和排序。您可以直观地看到有多少天。通过尝试将它们分成 30、60 或 90 天的桶,只知道距离上次约会有多少天可能就像按降序排序一样容易,最旧的约会首先被调用,而不是刚刚发生的约会。甚至可能在 20 天后切断通话清单,但仍未预约并接近预期的 30 天。

SELECT
      p.LastName,
      p.FirstName,
      p.Phone,
      Last90.Patient_ID,
      Last90.MostRecentApnt,
      DATEDIFF(CURDATE(), Last90.appointment_date)  LastAppointmentDays
   FROM
      ( select
              a1.patient_id,
              max( a1.appointment_date ) MostRecentApnt
           from 
              appointments a1
           WHERE
              a1.appointment_date > date_sub( a1.appointment_date, interval 90 day )
           group by
              a1.patient_id ) Last90
      -- Guessing you might want patient data to do phone calling
         JOIN Patients p
            on Last90.Patient_id = p.patient_id
   order by
      Last90.MostRecentApnt DESC,
      p.LastName,
      p.FirstName

有时,仅针对直接问题给出答案并不能满足正确的需求。希望我更 on-target 满足预期的最终结果需求。同样,以上内容意味着为了 follow-up 呼叫目的加入患者 table 以安排约会。