这个SQL查询可以简化吗?

时间:2010-05-11 07:32:58

标签: sql mysql simplify

我有以下表格:
人,{“Id”,“姓名”,“姓氏”} 体育,{“Id”“姓名”,“类型”} SportsPerPerson,{“Id”,“PersonId”,“SportsId”}

对于我的查询,我希望得到所有超过特定运动项目的人员,而我只拥有运动“名称”属性。要检索正确的行,我已经找到了以下查询:

SELECT *
FROM Person
WHERE Person.Id in 
(
    SELECT SportsPerPerson.PersonId FROM SportsPerPerson
    INNER JOIN Sports on SportsPerPerson.SportsId = Sports.Id
    WHERE Sports.Name = 'Tennis'
)
AND Person.Id in 
(
    SELECT SportsPerPerson.PersonId FROM SportsPerPerson
    INNER JOIN Sports on SportsPerPerson.SportsId = Sports.Id
    WHERE Sports.Name = 'Soccer'
)

OR

SELECT *
FROM Person
WHERE Id IN
    (SELECT PersonId FROM SportsPerPerson WHERE SportsId IN 
        (SELECT Id FROM Sports WHERE Name = 'Tennis'))
AND Id IN
    (SELECT PersonId FROM SportsPerPerson WHERE SportsId IN 
        (SELECT Id FROM Sports WHERE Name = 'Soccer'))

现在我的问题是,是不是有更简单的方法来编写这个查询?使用OR不会起作用,因为我需要扮演'网球'和'足球'的人。但是使用AND也不起作用,因为值不在同一行上。

5 个答案:

答案 0 :(得分:2)

您可以使用其他JOIN来避免第二个IN。子选择只返回那些同时打网球和足球的人:

SELECT *
FROM Person
WHERE Person.Id IN
(
    SELECT spp1.PersonId
    FROM SportsPerPerson spp1
    JOIN SportsPerPerson spp2 ON ( spp2.PersonId = spp1.PersonId )
    JOIN Sports s1 on spp1.SportsId = s1.Id
    JOIN Sports s2 on spp2.SportsId = s2.Id
    WHERE s1.Name = 'Tennis'
      AND s2.Name = 'Soccer'
)

答案 1 :(得分:1)

您应该在查询中使用两个联接:

SELECT *
FROM Person p INNER JOIN SportsPerPerson spp1 ON (p.PersonId = spp1.PersonId)
              INNER JOIN Sports s1 ON (s1.SportsIN = spp1.SportId)
              INNER JOIN SportsPerPerson spp2 ON (p.PersonId = spp2.PersonId)
              INNER JOIN Sports s2 ON (s2.SportId = spp2.SportId)
    WHERE s1.Name = 'Tennis' AND s2.Name='Soccer'

答案 2 :(得分:0)

诀窍是使用别名,以便您可以多次使用相同的表:

SELECT p.*
FROM Person p
INNER JOIN SportsPerPerson spa
  ON p.Id = spa.PersonId
INNER JOIN Sports sa
  ON spa.SportsId = sa.Id
INNER JOIN SportsPerPerson spb
  ON p.Id = spb.PersonId
INNER JOIN Sports sb
  ON spb.SportsId = sb.Id
WHERE
  sa.Name = 'Tennis'
  AND sb.Name = 'Soccer'

答案 3 :(得分:0)

此:

SELECT  *
FROM    Person p
WHERE   (
        SELECT  COUNT(*)
        FROM    Sports s
        JOIN    SportsPerPerson sp
        ON      sp.SportsID = s.id
        WHERE   s.name IN ('Tennis', 'Soccer')
                AND sp.PersonID = p.id
        ) = 2

或者这个:

SELECT  p.*
FROM    (
        SELECT  sp.PersonID
        FROM    Sports s
        JOIN    SportsPerPerson sp
        ON      sp.SportsID = s.id
        WHERE   s.name IN ('Tennis', 'Soccer')
        GROUP BY
                sp.PersonID
        HAVING  COUNT(*) = 2
        ) q
JOIN    person p
ON      p.id = q.personID

您需要在UNIQUE KEY上声明PRIMARY KEYSportsPerPerson (sportsid, personid)才能正常,快速地工作。

答案 4 :(得分:0)

您需要的查询是:

SELECT p.ID, p.Name, p.LastName
FROM Person p
JOIN SportsPerPerson sp ON p.ID = sp.PersonID 
JOIN Sports s ON sp.SportsID = s.ID
WHERE s.Name = 'Football'

这就是说,除此之外,SportsPerPerson表上的ID键完全没有必要实现你拥有的多对多关系。使用PersonID和SportID列作为复合主键就足够了。