Self join tutorial #10 on sqlzoo

旧街凉风 提交于 2019-12-11 02:33:35

问题


I have tried http://sqlzoo.net/wiki/Self_join

Self Join Session for the #10

# 10 : Find the routes involving two buses that can go from Craiglockhart to Sighthill.Show the bus no. and company for the first bus, the name of the stop for the transfer,and the bus no. and company for the second bus.

Here is my code:

SELECT   a.num, a.company, 
             trans1.name ,  c.num,  c.company
FROM route a JOIN route b
ON (a.company = b.company AND a.num = b.num)
JOIN ( route c JOIN route d ON (c.company = d.company AND c.num= d.num))
JOIN stops start ON (a.stop = start.id)
JOIN stops trans1 ON (b.stop = trans1.id)
JOIN stops trans2 ON (c.stop = trans2.id)
JOIN stops end ON (d.stop =  end.id)
WHERE  start.name = 'Craiglockhart' AND end.name = 'Sighthill'
            AND  trans1.name = trans2.name 
ORDER BY a.num ASC , trans1.name

I know the output would give you multiple rows like:

    4   LRT London Road 35  LRT
    4   LRT London Road 34  LRT
    4   LRT London Road 35  LRT
    4   LRT London Road 34  LRT
    4   LRT London Road C5  SMT

Where you want:

    4   LRT London Road 34  LRT
    4   LRT London Road 35  LRT
    4   LRT London Road 65  LRT
    4   LRT London Road C5  SMT

There is also a bug that the order of a.num when I try ASC doesn't work. Also the when I put DISTINCT before c.num it shows error. can't use group by since it gives you too few rows.

Can anyone experts help?


回答1:


RE: the sorting 'bug', this is due to the way the application sorts. It sorts alphabetically; so 10 comes before 2, etc. This article shows a way to do "natural sorting" using LENGTH().

For this particular problem, I was able to get the correct answer using:

ORDER BY LENGTH(a.num), b.num, trans1.id, LENGTH(c.num), d.num;



回答2:


My solution to this problem: I divided the problem into two.

First subquery will be the table S(Start), which will get all the routes that start from 'Craiglockhart' Second subquery will be the table E(End), which will get all the routes that start from 'Sighthill'

Now both table S and E will have common routes, and i get all this common routes by joining the subqueries, using the ids of each table. As there are duplicates routes(same: S.num, S.company, stops.name, E.num, E.company) i used DISTINCT.

SELECT DISTINCT S.num, S.company, stops.name, E.num, E.company
FROM
(SELECT a.company, a.num, b.stop
 FROM route a JOIN route b ON (a.company=b.company AND a.num=b.num)
 WHERE a.stop=(SELECT id FROM stops WHERE name= 'Craiglockhart')
)S
  JOIN
(SELECT a.company, a.num, b.stop
 FROM route a JOIN route b ON (a.company=b.company AND a.num=b.num)
 WHERE a.stop=(SELECT id FROM stops WHERE name= 'Sighthill')
)E
ON (S.stop = E.stop)
JOIN stops ON(stops.id = S.stop)



回答3:


If you only want distinct rows, use the keyword DISTINCT:

SELECT DISTINCT  a.num, a.company, 
             trans1.name ,  c.num,  c.company
FROM route a JOIN route b
ON (a.company = b.company AND a.num = b.num)
JOIN ( route c JOIN route d ON (c.company = d.company AND c.num= d.num))
JOIN stops start ON (a.stop = start.id)
JOIN stops trans1 ON (b.stop = trans1.id)
JOIN stops trans2 ON (c.stop = trans2.id)
JOIN stops end ON (d.stop =  end.id)
WHERE  start.name = 'Craiglockhart' AND end.name = 'Sighthill'
            AND  trans1.name = trans2.name 
ORDER BY a.num ASC , trans1.name

The manual states:

The ALL and DISTINCT options specify whether duplicate rows should be returned. ALL (the default) specifies that all matching rows should be returned, including duplicates. DISTINCT specifies removal of duplicate rows from the result set. It is an error to specify both options. DISTINCTROW is a synonym for DISTINCT.




回答4:


Try this out, it works!

SELECT DISTINCT  a.num, a.company, 
         trans1.name,  d.num,  d.company
FROM route a JOIN route b
ON (a.company = b.company AND a.num = b.num)
JOIN route c ON (b.stop=c.stop AND b.num!=c.num)
JOIN route d on (c.company = d.company AND c.num = d.num)
JOIN stops start ON (a.stop=start.id)
JOIN stops trans1 ON (b.stop = trans1.id)
JOIN stops trans2 ON (c.stop = trans2.id)
JOIN stops end ON (d.stop =  end.id)
WHERE  start.name = 'Craiglockhart' AND end.name = 'Sighthill'
AND  trans1.name = trans2.name order by length(a.num), a.num



回答5:


SELECT DISTINCT sub1.num, 
                sub1.company, 
                name, 
                sub2.num, 
                sub2.company 
FROM   (SELECT r1.num, 
               r1.company, 
               r1.stop AS first, 
               r2.stop AS mid 
        FROM   route r1 
               JOIN route r2 
                 ON r1.num = r2.num 
                    AND r1.company = r2.company 
        WHERE  r1.stop = (SELECT id 
                          FROM   stops 
                          WHERE  name = 'Craiglockhart'))sub1 
       JOIN (SELECT r3.num, 
                    r3.company, 
                    r3.stop AS mid2, 
                    r4.stop AS dest 
             FROM   route r3 
                    JOIN route r4 
                      ON r3.num = r4.num 
                         AND r3.company = r4.company 
             WHERE  r4.stop = (SELECT id 
                               FROM   stops 
                               WHERE  name = 'Sighthill'))sub2 
         ON sub1.mid = sub2.mid2 
       JOIN stops 
         ON id = sub1.mid 



回答6:


SELECT DISTINCT x.num,x.company,x.name,y.num,y.company 
FROM 
(
SELECT a.num as num,a.company as company,sb.name as name
FROM route a
JOIN route b
    ON a.company = b.company AND a.num = b.num
JOIN stops sa
    ON sa.id = a.stop
JOIN stops sb
    ON sb.id = b.stop
WHERE 
    sa.name = 'Craiglockhart'
) x

JOIN 

(
SELECT a.num as num, a.company as company,sb.name as name
FROM route a
JOIN route b
    ON a.company = b.company AND a.num = b.num
JOIN stops sa
    ON sa.id = a.stop
JOIN stops sb
    ON sb.id = b.stop
WHERE sa.name = 'Sighthill'
) y

ON x.name = y.name



回答7:


Please check a possible solution:

SELECT distinct StartOfR1.num, StartOfR1.company, Xfer.name xfer_name,  EndOfR2.num, EndOfR2.company
FROM stops Start, stops Xfer, stops Finish, route StartOfR1, route EndOfR1, route StartOfR2, route EndOfR2 
WHERE Start.name='Craiglockhart' AND Finish.name='Sighthill' AND StartOfR1.stop= Start.id -- R1 actually visits Start 
AND EndOfR1.num = StartOfR1.num  -- no transfer on the same route 
AND EndOfR1.stop= StartOfR2.stop   -- R2 starts where R1 ends 
AND EndOfR1.num != StartOfR2.num -- R1 and R2 are not the same route 
AND EndOfR1.stop = Xfer.id-- R1 changes to R2 
AND EndOfR2.company = StartOfR2.company -- R1 changes bus to R2 
AND EndOfR2.num = StartOfR2.num  -- two stops on the same route 
AND EndOfR2.stop = Finish.id -- R2 actually visits Finish;

Source.



来源:https://stackoverflow.com/questions/24834948/self-join-tutorial-10-on-sqlzoo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!