从过去7天没有联系人的客户中选择ID,在该月中选择2次

时间:2016-01-21 17:09:00

标签: sql sql-server select plsql sql-server-2012

我有2个表:customer,c_contact。 c_contact是我发给客户的所有电子邮件。 从现在开始,我需要制定一条新规则,即客户无法在以下情况下收到新电子邮件: 1)它在过去7天内收到了一封电子邮件 2)在当月发送2封或者更多的电子邮件

我认为是这样的:

SELECT * from customer c inner join c_contact cc on cc.ID = c.ID WHERE
ID not in (select ID from c_contact c1 where c1.ID = cc.ID and 
c1.CONTDATE >= getdate()-7) AND
ID not in (select count(ID) from c_contact where MONTH(contdate) = MONTH(getdate()) 
and YEAR(contdate) = YEAR(getdate() HAVING count(ID) >= 2)

但表c_contact很大,运行它需要很长时间。 有没有办法在1" ID不在"?中执行这两个条件?我认为它会跑得更快。

2 个答案:

答案 0 :(得分:1)

我不确定这会对性能有多好,但是我可以做到这一点。

SELECT  *
FROM    customer c
        OUTER APPLY (SELECT COUNT(*) monthCount 
                     FROM   c_contact cc 
                     WHERE  cc.ID = c.ID 
                            AND cc.contdate >= DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), 0) 
                            AND cc.contdate < DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)) ct
        OUTER APPLY (SELECT MAX(cc.contdate) lastSent 
                     FROM   c_contact cc 
                     WHERE  cc.ID = c.ID AND cc.contdate < GETDATE()) ls
WHERE   ct.monthCount < 2
        AND ls.lastSent < DATEADD(dd, -7, GETDATE()) 

或者,使用左连接而不是2外部适用,您可以尝试:

SELECT  *
FROM    customer c
        LEFT JOIN (
            SELECT  cc.ID, 
                    COUNT(CASE WHEN MONTH(cc.contdate) = MONTH(GETDATE()) THEN 1 END) monthCount,
                    MAX(cc.contdate) lastSent
            FROM    c_contact cc
            WHERE   cc.contdate BETWEEN DATEADD(dd, -32, GETDATE()) AND GETDATE()
            GROUP BY cc.ID
        ) cc ON c.ID = cc.ID
WHERE   ISNULL(cc.monthCount,0) < 2
        AND ISNULL(cc.lastSent,GETDATE()) < DATEADD(dd, -7, GETDATE()) 

如果您真的只想使用NOT IN,可以尝试:

SELECT  *
FROM    customer c
WHERE   c.ID NOT IN (
            SELECT  cc.ID, 
                    COUNT(CASE WHEN MONTH(cc.contdate) = MONTH(GETDATE()) THEN 1 END) monthCount,
                    MAX(cc.contdate) lastSent
            FROM    c_contact cc
            WHERE   cc.contdate BETWEEN DATEADD(dd, -32, GETDATE()) AND GETDATE()
            GROUP BY cc.ID
            HAVING  COUNT(CASE WHEN MONTH(cc.contdate) = MONTH(GETDATE()) THEN 1 END) > 1
                    AND MAX(cc.contdate) >  DATEADD(dd, -7, GETDATE()) 
        )

答案 1 :(得分:0)

这也可以通过其他方式完成:

select A.* from Customers A
where A.CustID not in (
select B.CustID from (
(select C.CustID, Count(C.CustID) cnt from Contacts C
where C.ContactedDate >=GETDATE()-7 group by C.CustID)
UNION
(select C.CustID, Count(C.CustID) cnt from Contacts C
where C.ContactedDate <=GETDATE()-7 and Month(C.ContactedDate) = Month(GETDATE()) and YEAR(C.ContactedDate)= YEAR(GETDATE()) 
group by C.CustID having COUNT(C.CustID) >= 2)) B);
go

将客户ID分为两组 - 第一组包含最近7天内联系的ID,第二组包含当前最后三周联系的ID。在选择所需的客户组时,最后排除这两组UNION