希望有助于构建MySQL复杂查询

时间:2016-03-10 07:23:25

标签: php mysql

我有3个MySQL表,如 -

**tblCampaigns**
campId  campName    startDate            endDate              status
1       Campaign1   2016-03-10 00:00:00  2016-03-17 00:00:00  active    
2       Campaign2   2016-03-11 00:00:00  2016-03-18 00:00:00  active

**tblServices**
serviceId   serviceName
1           Car Washing
2           Car Painting

**tblCampaignServices**
id  campId  serviceId
1   1       1
2   1       2

我已选择通过自动完成选择向广告系列添加多项服务。我的要求是,当用户键入自动完成以选择要添加到广告系列的服务时,只有那些 serviceName 应出现在建议列表中,这些列表尚未添加到其开始日期和结束日期即将到来的其他广告系列中在当前活动的开始和结束日期之间。我的意思是日期不应与其他广告系列日期相交。此外,serviceName也不应添加到同一个广告系列中。

我做了一半简单的查询,比如获取尚未添加到同一广告系列中的服务 -

select    tblServices.serviceId,tblServices.serviceName 
from      tblServices 
LEFT JOIN tblCampaignServices ON (tblServices.serviceId=tblCampaignServices.serviceId 
AND       tblCampaignServices.campaignId=2) 
where     ISNULL(tblCampaignServices.id)

首先,是否可以通过单个查询来满足我的要求。如果是,请帮助建立它。如果不是,这是获得这个的最好方法吗?

1 个答案:

答案 0 :(得分:1)

以下查询会查找您要查找的内容。

SELECT DISTINCT    
tblServices.serviceId,
tblServices.serviceName
FROM tblServices 
LEFT JOIN tblCampaignServices ON tblServices.serviceId=tblCampaignServices.serviceId
LEFT JOIN tblCampaigns ON tblCampaigns.campId = tblCampaignServices.campId
WHERE
tblCampaigns.campId IS NULL
OR(
(endDate <
(SELECT startDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)
OR 
startDate >
(SELECT endDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2))
AND serviceName NOT IN
(SELECT serviceName
FROM tblCampaignServices 
LEFT JOIN tblServices ON tblServices.serviceId=tblCampaignServices.serviceId
LEFT JOIN tblCampaigns ON tblCampaigns.campId = tblCampaignServices.campId
WHERE
(startDate BETWEEN
(SELECT startDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)
AND
(SELECT endDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2))
OR
(endDate BETWEEN
(SELECT startDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)
AND
(SELECT endDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)))
AND
tblCampaigns.campId <> 2);

这很复杂,所以让我们看看它是如何工作的:

首先,我们加入所有信息,因为我们还需要开始和结束日期来选择允许的服务

我们选择不在广告系列中的所有服务:

tblCampaigns.campId IS NULL  

我们选择的活动中的所有服务与当前的服务不重叠,即endDate低于当前的startDate,或者startDate大于当前的endDate:

(endDate <
(SELECT
startDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)
OR 
startDate >
(SELECT
endDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)

我们从结果集中排除那些广告系列中与当前服务重叠的服务,即当前服务的startDate和endDate之间的startDate或endDate。

serviceName NOT IN
(SELECT serviceName
FROM tblCampaignServices 
LEFT JOIN tblServices ON tblServices.serviceId=tblCampaignServices.serviceId
LEFT JOIN tblCampaigns ON tblCampaigns.campId = tblCampaignServices.campId
WHERE
(startDate BETWEEN
(SELECT startDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)
AND
(SELECT
endDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2))
OR
(endDate BETWEEN
(SELECT startDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)
AND
(SELECT endDate
FROM tblCampaigns
WHERE tblCampaigns.campId=2)))

我们会排除当前广告系列中已有的服务:

tblCampaigns.campId <> 2

由于结果集将具有重复服务,因为在多个不重叠的广告系列中存在服务,我们将DISTINCT添加到顶部SELECT以避免重复服务。

如果当前广告系列与现有广告系列具有相同的startDate和endDate,则查询也会有效。

测试表

 tblCampaigns
 campId campName    startDate           endDate             status 
 1      Campaign1   2016-03-10 00:00:00 2016-03-17 00:00:00 active  
 2      Campaign2   2016-03-11 00:00:00 2016-03-18 00:00:00 active  
 3      Campaign3   2016-02-11 00:00:00 2016-02-18 00:00:00 closed  
 4      Campaign4   2016-04-11 00:00:00 2016-04-18 00:00:00 active  

 tblServices
 serviceId   serviceName
 1           Car Washing
 2           Car Painting
 3           Car Maintenance
 4           Brake Replacement
 5           Gear Replacement

 tblCampaignServices
 id campId  serviceId
 1     1       1
 2     1       2
 3     3       1
 4     3       2
 5     3       3
 6     2       4
 7     4       3

使用此测试表,查询结果为:

serviceId   serviceName
    3       Car Maintenance
    5       Gear Replacement

满足所有要求。

此致