0

我的任务是向我们数据库中的客户发送电子邮件提醒,通知他们的年度订阅即将到期。发送期限为账户过期前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

帐户状态

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.id并且account_metadata.accountId是独一无二的
  2. accounts.id = account_metadata.accountId = account_status.accountId
  3. 这三个表都是 Innodb

我目前拥有的 MySQL 查询是:

  1. 如果 account_status 中的 statusId 不为 3,则将提醒邮件的值设置为 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';
    

这里的问题是,account_status.accountId不是唯一的(见上表 where accountId = 13)。这将导致#1 将一些行重置为 7,并且客户会觉得他们收到了垃圾邮件。有什么方法可以修改 #2 和/或 #1 以选择最新的account_status.statusId(基于account_status.time)或通过最新的更新account_status.stautsId

4

2 回答 2

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);
于 2012-05-31T10:51:06.183 回答
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;
于 2012-05-31T02:24:13.313 回答