这个练习查询SQL是正确的吗?

时间:2018-09-29 17:55:28

标签: mysql database

我有这个数据库

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 ;

对吗?

对不起,我英语不好。

2 个答案:

答案 0 :(得分:0)

我几乎没有弄清楚您的示例以及您要检索的确切输出是什么,我认为以下内容将为您提供帮助。

SELECT a.citta
FROM aereoporto as a, volo as v
WHERE a.id_ap = v.id_part AND a.nazione = 'francia'
GROUP BY a.citta having count(*) > 20 ;

样机数据

机场

id_ap     citta     nazione
  1       rome      italia
  2       milan     italia
  3       paris     francia
  4       bordeaux  francia

volo

id_volo data    id_part oraPart id_arr  oraArr  tipoAereo
1       NULL       3    NULL       1    NULL    NULL
2       NULL       3    NULL       1    NULL    NULL
3       NULL       3    NULL       2    NULL    NULL
4       NULL       4    NULL       2    NULL    NULL
5       NULL       4    NULL       1    NULL    NULL

答案 1 :(得分:0)

返回所有飞行次数> 20的离开“法兰西”并到达“意大利”的城市的城市名称。

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.citta的{​​{1}}将是两个巴黎城市的计数;这可能不是理想的结果。如果没有描述Paris的唯一标识符(我们将其分组),则该问题可能会继续存在。因此,也许我们需要按a.cittaa.citta进行分组,并在选择项中同时显示两者,以便用户知道我们正在谈论的“哪个机场”。或者,我认为每个机场都分配有定义它的代码具体来说;如果将其作为机场信息的一部分进行跟踪,我们可以对其进行分组并避免使用a.id_ap。仅凭城市本身不足以使记录保持唯一性。

示例:

a.id_ap

我不喜欢在from子句中使用交叉联接,这是from子句中的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 ; 表示法。这种连接样式来自1980年代,应放弃使用,innerleftrightfull outer的显式语法。

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

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

cross join

鉴于以上所述的含糊不清,对于下一个人而言,维护可能会更加困难,因此,通过使用一次明确的不存在(一次到达和一次离开),您可以获得相同的结果;但是我不认为它会在性能上达到最佳……但是,它也可以达到正确的结果。在处理可能增长到超过50个值的数据集时,我更喜欢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); 胜过not exists。由于查询与看起来将继续增长的数据集相关,因此不存在似乎是不存在的第二选择。我相信在较大的数据集上性能会更好。