MySQL选择用于发送帐户到期提醒的电子邮件

时间:2012-05-31 02:00:18

标签: mysql

我的任务是发送电子邮件提醒我们的数据库中的客户通知他们的年度订阅即将到期。发送期限为帐户到期前30天,15天,7天。已发送的电子邮件将在下一个时间段之前重新发送(例如,john.doe @ aaa.com帐户即将于2012-06-01到期。服务器在2012-05-02发送电子邮件,然后等到2012-05 -17如果状态未改变则再次发送)。此外,如果account_status.statusId不是3,则服务器将不再发送消息并将account_metadata.v设置为7。

以下示例数据列表:

帐户

id  email
1   velit@necenimNunc.com
2   nec@magna.org
3   imperdiet.ullamcorper.Duis@sagittisaugue.com
4   lacus@velitin.edu
5   Curae;@Phasellus.edu
6   dui.nec@Vivamussitamet.org
7   Aliquam.erat.volutpat@Intincidunt.com
8   vehicula.risus.Nulla@id.org
9   Fusce.diam.nunc@egetdictum.ca
10  urna@magnaNam.edu
11  vitae.erat@erategetipsum.ca
12  eu@eratneque.com
13  non@inconsectetuer.com
14  lectus@Nullamfeugiat.ca
15  sit.amet.diam@enimEtiamimperdiet.com
16  consectetuer.euismod.est@euerosNam.com
17  urna.Nunc.quis@egestas.com
18  tristique.aliquet.Phasellus@afelis.org
19  eget.tincidunt.dui@ligula.org
20  primis.in@accumsanneque.edu
21  ultricies.adipiscing@arcuVestibulum.com
22  euismod.et.commodo@nisi.edu
23  iaculis.quis@molestietortornibh.com
24  molestie@Pellentesque.org
25  ligula.tortor.dictum@dolor.com
26  dictum.ultricies.ligula@ipsum.com
27  pretium@turpis.ca
28  neque.Nullam.nisl@feugiatLoremipsum.edu
29  adipiscing.non.luctus@inconsequatenim.ca
30  faucibus@Mauris.com

ACCOUNT_STATUS

id   statusId  accountId  time
1    1         2          2011-06-01 21:54:37
2    1         3          2011-06-02 09:07:14
3    1         4          2011-06-02 09:13:20
4    1         5          2011-06-02 09:54:44
5    1         6          2011-06-02 10:15:52
6    1         7          2011-06-02 10:17:22
7    2         7          2011-06-02 10:21:25
8    1         8          2011-06-02 11:09:03
9    1         9          2011-06-02 11:09:18
10   1         10         2011-06-02 11:13:29
11   1         11         2011-06-02 11:21:11
12   1         12         2011-06-02 11:21:35
13   3         5          2011-06-02 11:41:04
14   3         2          2011-06-02 11:46:07
15   1         13         2011-06-02 11:49:18
16   3         13         2011-06-02 11:53:45
17   1         14         2011-06-02 12:02:26
18   3         14         2011-06-02 12:10:54
19   1         15         2011-06-02 13:41:19
20   1         16         2011-06-02 15:27:03
21   3         16         2011-06-02 15:42:58
22   1         17         2011-06-02 15:46:05
23   1         18         2011-06-02 15:59:56
24   1         19         2011-06-02 16:13:41
25   1         20         2011-06-02 16:17:36
26   1         21         2011-06-02 16:47:04
27   1         22         2011-06-02 16:47:39
28   1         23         2011-06-02 18:35:29
29   1         24         2011-06-02 19:17:06
30   1         25         2011-06-02 20:07:33

account_metadata

id       accountId  k              v
27033    2          remindEmail    3
27034    3          remindEmail    3
27035    4          remindEmail    3
27036    5          remindEmail    3
27037    6          remindEmail    3
27038    7          remindEmail    3
27039    8          remindEmail    3
27040    9          remindEmail    7
27041    10         remindEmail    7
27042    11         remindEmail    7
27043    12         remindEmail    7
27044    13         remindEmail    3
27045    14         remindEmail    3
27046    15         remindEmail    7
27047    16         remindEmail    3
27048    17         remindEmail    7
27049    18         remindEmail    7

请注意:

  1. accounts.idaccount_metadata.accountId是唯一的
  2. accounts.id = account_metadata.accountId = account_status.accountId
  3. 所有三张表都是Innodb
  4. 我目前的MySQL查询是:

    1. 如果account_status中的statusId不是3,则将remindEmail的值设置为7:

      UPDATE `account_status` AS acs, `accounts` AS a, `account_metadata` AS am
      SET am.v = '7' 
      WHERE acs.statusId != 3 
      AND acs.accountId = a.id
      AND a.id = am.accountId 
      AND am.k = 'remindEmail';
      
    2. 已发送电子邮件提醒取决于1年前的期限(30天=> 7,15天=> 3,7天=> 1)和status = 3

      SELECT am.accountId, a.email, am.k, am.v, acs.time
      FROM accounts a 
      INNER JOIN account_status  acs ON a.id = acs.accountId 
      INNER JOIN account_metadata am ON a.id = am.accountId
      WHERE acs.statusId = 3
      AND am.k =  'remindEmail'
      AND NOW() <= DATE_ADD(acs.time, INTERVAL 365 DAY)
      AND NOW() >  DATE_ADD(acs.time, INTERVAL 365 - ((am.v & 1) * 7 + (am.v & 2) * 8 + (am.v & 4) * 15) DAY)
      AND am.v = %s;
      
    3. account_metadata.v更新为新状态:

      UPDATE `account_metadata` AS am
      SET am.v = '%s'
      WHERE am.accountId = '%s'
      AND am.k = 'remindEmail';
      
    4. 此处的问题是,account_status.accountId并非唯一(请参阅上表accountId = 13)。这将导致#1将某些行重置为7并且客户感觉他们被垃圾邮件发送。有没有办法修改#2和/或#1来选择最新的account_status.statusId(基于account_status.time)或更新最新的account_status.stautsId

2 个答案:

答案 0 :(得分:0)

这似乎有效:

SELECT am.accountId, a.email, am.k, am.v, acs.time
FROM accounts a 
INNER JOIN account_status  acs ON a.id = acs.accountId 
AND acs.id = (
    SELECT acs2.id
    FROM account_status acs2
    WHERE  acs2.time = (
           SELECT MAX(acs3.time)
           FROM   account_status acs3
           WHERE  acs3.accountId = acs.accountId)) 
INNER JOIN account_metadata am ON a.id = am.accountId
WHERE acs.statusId = 3
AND am.k =  'remindEmail'
AND NOW() <= DATE_ADD(acs.time, INTERVAL 365 DAY)
AND NOW() >  DATE_ADD(acs.time, INTERVAL 365 - ((am.v & 1) * 7 + (am.v & 2) * 8 + (am.v & 4) * 15) DAY)
AND am.v = %s;

答案 1 :(得分:0)

我最后自己解决了这个问题。

-- If statusId in account_status is not 3, then set value of remindEmail to 7 --
UPDATE account_metadata am  
  INNER JOIN (
    SELECT acs0.id, acs0.accountId, acs0.statusId, acs0.time 
    FROM account_status acs0
    CROSS JOIN (
      SELECT accountId, MAX(id) AS id 
      FROM account_status
      GROUP BY accountId
    ) acs1 USING (accountId, id)
    WHERE acs0.statusId != 3
  ) acs2 ON am.accountId = acs2.accountId
SET am.v = '7'
WHERE am.k = 'remindEmail';

-- Have sent email reminder depend on the period --
-- (30 days => 7, 15 days => 3, 7 days => 1) before 1 year --
-- and status = 3 --
SELECT am.accountId, a.email, am.k, am.v, acs2.time 
FROM accounts a 
INNER JOIN (
  SELECT acs.`id`, acs.`statusId`, acs.`accountId`, acs.`time` 
  FROM `account_status` acs 
  CROSS JOIN (
    SELECT accountId, MAX(id) AS id 
    FROM `account_status` 
    GROUP BY accountId
  ) AS acs1 
  USING (accountId, id) 
  WHERE acs.`statusId` = 3 
) acs2 ON a.id = acs2.accountId 
INNER JOIN account_metadata am ON a.id = am.accountId 
WHERE am.v = %s 
AND am.k =  'remindEmail' 
AND NOW() <= DATE_ADD(acs2.time, INTERVAL 365 DAY) 
AND NOW() >  DATE_ADD(acs2.time, INTERVAL 365 - ((am.v & 1) * 7 + (am.v & 2) * 8 + (am.v & 4) * 15) DAY);