多表连接中的重复行

时间:2011-11-26 11:39:23

标签: mysql

我有四张表格如下:

tenant
+----+------------+
| id | name       |
+----+------------+
|  1 | John Smith | 
|  2 | Anna Jones | 
+----+------------+

property
+----+-------------+---------------+
| id | landlord_id | address       |
+----+-------------+---------------+
|  1 |           1 | King Street 1 | 
|  2 |           1 | Green Grove 2 | 
|  3 |           2 | Queen Stree 3 | 
+----+-------------+---------------+

tenant_has_property
+-----------+-------------+
| tenant_id | property_id |
+-----------+-------------+
|         1 |           1 | 
|         1 |           2 | 
+-----------+-------------+

landlord
+----+-----------------+
| id | name            |
+----+-----------------+
|  1 | Best Homes Ltd. | 
|  2 | RealEstates Inc | 
+----+-----------------+

现在我想获得一个从房东id = 1

房租房产的租户名单

当我运行如下查询时:

SELECT 
  tenant.id, tenant.name 
FROM 
  tenant, property, tenant_has_property 
WHERE 
  tenant.id = tenant_has_property.tenant_id AND 
  tenant_has_property.property_id = property.id AND 
  property.landlord_id = 1

我收到重复的行:

+----+------------+
| id | name       |
+----+------------+
|  1 | John Smith | 
|  1 | John Smith | 
+----+------------+

我知道将查询更改为

SELECT 
  DISTINCT tenant.id, tenant.name ...

会删除重复的行,但我的问题是:

是否可以避免使用DISTINCT并以不返回重复行的方式构造JOIN?已经尝试了INNER,LEFT JOINS的所有组合,没有太多运气:(

非常感谢任何建议

3 个答案:

答案 0 :(得分:1)

真正的版本是

SELECT id, name FROM tenant 
WHERE id IN 
(SELECT tenant_has_property.tenant_id FROM 
tenant_has_property 
WHERE tenant_has_property.property_id IN 
(SELECT property.id FROM property WHERE property.landlord_id = 1 )
)

我认为这对你有用。但我没有尝试它,因为我没有访问我的终端上的SQL服务器。

答案 1 :(得分:1)

Jonh Smith是Best Homes Ltd的两个房产的租户,所以他出了两次,所以你不得不搞砸一下或者说不同等。

为了得到你想要的东西,你需要另一张桌子说

组合 哪个会给你一个连接帐篷到kandlord的记录。 然后你可以用它来将投资组合链接到财产。即您将多个租约分组,因此您不必使用tennat_has_property表来查看关系。

是否值得重构架构我不知道。

答案 2 :(得分:0)

您可以使用IN子句使用以下查询执行此操作:

  SELECT 
    t.id, t.name 
  FROM 
    tenant t 
  WHERE 
    t.id IN (
      SELECT
        thp.tenant_id 
      FROM 
        tenant_has_property thp
        INNER JOIN property p ON thp.property_id = p.id
      WHERE
        p.landlord_id = 1
    )

但我强烈建议您不要使用此方法,因为内部SQL语句往往比JOIN查询运行得慢。您可以使用GROUP BY按tenant.id对结果进行分组。

  SELECT 
    t.id, t.name 
  FROM 
    tenant t 
    INNER JOIN tenant_has_property thp ON t.id=thp.tenant_id
    INNER JOIN property p ON thp.property_id = p.id
  WHERE 
    p.landlord_id = 1
  GROUP BY t.id

据我所知,仅使用JOIN语句实现此目的是不可能的。因为MySQL将按照您的请求加入记录,然后最终会有以下行:

t.id,   t.name  , thp.tenant_id, thp.property_id, p.id, p.landlord_id,  p.address  
 1  , John Smith,       1      ,        1         , 1 ,       1      , King Street 1  
 1  , John Smith,       1      ,        2         , 2 ,       1      , Green Grove 2  

由于您只请求t.id和t.name字段,因此MySQL仅向您返回列,但它不知道它们具有重复值。您必须通过向select子句添加DISTINCT或告诉MySQL如何对记录进行分组并返回单行来强制它。