2012-05-31 64 views
0

我已經給了一個任務發送電子郵件提醒客戶在我們的數據庫通知他們的年度訂閱即將到期。發送期限爲賬戶過期前7天30天,15天。已發送的電子郵件將不會重新發送,直到下一個時間段到達(例如[email protected]帳戶即將在2012-06-01到期。服務器在2012-05-02發送電子郵件,然後等到2012-05如果狀態沒有改變,-17再次發送)。此外,如果account_status.statusId不是3,服務器將不會再次發送消息,並重新設置account_metadata.v至7MySQL選擇電子郵件發送帳戶到期提醒

下面的示例數據列表:

id email 
1 [email protected] 
2 [email protected] 
3 [email protected] 
4 [email protected] 
5 Curae;@Phasellus.edu 
6 [email protected] 
7 [email protected] 
8 [email protected] 
9 [email protected] 
10 [email protected] 
11 [email protected] 
12 [email protected] 
13 [email protected] 
14 [email protected] 
15 [email protected] 
16 [email protected] 
17 [email protected] 
18 [email protected] 
19 [email protected] 
20 [email protected] 
21 [email protected] 
22 [email protected] 
23 [email protected] 
24 [email protected] 
25 [email protected] 
26 [email protected] 
27 [email protected] 
28 [email protected] 
29 [email protected].ca 
30 [email protected] 

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 

一ccount_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的

MySQL的查詢我目前有有:

  1. 如果statusId在ACCOUNT_STATUS不是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. 已將電子郵件提醒取決於週期(30天=> 7,15天=> 3 ,7天=> 1)前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不是唯一的(看到accountId = 13上表)。這會導致#1將某些行重置爲7,並且客戶感覺他們被垃圾郵件。有沒有辦法修改#2和/或#1來選擇最新的account_status.statusId(基於account_status.time)或更新最近的account_status.stautsId

回答

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; 
+0

它似乎永遠不會回報。 – user1045217

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); 
相關問題