SQLZoo 自助加入教程

问题描述 投票:0回答:12

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

Self Join: 找到从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

还有一个bug,就是我试

a.num
ASC
的顺序不对

另外,当我将

DISTINCT
放在
c.num
之前时,它会显示错误。

我不能使用

group by
,因为它给出的行数太少。

为什么?

mysql sql join self-join
12个回答
4
投票

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

第一个子查询将是表 S(Start),它将获取所有 从“Craiglockhart”开始的路线第二个子查询将是 表 E(End),它将获取所有从 '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)

2
投票

RE:排序“错误”,这是由于应用程序排序的方式造成的。它按字母顺序排序;所以 10 在 2 之前,等等。这篇文章 展示了一种使用 LENGTH() 进行“自然排序”的方法。

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

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

2
投票

如果您只想要不同的行,请使用关键字

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

手册状态

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


2
投票

我使用下面的代码。 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'
-- if you use MySQL engine, you need order by to pass the problem
order by a.num, stopb.name, d.num 

正如@Eduardo06sp 评论的那样,我再次在 SQL Zoo 中测试此脚本,SQL Zoo 报告正确使用 Miscrosoft SQL 引擎,但报告错误的 MySQL 引擎没有

order by
.


1
投票

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

两地之间没有直达巴士 (在我的案例中,Craiglockhart 到 Lochend) 我通过先进行另一个查询得出了这个结论。 (如第6题)

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

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;

恕我直言...


1
投票

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

找到涉及从克雷格洛克哈特到洛兴德的两辆公共汽车的路线。 显示公交车号和第一辆公共汽车的公司,换乘站的名称, 和公共汽车号和第二辆公共汽车的公司。

请注意,目的地已更改为Lochend (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 重新组织输出以适应目标结果。


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

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 

0
投票
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

0
投票

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

“一”代表第一班车; “second”代表第二辆公交车

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.


0
投票

我通过运行以下查询得到了正确答案:

SELECT a.num,a.company,stopb.name,c.num,c.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 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' AND stopb.name=stopc.name
    ORDER BY cast(a.num as char),stopb.name,cast(c.num as char)

-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;

来源.

© www.soinside.com 2019 - 2024. All rights reserved.