在LEFT JOIN之后SQL查询未返回预期结果(包括架构和图片)

时间:2014-08-04 23:55:03

标签: php mysql sql join left-join

我之前创建了一个查询,用于连接与客户关联的员工。每个客户只分配了2个客户。我的问题是在执行查询之后,对于每个客户,它将所有员工与每个客户相关联,而不是2.这是我到目前为止所拥有的:

SELECT C.customer_ID, C.l_Name AS Surname, 
    C.f_Name AS 'First Name', C.travel_Date,
    T.tour_Name, 
    GROUP_CONCAT(S.f_Name, S.l_Name ) AS Staff_Concat
    FROM Customers AS C 

    LEFT JOIN Tour AS T ON C.tour_ID = T.tour_ID
    LEFT JOIN Staff_Day AS SD ON C.tour_ID = SD.tour_ID
    LEFT JOIN Staff_Day AS SD_2 ON SD_2.sd_Date = C.travel_Date 
    LEFT JOIN Staff AS S ON SD.staff_ID = S.staff_ID

    WHERE 
    C.travel_Date >= '2014-07-08 00:00:00' 
    AND C.travel_Date <= '2014-07-08 23:59:59'

    AND C.customer_ID NOT IN (SELECT O.customer_ID 
    FROM Customers AS C, Orders AS O 
    WHERE C.travel_Date >= '2014-07-08 00:00:00' 
    AND C.travel_Date <= '2014-07-08 23:59:59' AND C.customer_ID = O.customer_ID )
    GROUP BY C.customer_ID, Surname, 'First Name', C.travel_Date, T.tour_Name

此查询成功返回正确数量的乘客。但是,它正在为工作人员返回不正确的数据。每位乘客只应分配2名工作人员。此查询似乎返回每个客户的所有员工。我得到的结果是:

6166    customer_Name   2014-07-08 Wildthing    Staff1, Staff2, staff3...staff10

预期结果应为:

6166    customer_Name   2014-07-08 Wildthing    Staff1, staff2

工作人员,Staff_Day和旅游表的附加图像:

Staff_Day

Staff Day Table

员工

Staff Table

游览

Tour Table

附件是Customers,Staff,Staff_Day和Tour表的结构:

Table structure for table Customers
Column  Type    Null    Default
customer_ID int(11) No  
f_Name  varchar(30) Yes NULL
l_Name  varchar(30) No  
address varchar(100)    No  
suburb  varchar(30) No  
state   varchar(30) No  
country varchar(30) No  
postcode    varchar(30) No  
email   varchar(50) No  
phone   varchar(20) No  
child_1 varchar(30) Yes NULL
child_2 varchar(30) Yes NULL
child_3 varchar(30) Yes NULL
child_4 varchar(30) Yes NULL
travel_Date datetime    No  
signature   text    No  
terms   tinyint(1)  No  
interested_video    tinyint(1)  Yes 0
specials    tinyint(1)  Yes NULL
tour_ID int(11) Yes NULL
updated timestamp   No  CURRENT_TIMESTAMP

Table structure for table Staff
Column  Type    Null    Default
f_Name  varchar(30) No  
l_Name  varchar(30) No  
comm_Value  int(3)  No  
staff_Type  varchar(50) No  
staff_ID    int(11) No  
bus_ID  int(11) No  

Table structure for table Staff_Day
Column  Type    Null    Default
sd_ID   int(11) No  
staff_ID    int(4)  No  
tour_ID int(4)  No  
sd_Date datetime    No  

Table structure for table Tour
Column  Type    Null    Default
tour_Name   varchar(30) No  
tour_ID int(11) No  
bus_ID  int(11) No  

有人告诉我,SQL查询的JOIN部分可能存在问题。任何帮助/指导将不胜感激。如果这是转贴,请道歉。我已经完成了我的研究,但我现在只是碰到了砖墙。

2 个答案:

答案 0 :(得分:0)

我认为你的问题就在这一行:

LEFT JOIN Staff_Day AS SD_2 ON SD_2.sd_Date = C.travel_Date

当您似乎只想要具有特定tour_ID的记录时,它会加入您的示例Staff_Day表中的所有记录。如果没有该行的原因,您可以完全删除它。但是,如果您尝试除了tour_ID之外还要按日期过滤Staff_Day表,请尝试将其替换为:

LEFT JOIN Staff_Day AS SD ON C.tour_ID = SD.tour_ID
LEFT JOIN Staff_Day AS SD_2 ON SD_2.sd_Date = C.travel_Date 

有了这个:

LEFT JOIN Staff_Day AS SD ON C.tour_ID = SD.tour_ID AND SD.sd_Date = C.travel_Date

这样,您只需加入Staff_Day表一次,就会收到我猜测的结果。

答案 1 :(得分:0)

首先,对您的查询进行非常轻微的重组。您不需要对ID和日期的员工日表进行两次查询,而是按日期创建笛卡尔结果。相反,在BOTH PARTS上使用一个表连接,而不是与员工日表相比硬编码from / to date。你可以做一个DATE_ADD()并且不到一整天...除非你在旅行日期存储时间部分,否则你最好根据日期匹配做,无论时间如何。

所以,第一次左游加入巡演的描述,没问题。 第二个是员工日,然后是基于匹配旅行和日期的工作人员。

最后,你有一个NOT IN(subselect)。我也将其更改为连接格式,但只是为了澄清。它显示您正在尝试获取可能已注册某个特定游览但从未实际放置并提交订单的所有客户的列表。但是......如果有人在同一个客户的不同日期为其他订单注册,他们会有订单存档...但是您将在客户旅行日期强制限定符。在不知道日期和订单表背后的更多细节的情况下......我不确定可能会暴露其他影响。

<强> 修改

由于您仍然遇到笛卡尔结果问题(但没有意义),请将您的联接更改为INNER JOINS,因此巡回赛应该是已知且有效的

SELECT 
      C.customer_ID, 
      C.l_Name AS Surname, 
      C.f_Name AS 'First Name', 
      C.travel_Date,
      T.tour_Name, 
      GROUP_CONCAT(S.f_Name, S.l_Name ) AS Staff_Concat
   FROM 
      Customers AS C 
         JOIN Tour AS T 
            ON C.tour_ID = T.tour_ID
         JOIN Staff_Day AS SD 
            ON C.tour_ID = SD.tour_ID
           AND C.Travel_Date >= SD.sd_Date
           AND SD.sd_date < Date_add( C.Travel_Date, INTERVAL 1 DAY )
            JOIN Staff AS S 
               ON SD.staff_ID = S.staff_ID
   WHERE 
          C.travel_Date >= '2014-07-08 00:00:00' 
      AND C.travel_Date <= '2014-07-08 23:59:59'
      AND C.customer_ID NOT IN 
         ( SELECT 
                 C.customer_ID 
              FROM 
                 Customers AS C
                    JOIN Orders AS O 
                       ON C.customer_ID = O.customer_ID 
              WHERE 
                     C.travel_Date >= '2014-07-08 00:00:00' 
                 AND C.travel_Date <= '2014-07-08 23:59:59' )
   GROUP BY 
      C.customer_ID, 
      Surname, 
      'First Name', 
      C.travel_Date, 
      T.tour_Name

关于表格重组的建议。我会更喜欢......

游览 - 一般来说 TourSpecific - 特定的唯一ID,它也具有基于它的游览的ID,但也具有提供的特定时间段。这样,当客户报名参加上午10点到下午2点的旅行时,他们将被分配到SpecificTourID,那么您不必处理时间戳比较。同样,特定日期和时间段的工作人员将具有SpecificTourID,那么您将获得更少的混淆和更简单的查询。

例如:

Tours
TourID   TourName
10       Jammin
11       Thriller
12       Thunderstruck
13       Wildthing

SpecificTours
SpecificTourID   TourID   TourDateTime
1                10       8/1/2014 8:00am
2                10       8/1/2014 1:15pm 
3                10       8/4/2014 8:00am
4                10       8/4/2014 1:15pm

Customers
CustomerID   FirstName  LastName
1            Bill       Board
2            Eileen     Dover
3            Seymore    Hair

Orders
OrderID   CustomerID   SpecificTourID
1         1            1
2         2            1
3         1            4

StaffDay(类似方法,但使用指定的特定tourID

这样,订单#2的订单适用于特定的旅游1,即旅游10,即Jammin。