MySQL获取具有条件的表之间的记录

时间:2016-11-04 13:32:40

标签: mysql sql left-join

我手上有一个大问题,我有以下SQL结构,其中 contract 表以dinamically方式生成,具有随机名称,例如 _xyz _xxx 等:

CREATE TABLE contract_xyz(
  id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
  created_at DATETIME NOT NULL
 );
CREATE TABLE contract_events(
    id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
    id_contract INT(11) NOT NULL,    
    table_contract VARCHAR(255) NOT NULL,
    created_at DATETIME NOT NULL
);
INSERT INTO contract_xyz (id,created_at) VALUES (1,'2016-11-01');
INSERT INTO contract_xyz (id,created_at) VALUES (2,'2016-10-21');
INSERT INTO contract_xyz (id,created_at) VALUES (3,'2016-11-04');
INSERT INTO contract_events(id,id_contract,table_contract,created_at) VALUES (1,1,'contract_xyz','2016-11-03');
INSERT INTO contract_events(id,id_contract,table_contract,created_at) VALUES (2,3,'contract_xyz','2016-11-04');

每份合约都有自己的活动。我需要解决以下问题:

获取所有在2天内没有新活动的合同,或者根本没有任何活动,并且是在2天前创建的。

我尝试过 LET JOIN ,但结果并不正确。我得到的最近的是以下查询:

SELECT `contract_xyz`.*
FROM `contract_xyz`
WHERE EXISTS(SELECT 1
         FROM `contract_events`
         WHERE
           `contract_events`.id_contract = `contract_xyz`.id AND `contract_events`.table_contract = 'contract_xyz'
           AND DATEDIFF(CURDATE(), `contract_events`.created_at) >= 2
         ORDER BY `contract_events`.created_at DESC
         LIMIT 1)
  OR (NOT EXISTS(SELECT 1
                 FROM `contract_events`
                 WHERE `contract_events`.id_contract = `contract_xyz`.id AND
                       `contract_events`.table_contract = 'contract_xyz') AND
      DATEDIFF(CURDATE(), `contract_xyz`.created_at) >= 2);

但我仍然无法找到没有任何事件的合同,并且是在2天前创建的。

2 个答案:

答案 0 :(得分:1)

我会创建一个子查询,其中包含每个合约的最大事件日期。我会在这个子查询上加入合约表。您可以根据最大事件日期和创建日期字段进行过滤,以实现预期结果:

select c.*
from contract_xyz c
left join 
    (select id_contract,
           max(created_at) max_event_date
     from contract_events
     group by id_contract) t on c.id-t.id_contract
 where
     DATEDIFF(CURDATE(), t.max_event_date) >= 2
     or (t.max_event_date is null and DATEDIFF(CURDATE(), c.created_at) >= 2)

或者,您不使用子查询,而是直接使用group by连接2个表,并在having子句中进行过滤。

答案 1 :(得分:0)

LEFT OUTER JOIN ON条件可以在此处提供帮助:

select c.id, c.created_at,count(e.id) as contract_events_less_than_2_days_old
from contract_xyz c
left outer join contract_events e on e.id_contract = c.id 
                                 and e.table_contract = 'contract_xyz' 
                                 and e.created_at > now() - interval 2 day
where c.created_at < now() - interval 2 day
and e.id is null
group by c.id, c.created_at;

如果您对它有任何控制权,我会建议不要动态生成表名!