【问题标题】:Three Tables, Two Joins, Only One Table Needed For Results三个表,两个连接,结果只需要一个表
【发布时间】:2025-12-09 21:20:07
【问题描述】:

我有三个表:Clients、Services 和 Client Locations。我正在运行一个查询,该查询需要返回接收特定服务的客户端的位置。所以在 SELECT 中使用第二个表,在 WHERE 中使用第三个表。我正在使用两个 LEFT JOIN 并以不合需要的方式重复我的结果。

这是三个表的简化版本...

客户(客户)

id_client | clientName
----------------------
1         | Abby
2         | Betty
3         | Cathy

Client Services(服务)仅在 WHERE 语句中使用

id_client | date      | serviceType
-----------------------------------
1         | 1/5/2015  | Counseling
1         | 1/12/2015 | Counseling
1         | 1/19/2015 | Counseling
2         | 1/21/2015 | Sup. Group

客户位置(locations)只在SELECT语句中使用

id_client | city
----------------------
1         | Boston, MA
3         | Providence, RI

这里是查询

SELECT clients.clientName,locations.city
FROM clients
LEFT JOIN locations ON clients.id_client=locations.id_client
LEFT JOIN services ON clients.id_client=services.id_client
WHERE services.serviceType='Counseling'

结果

clientName | city
-----------------------
Abby       | Boston, MA
Abby       | Boston, MA
Abby       | Boston, MA

所以这让我 Abby 住在波士顿 3 次,而不是想要的那次。

现在,我确切地知道为什么会发生这种情况。用于服务表的 LEFT JOIN 正在用于结果,并且 Abby 的 3 次咨询会导致该城市重复 3 次。

是否有另一种方法来执行此 JOIN 以便服务表不会导致这样的重复?我已经尝试过 INNER JOIN 并得到了同样的结果。

【问题讨论】:

  • 您应该注意,您的查询在服务上使用左连接,而 where 子句中的条件基本上使其成为内连接。

标签: mysql sql join


【解决方案1】:

使用exists:

SELECT c.clientName, l.city
FROM clients c JOIN
     locations l
     ON c.id_client = l.id_client
WHERE EXISTS (SELECT 1
              FROM services s
              WHERE c.id_client = s.id_client AND
                    s.serviceType = 'Counseling'
             );

虽然您可以使用group bydistinct,但这种方法应该会执行得更好。不需要生成重复的结果,只是为了在另一个步骤中删除它们。

【讨论】:

  • 我觉得这个答案是最好的,因为它以最有效的方式解决了我发布的问题。不幸的是,我的实际情况比我发布的要复杂得多,这将是一场噩梦。
  • 关联子查询的性能更好?比我的回答还要好? *.com/a/28456160/40822
  • 我很难真正了解这里的性能差异。我赞成你提供另一种方法。最后,对于我发布的内容,它们都是有效的解决方案,但我最终不得不做一些稍微不同的事情来解决我的实际问题。
  • @dotjoe 。 . .我希望相关子查询比具有显式select distinct 子查询的子查询执行得更好。我希望通过services(id_client, service_type) 上的适当索引,它会快得多。
  • 很有趣,我想我一直认为它会更慢,因为它必须为每个 id_client 运行存在。也许它会优化它?
【解决方案2】:

要么使用distinct

SELECT DISTINCT clients.clientName,locations.city
FROM clients
LEFT JOIN locations ON clients.id_client=locations.id_client
LEFT JOIN services ON clients.id_client=services.id_client
WHERE services.serviceType='Counseling'

group by

SELECT clients.clientName,locations.city
FROM clients
LEFT JOIN locations ON clients.id_client=locations.id_client
LEFT JOIN services ON clients.id_client=services.id_client
WHERE services.serviceType='Counseling'
GROUP BY clients.clientName,locations.city

或子查询

SELECT clients.clientName,locations.city
FROM clients
LEFT JOIN locations ON clients.id_client=locations.id_client
LEFT JOIN (
  SELECT id_client, serviceType 
  FROM services 
  GROUP BY id_client, serviceType 
) services ON clients.id_client=services.id_client
WHERE services.serviceType='Counseling'
GROUP BY clients.clientName,locations.city

Sample SQL Fiddle

【讨论】:

  • 起初我觉得这行不通,因为在某些情况下,一个人会有两次相同的位置,这需要反映在结果中,而不是归结为一个。但后来我意识到我可以使用 GROUP BY 并将 id_client 和 id_location 列分组(我知道我没有在我的帖子中显示),我会得到我正在寻找的结果。希望我能做出两个正确的答案!
【解决方案3】:

您可以获取该服务类型的不同客户端 ID,然后加入客户端和位置以获取有关客户端的更多详细信息。

SELECT clients.clientName,locations.city
FROM 
(Select distinct id_client from services WHERE services.serviceType='Counseling') s
INNER JOIN clients ON clients.id_client = s.id_client
LEFT JOIN locations ON clients.id_client=locations.id_client

【讨论】:

    【解决方案4】:

    您正在汇总详细结果集。因此,请使用 DISTINCT。

    SELECT DISTINCT clients.clientName, locations.city
      FROM clients
      LEFT JOIN locations ON clients.id_client=locations.id_client
      LEFT JOIN services ON clients.id_client=services.id_client
     WHERE services.serviceType='Counseling'
    

    或者使用 GROUP BY 查询并提供一些汇总统计信息:

    SELECT DISTINCT clients.clientName, locations.city,
           COUNT(*) service_count
      FROM clients
      LEFT JOIN locations ON clients.id_client=locations.id_client
      LEFT JOIN services ON clients.id_client=services.id_client
     WHERE services.serviceType='Counseling' 
     GROUP BY clients.clientName, locations.city
    

    【讨论】:

      【解决方案5】:

      您可以简单地使用 distinct 子句来避免双重结果。

      SELECT distinct clients.clientName,locations.city
      FROM clients
      LEFT JOIN locations ON clients.id_client=locations.id_client
      LEFT JOIN services ON clients.id_client=services.id_client
      WHERE services.serviceType='Counseling'
      

      【讨论】: