问题
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