如何在SQL中使用子查询?

时间:2018-01-01 14:33:37

标签: mysql sql subquery

我有4张桌子:
Travelers (TravelerID,FirstName,LastName)
Guides(GuideID,FirstName,LastName)
Locations(LocationID,LocationName)
Trips(TravelerID,GuideID,LocationID,Stars,StartDate,ReturnDate)

我想按指南返回他引导最多旅行者人数的位置名称。

我尝试过使用这个子查询,但它不起作用:

SELECT G.FirstName,L.LocationName,count(distinct(TravelerID))as number_of_travelers_per_guide 
FROM Guides AS G 
LEFT JOIN Trips AS T USING (GuideID) 
LEFT JOIN Locations AS L USING (LocationID)
GROUP BY G.FirstName,L.LocationName 
HAVING max((SELECT T1.number_of_travelers_per_guide 
            FROM Trips AS T1 
            WHERE T.GuideID=T1.GuideID));

我将不胜感激任何帮助

3 个答案:

答案 0 :(得分:1)

尝试使用完整功能而不是alis

SELECT G.FirstName,L.LocationName, count(distinct T.TravelerID ) as number_of_travelers_per_guide 
FROM Guides AS G 
LEFT JOIN Trips AS T USING (GuideID) 
LEFT JOIN Locations AS L USING (LocationID)
GROUP BY G.FirstName,L.LocationName 
HAVING count(distinct TravelerID ) = ( 
            select max(my_count) from (SELECT count(distinct T.TravelerID) my_count
            FROM Guides AS G 
            LEFT JOIN Trips AS T USING (GuideID) 
            LEFT JOIN Locations AS L USING (LocationID)
            GROUP BY G.FirstName, L.LocationName ) my_t );

答案 1 :(得分:1)

这是MySQL真正的痛苦,因为pre v 8版本既没有CTE也没有窗口函数。一种方法使用变量:

SELECT gl.*
FROM (SELECT gl.*,
             (@rn := if(@g = gl.FirstName, @rn + 1,
                        if(@g := gl.FirstName, 1, 1)
                       )
             ) as rn
      FROM (SELECT G.FirstName, L.LocationName, count(distinct TravelerID) as number_of_travelers_per_guide 
            FROM Guides G LEFT JOIN
                 Trips T
                 USING (GuideID) LEFT JOIN
                 Locations L
                 USING (LocationID)
            GROUP BY G.FirstName, L.LocationName 
            ORDER BY G.FirstName, number_of_travelers_per_guide DESC
           ) gl CROSS JOIN
           (SELECT @g := '', @rn := -1) params
      ) gl
WHERE rn = 1;

我不会强调理解MySQL中的变量。相反,请了解row_number()rank()dense_rank() - 这些是在几乎所有数据库中解决问题的正确方法。

答案 2 :(得分:0)

如果无法使用CTE和分析功能,我认为您正在考虑以下内容。但是,如果指南有两个排名相同的位置,则会有一个危险,那么将为该指南返回两行或更多行而不是一行。

SELECT
    G.FirstName
    ,L.LocationName
    ,guide_stats.traveler_count

FROM
    (
        SELECT
            GuideID
            ,LocationID
            ,COUNT(DISTINCT TravelerID) AS traveler_count

        FROM Trips
        GROUP BY GuideID, LocationID

    ) AS guide_stats

INNER JOIN
    (
        SELECT 
            guide_stats_for_max.GuideID
            ,MAX(guide_stats_for_max.traveler_count) AS max_traveler_count

        FROM
        (
            SELECT
                GuideID
                ,LocationID
                ,COUNT(DISTINCT TravelerID) AS traveler_count

            FROM Trips
            GROUP BY GuideID, LocationID

        ) AS guide_stats_for_max

        GROUP BY GuideID

    ) AS guide_max
    ON (guide_stats.GuideID = guide_max.GuideID)
    AND (guide_stats.traveler_count = guide_max.max_traveler_count)

LEFT JOIN Guides    AS G USING (guide_stats.GuideID)
LEFT JOIN Locations AS L USING (guide_stats.LocationID)

注意我在没有测试的情况下编写了此代码 - 请原谅小错误。