我有这个数据库

aeroporto(1) <----> (n)volo(n) <----> (1)aereo

AEROPORTO: (pK)id_ap, città, naz, num_pist

VOLO: (pk)id_volo, data, (fk)id_part, oraPart, (fk)id_arr, oraArr, (fk)tipoAereo

AEREO: (pk)id_aereo, qta_merci, num_pass, cod_aereo


/ *从法国出发的二十多趟直航从法国城市出发* /

select a.citta

from volo as v, aereoporto as a, aereoporto as b

where a.id_ap = v.id_part and b.id_ap = v.id_arr and
a.nazione != b.nazione and a.nazione = 'francia' and count(b.citta = 'italia') > 20 ;


这是正确的?

对不起,我英语不好。

最佳答案

返回所有飞行次数> 20的离开“ francia”并到达“ italia”的城市的城市名称。

SELECT a.citta
FROM volo as v
INNER JOIN aereoporto as a
   on a.id_ap = v.id_part
INNER JOIN aereoporto as b
   on b.id_ap = v.id_arr
WHERE a.nazione = 'francia'
  and b.nazione = 'italia'
GROUP BY a.citta
HAVING count(v.id_volo) > 20 ;


GROUP BY允许我们从“ francia”中将类似的城市归为一组,而hading子句可以计算飞行次数,并确保仅显示飞行次数超过20的城市。

但是,这确实假设每个naz都没有重复citta。例如:如果同一名称的城市存在于francia的不同区域中;那就有问题了因此,如果有一个Paris Brittany和一个Paris Île-de-France,并且两个机场都有通行证;那么a.cittaParis将是两个巴黎城市的计数;这可能不是理想的结果。如果没有描述我们要分组的a.citta的唯一标识符,此问题可能会继续存在。因此,也许我们需要对a.cittaa.id_ap进行分组,并在选择项中同时显示它们,以便用户知道我们正在谈论的“哪个机场”。或者,我认为每个机场都分配有专门定义它的代码;如果那样作为机场信息的一部分被跟踪;我们可以对其进行分组,避免使用a.id_ap。仅凭城市本身不足以使记录保持唯一。

例:

SELECT a.citta, a.id_ap
FROM volo as v
INNER JOIN aereoporto as a
   on a.id_ap = v.id_part
INNER JOIN aereoporto as b
   on b.id_ap = v.id_arr
WHERE a.nazione = 'francia'
  and b.nazione = 'italia'
GROUP BY a.citta, a.id_ap
HAVING count(v.id_volo) > 20 ;


我不喜欢在from子句中使用交叉联接,这是from子句中的,表示法。这种连接样式是从1980年代开始的,应放弃使用,而使用innerleftrightfull outercross join的显式语法。

我的理由是FROM子句应定义正在使用的表以及它们在大多数情况下的关系。应该使用where子句限制返回的数据;混合两者会带来混乱和长期维护困难的代价。此规则的唯一例外是外部联接,它可能需要限制数据作为联接的一部分,以保持外部联接的完整性。

解决评论:
这样的事情可能会起作用:如果从城市机场起飞的航班总数与从意大利到达目的地的数量相匹配,则所有航班都是内部/国内航班;否则请勿显示该机场。因此,诸如where之类的have子句用作过滤器,以排除航班已从其他国家/地区出发或飞往其他国家/地区的城市。这种方法在执行的操作上有些模棱两可,但是从性能的角度来看,它应该比in(不存在)操作更好,否则子查询会在字段上给出适当的索引。

SELECT a.citta, a.id_ap
FROM volo as v
INNER JOIN aereoporto as a
   on a.id_ap = v.id_part
INNER JOIN aereoporto as b
   on b.id_ap = v.id_arr
GROUP BY a.citta, a.id_ap
HAVING count(v.id_volo) =  sum(case when a.nazione = 'italia' then 1 else 0 end as ItalianArrivals)
   and count(v.id_volo) =  sum(case when b.nazione = 'italia' then 1 else 0 end as ItalianDepartures);


鉴于上述含糊不清,下一个人的维护可能会有些困难,因此通过使用明确的不存在的方法,一次到达和一次离开都可以达到相同的结果;但是我不认为它会在性能上达到最佳……但是,它也可以达到正确的结果。在处理可以增长到超过50个值的数据集时,我更喜欢not exists而不是not in。由于查询与看起来将继续增长的数据集相关,因此不存在似乎是不存在的第二选择。我相信在较大的数据集上性能会更好。

关于mysql - 这个练习查询SQL是正确的吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52571045/

10-11 15:42