/
sql-39-final.sql
247 lines (229 loc) · 11.9 KB
/
sql-39-final.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
set search_path to bookings;
-- 1 В каких городах больше одного аэропорта?
/*
* Группирую таблицу аэропортов по городу и вывожу только те, у которых количество airport_code больше 1
*/
select city "Город"
from airports a
group by city
having count(airport_code) > 1;
-- 2 В каких аэропортах есть рейсы, выполняемые самолетом с максимальной дальностью перелета?
-- - Подзапрос
/*
* Подзапрос получает код самолета с самыой большой дальностью (с помощью сортировки и ограничения вывода).
* Далее в основном запросе указывается условие соответствия самолета.
* Основной запрос получает имя аэропорта по джойну с таблицей перелётов
*/
select distinct
a.airport_name "Аэропорт"
from airports a
join flights f on a.airport_code = f.departure_airport
where f.aircraft_code = (
select a.aircraft_code
from aircrafts a
order by a."range" desc limit 1
);
-- 3 Вывести 10 рейсов с максимальным временем задержки вылета - Оператор LIMIT
/*
* Отбираю только те рейсы, которые вылетели (actual_departure заполнено)
* Задержка считается простым вычитанием.
* Наконец, сортировка по убыванию и ограничение вывода
*/
select
f.flight_id,
f.scheduled_departure,
f.actual_departure,
f.actual_departure - f.scheduled_departure "Задержка"
from flights f
where f.actual_departure is not null
order by "Задержка" desc
limit 10;
-- 4 Были ли брони, по которым не были получены посадочные талоны? - Верный тип JOIN
/*
* Left join, т.к. нужно полное множество броней.
* Джойню таблицу tickets т.к. таблица броней связывается с талонами через билет.
*/
select
case when count(b.book_ref) > 0 then 'Да'
else 'Нет'
end "Наличие броней без пт",
count(b.book_ref) "Их количество"
from bookings b
join tickets t on t.book_ref = b.book_ref
left join boarding_passes bp on bp.ticket_no = t.ticket_no
where bp.boarding_no is null;
-- 5 Найдите свободные места для каждого рейса, их % отношение к общему количеству мест в самолете.
-- Добавьте столбец с накопительным итогом - суммарное накопление количества вывезенных пассажиров из каждого аэропорта на каждый день.
-- Т.е. в этом столбце должна отражаться накопительная сумма - сколько человек уже вылетело из данного аэропорта на этом или более ранних рейсах за день.
-- - Оконная функция
-- - Подзапросы или cte
/*
* CTE boarded получает количество выданных посадочных талонов по каждому рейсу
* Ограничение actual_departure is not null для того, чтобы отслеживать уже вылетевшие рейсы
* CTE max_seats_by_aircraft получает количество мест в самолёте
* В итоговом запросе оба CTE джойнятся по aircraft_code
* Для подсчета накопительной суммы использется оконная функция c разделением по аэропорту отправления и времени вылета приведенному к формату date.
*/
with boarded as (
select
f.flight_id,
f.flight_no,
f.aircraft_code,
f.departure_airport,
f.scheduled_departure,
f.actual_departure,
count(bp.boarding_no) boarded_count
from flights f
join boarding_passes bp on bp.flight_id = f.flight_id
where f.actual_departure is not null
group by f.flight_id
),
max_seats_by_aircraft as(
select
s.aircraft_code,
count(s.seat_no) max_seats
from seats s
group by s.aircraft_code
)
select
b.flight_no,
b.departure_airport,
b.scheduled_departure,
b.actual_departure,
b.boarded_count,
m.max_seats - b.boarded_count free_seats,
round((m.max_seats - b.boarded_count) / m.max_seats :: dec, 2) * 100 free_seats_percent,
sum(b.boarded_count) over (partition by (b.departure_airport, b.actual_departure::date) order by b.actual_departure) "Накопительно пассажиров"
from boarded b
join max_seats_by_aircraft m on m.aircraft_code = b.aircraft_code;
-- 6 Найдите процентное соотношение перелетов по типам самолетов от общего количества. - Подзапрос
-- - Оператор ROUND
/*
* Используется подзапрос для получения общего числа полетов (проверяем, вылетел ли самолет при подсчете)
* В основном запросе используется группировка по полю model
*/
select
a.model "Модель самолета",
count(f.flight_id) "Количество рейсов",
round(count(f.flight_id) /
(select
count(f.flight_id)
from flights f
where f.actual_departure is not null
)::dec * 100, 4) "В процентах от общего числа"
from aircrafts a
join flights f on f.aircraft_code = a.aircraft_code
where f.actual_departure is not null
group by a.model;
-- 7 Были ли города, в которые можно добраться бизнес - классом дешевле, чем эконом-классом в рамках перелета?
-- - CTE
/*
* В CTE prices собираются стоимости билетов на рейс: максимальная для Эконома и минимальная для бизнеса.
* Затем из него отбираются эти стоимости и группируются в одну строку по каждому аэропорту - это внешний
* CTE eco_busi. Результаты фильтруются по сравнению полей b_min_amount и e_max_amount
* Далее этот CTE джойнится с таблицами рейсов и аэропортов, чтобы достать из них города отправления и прибытия.
* Судя по тому, что результат пустой, таких рейсов нет
*/
with eco_busi as (
with prices as(
select
f.flight_id,
case when tf.fare_conditions = 'Business' then min(tf.amount) end b_min_amount,
case when tf.fare_conditions = 'Economy' then max(tf.amount) end e_max_amount
from ticket_flights tf
join flights f on tf.flight_id = f.flight_id
group by
f.flight_id, tf.fare_conditions
)
select
p.flight_id,
min(p.b_min_amount),
max(p.e_max_amount)
from prices p
group by p.flight_id
having min(p.b_min_amount) < max(p.e_max_amount)
)
select
e.flight_id,
a.city depatrure_city,
a2.city arrival_city
from eco_busi e
join flights f on e.flight_id = f.flight_id
join airports a on f.departure_airport = a.airport_code
join airports a2 on f.arrival_airport = a2.airport_code
/*
* Этот вариант смотрит стоимость билета между городами без учета рейса
* CTE max_min_by_city формирует минимальную стоимость по бизнес классу и муксимальную по эконому
* с группировкой по городу отправления и прибытия и по классу билета.
* результаты его отправляются во внешний запрос, который собирает минимум и максимум по двум городам
* в одну строку. В итоговом условии выводятся только те строки, в которых min(b_min_amount) < max(e_max_amount).
* Таких строк нет, так что и в этом случае бизнес всегда дороже эконома
*/
with max_min_by_city as(
select
a.city dep_city,
a2.city arr_city,
tf.fare_conditions,
case when tf.fare_conditions = 'Business' then min(tf.amount) end b_min_amount,
case when tf.fare_conditions = 'Economy' then max(tf.amount) end e_max_amount
from flights f
join ticket_flights tf on tf.flight_id = f.flight_id
join airports a on f.departure_airport = a.airport_code
join airports a2 on f.arrival_airport = a2.airport_code
group by (1, 2), 3
)
select
dep_city "Из",
arr_city "В",
min(b_min_amount) "Минимум за бизнес",
max(e_max_amount) "Максимум за эконом"
from max_min_by_city
group by (1, 2)
having min(b_min_amount) < max(e_max_amount);
-- 8 Между какими городами нет прямых рейсов?
-- - Декартово произведение в предложении FROM
-- - Самостоятельно созданные представления
-- - Оператор EXCEPT
/*
* Создаю представление для получения городов, между которыми есть рейсы
* Два джойна в представлении для получения города отправления и города прибытия
* В основном запросе получаю декартово произведение всех городов, с условием их неравенства
* Затем из него убираю данные, которые есть в представлении.
*/
create view dep_arr_city as
select distinct
a.city departure_city,
a2.city arrival_city
from flights f
join airports a on f.departure_airport = a.airport_code
join airports a2 on f.arrival_airport = a2.airport_code;
select distinct
a.city departure_city,
a2.city arrival_city
from airports a, airports a2
where a.city != a2.city
except
select * from dep_arr_city
-- 9 Вычислите расстояние между аэропортами, связанными прямыми рейсами, сравните с допустимой максимальной дальностью перелетов
-- в самолетах, обслуживающих эти рейсы * - Оператор RADIANS или использование sind/cosd
-- - CASE
/*
* Опять два раза джойн таблицы аэропортов.
* Поле "Долетит?" заполняется по условию того, что рассчитанная дальность между городами меньше дальности самолета.
* Расстояние между городами делал по формуле из задания не особо задумываясь об этом
*/
select distinct
ad.airport_name "Из",
aa.airport_name "В",
a."range" "Дальность самолета",
round((acos(sind(ad.latitude) * sind(aa.latitude) + cosd(ad.latitude) * cosd(aa.latitude) * cosd(ad.longitude - aa.longitude)) * 6371)::dec, 2) "Расстояние",
case when
a."range" <
acos(sind(ad.latitude) * sind(aa.latitude) + cosd(ad.latitude) * cosd(aa.latitude) * cosd(ad.longitude - aa.longitude)) * 6371
then 'Нет!'
else 'Да!'
end "Долетит?"
from flights f
join airports ad on f.departure_airport = ad.airport_code
join airports aa on f.arrival_airport = aa.airport_code
join aircrafts a on a.aircraft_code = f.aircraft_code