在sqlzoo上自学加入#10教程

时间:2014-07-18 22:57:40

标签: mysql sql join self-join

我试过http://sqlzoo.net/wiki/Self_join

#10

的自加入会话

#10:找到可以从Craiglockhart到Sighthill的两辆公共汽车的路线。显示公交车号码。和第一辆公共汽车的公司,转移的停止的名称,和公共汽车号码。第二辆公共汽车的公司。

这是我的代码:

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

我知道输出会给你多行,如:

    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

你想要的地方:

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

还有一个错误,当我尝试a.num时,ASC的顺序不起作用。 此外,当我在DISTINCT之前放置c.num时,它显示错误。 不能使用group by,因为它会给你太少的行。

任何专家都可以提供帮助吗?

11 个答案:

答案 0 :(得分:3)

我解决这个问题的方法: 我把问题分成两部分。

  

第一个子查询将是表S(开始),它将获得所有   从Craiglockhart'开始的路线第二个子查询将是   表E(结束),它将获得从中开始的所有路线   ' Sighthill'

现在表S和E都有公共路由,我通过使用每个表的id加入子查询来获得所有这些常见路由。 因为有重复的路线(相同:S.num,S.company,stops.name,E.num,E.company)我使用了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)

答案 1 :(得分:1)

如果您只想要不同的行,请使用关键字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

manual states

  

ALL和DISTINCT选项指定是否应该有重复的行   回。 ALL(默认值)指定所有匹配的行应该是   返回,包括重复。 DISTINCT指定删除   结果集中的重复行。指定两者都是错误的   选项。 DISTINCTROW是DISTINCT的同义词。

答案 2 :(得分:1)

RE:排序'bug',这是由于应用程序的排序方式。它按字母顺序排序;所以10在2之前出现,等等This article显示了一种使用LENGTH()进行“自然排序”的方法。

对于这个特殊问题,我能够使用以下方法得到正确的答案:

ruby-2.1.1 [ x86_64 ]
ruby-2.1.4 [ x86_64 ]
=* ruby-2.2.2 [ x86_64 ]

答案 3 :(得分:1)

如果有人可以以人类的口头更深入地谈论这个问题,我会很高兴。

两个地方之间没有直达巴士 (在我的情况下,克雷格洛克哈特飞往洛亨德) 我通过首先进行另一个查询得出了这个结论。 (就像第六个问题一样)

所以我先查询了第一个城市,然后又查询了第二个城市,然后在他们匹配的站点上将它们合并在一起。之后,我们需要选择所需的列。 这是我自己的答案:

SELECT 
  firstbus.busnumber AS 'num', 
  firstbus.company, 
  secondbus.transfer AS 'name', 
  secondbus.busnumber AS 'num', 
  secondbus.company 
FROM (
  SELECT r1.num AS 'busnumber', 
  r1.company AS 'company', 
  r2.stop AS 'stopp' 
  FROM route r1 
  JOIN route r2 ON (r1.num = r2.num AND r1.company = r2.company) 
  JOIN stops s1 ON s1.id = r1.stop
  JOIN stops s2 ON s2.id = r2.stop
  WHERE s1.name = 'Craiglockhart'
  ) firstbus
  JOIN
  (
  SELECT s1.name AS 'transfer', 
  r1.num AS 'busnumber', 
  r1.company AS 'company', 
  r1.stop AS 'stopp', 
  r1.pos AS 'pos' 
  FROM route r1 JOIN route r2 ON (r1.num = r2.num AND r1.company = r2.company) 
  JOIN stops s1 ON s1.id = r1.stop
  JOIN stops s2 ON s2.id = r2.stop
  WHERE s2.name = 'Lochend'
  ) secondbus
  ON firstbus.stopp = secondbus.stopp
ORDER BY firstbus.busnumber, name, 4;

以我所有的敬意...

答案 4 :(得分:1)

发布时,这是更新的问题:

Find the routes involving two buses that can go from Craiglockhart to Lochend.
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.

请注意,目的地已更改为午餐(147)。以下查询在发布时产生正确的结果:

SELECT DISTINCT bus1.num, bus1.company, transfer.name, bus2.num, bus2.company
 FROM route bus1 JOIN route midA ON (bus1.num = midA.num AND bus1.company = midA.company)
                 JOIN route midD ON (midA.stop = midD.stop)
                 JOIN route bus2 ON (midD.num = bus2.num AND midD.company= bus2.company)
                 JOIN stops transfer ON (midA.stop = transfer.id)
 WHERE bus1.stop = 53 AND bus2.stop = 147
 ORDER BY bus1.company, bus1.num, midA.stop, bus2.num

请注意,最后的ORDER BY会重新组织输出以适合目标结果。

答案 5 :(得分:0)

试试这个,它有效!

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

答案 6 :(得分:0)

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 

答案 7 :(得分:0)

e->add_handler

答案 8 :(得分:0)

我使用下面的代码。 a,b用于第一条总线,c,d用于第二条总线。 和b,c使用相同的挡块进行连接。

SELECT a.num, a.company, stopb.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)
             JOIN route d ON (d.company = c.company AND c.num = d.num)
             JOIN stops stopa ON a.stop = stopa.id
             JOIN stops stopb ON b.stop = stopb.id
             JOIN stops stopc ON c.stop = stopc.id
             JOIN stops stopd ON d.stop = stopd.id
WHERE stopa.name = 'Craiglockhart'
AND stopd.name = 'Lochend'

答案 9 :(得分:0)

我使用下面的代码,网站接受了它作为正确答案:

“一个”代表第一辆公共汽车; “第二”代表第二条总线。

select distinct 
#one.start,
#two.end,
one.num,
one.company,
one.transfer as name, 
two.num,
two.company
from
(select distinct -- make sure you use select distinct here or else you will get an error "The SELECT would examine more than MAX_JOIN_SIZE rows”
a.num,
a.company,
stopsa.name as start,
stopsb.name as transfer,
stopsb.id as transferid
from route a 
inner join route b
on (a.num = b.num and a.company = b.company)
join stops stopsa on (stopsa.id = a.stop) 
join stops stopsb on (stopsb.id = b.stop)
where stopsa.name = 'Craiglockhart' and stopsb.name != 'Lochend' -- we don't want the first bus to lead us directly to 'Lochend'
) one

join 

(select distinct
c.num,
c.company,
stopsc.name as transfer,
stopsd.name as end
from route c
inner join route d
on c.num = d.num and c.company = d.company
join stops stopsc on stopsc.id = c.stop
join stops stopsd on stopsd.id = d.stop
where stopsd.name = 'Lochend' and stopsc.name != 'Craiglockhart' -- we don't want the second bus to go from Craiglockhart to Lochend
) two
on two.transfer = one.transfer -- first bus and second bus' overlap --> the transfer stop!
ORDER BY one.company, one.num, one.transfer, two.num -- i addded this final statement just to tailor my code to fit the correct answer. think this is a bug with sqlzoo.

答案 10 :(得分:-1)

请检查可能的解决方案:

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