quiz_1.sql 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. -- -----------------------------------------------------------------
  2. -- Задания
  3. -- -----------------------------------------------------------------
  4. -- 11.16 Выборка данных из других источников
  5. -- Выборка из подзапроса
  6. select genus_name from (
  7. select * from genus
  8. );
  9. -- Выборка анбора дат с интервалом в 2 месяца
  10. select date
  11. from generate_series('2020-01-01'::date,
  12. '2024-06-01'::date,
  13. '2 month'::interval) date;
  14. --
  15. select * from (values
  16. ('The Shawshank Redemption', 9.3, 1994),
  17. ('The Godfather', 9.2, 1972),
  18. ('The Dark Knight', 9.1, 2008),
  19. ('Inception', 8.8, 2010)
  20. ) t(movie, imdb_rating, year);
  21. -- -----------------------------------------------------------------
  22. -- 11.18 Фильтрация данных
  23. table family;
  24. select * from family where family_name='Дроздовые';
  25. select * from family where family_name='Дроздовые' or family_name='Синицевые';
  26. select * from family where family_name in ('Дроздовые', 'Синицевые');
  27. select * from family where family_name like '%а%';
  28. select * from family where family_name like '%а%' or family_name like '%с%';
  29. select * from family where family_name ilike '%а%';
  30. -- -----------------------------------------------------------------
  31. -- 11.19 Особое значение NULL, coalesce
  32. select family_id, family_name, coalesce(description, 'не заполнено') as description from family;
  33. select * from family where description is null;
  34. select * from family where description is null or family_name like '%Д%';
  35. -- -----------------------------------------------------------------
  36. -- 11.20 Сортировка данных
  37. select * from family order by family_id;
  38. select * from family order by description nulls first;
  39. select * from family order by sescription nulls last;
  40. select family_name from family where family_name like 'Д%' order by family_name;
  41. -- -----------------------------------------------------------------
  42. -- 11.21 Ограничение количества результатов запроса
  43. table species;
  44. select * from species order by species_name, description
  45. limit 10 offset 10;
  46. select species_id, species_name from species where primary_color ilike '%бел%'
  47. order by species_name
  48. limit 5;
  49. -- -----------------------------------------------------------------
  50. -- 11.22 Измененяем данные в БД
  51. select 'Птичка: ' || species_name птичка from species order by species_name;
  52. -- или через функцию format
  53. select format('Птичка: %s', species_name) as 'птичка'
  54. from species order by species_name;
  55. -- Обновить записа
  56. update species set species_name='Древесный дрозд'
  57. where species_name='Дрозд лесной';
  58. -- Удалить таблицу. Но команда упадет с ошибкой если таблицы нет или если
  59. -- на таблицу ссылается другая таблица.
  60. drop table something;
  61. -- Удалить таблицу. Но команда упадет если на таблицу ссылается другая таблица.
  62. drop table if exists something;
  63. -- Удалить таблицу.
  64. drop table if exists something cascade;
  65. -- Создание таблицы из данных другой таблицы
  66. create temp table crows as
  67. select * from species where genus_id=(
  68. select genus_id from genus where genus_name='Ворон');
  69. -- Создание таблицы из данных другой таблицы
  70. select * into crows from species s where s.genus_id=(
  71. select genus_id from genus g where g.genus_name='Ворон'
  72. );
  73. -- Обновление данных в таблице
  74. create table smth (a int);
  75. update smth set a = a * 2;
  76. -- -----------------------------------------------------------------
  77. -- 11.26 Работа со строками
  78. select species_name from species
  79. order by length(species_name) desc, species_name limit 5;
  80. -- -----------------------------------------------------------------
  81. -- 11.28 Работа со перечислениями
  82. create table color (
  83. name varchar(22) primary key check (name in (
  84. 'адовый красный',
  85. 'ядерный зеленый',
  86. 'подозрительная мурена'
  87. ))
  88. );
  89. create table color (
  90. name text check (length(name) between 4 and 20)
  91. );
  92. -- -----------------------------------------------------------------
  93. -- 11.29 Работа со временем
  94. select to_char(created_at, 'DD.MM.YYYY HH24:MI:SS') "дата инцидента",
  95. message "сообщение" from log;
  96. insert into log (created_at, message) values
  97. ('2024-07-31 20:19:51'::timestamp, 'Произошло страшное: сломался приём платежа #1128'),
  98. ('2024-07-31 17:19:52'::timestamp, 'Трындец с отправкой почты, похоже, почтовый сервер недоступен!'),
  99. ('2024-07-31 17:20:53'::timestamp, 'Ужас, всё работает!');
  100. drop table if exists log;
  101. create temp table log(
  102. log_id bigint generated always as identity,
  103. created_at timestamp not null,
  104. message text not null
  105. );
  106. insert into log (created_at, message) values
  107. ('2024-06-02 20:20:20'::timestamp, 'Это событие за прошлый год'),
  108. ('2025-06-02 20:20:20'::timestamp, 'Это событие за текущий год');
  109. table log;
  110. select * from log where extract(month from(created_at)) = extract(month from now())
  111. and extract(year from(created_at)) = extract(year from now());
  112. -- Вернуть данные за этот месяц
  113. select * from log
  114. where date_trunc('month', created_at) = date_trunc('month', current_timestamp)
  115. order by log_id;
  116. -- Вернуть данные за последнюю неделю
  117. select * from log where created_at >= current_date - interval '7 days'
  118. -- Удалить данные за последние 30 дней
  119. delete from log
  120. where created_at < current_date - intercal '30 days';
  121. -- Прибавить месяц
  122. select '2024-01-31'::date + '1 month'::interval;
  123. -- Прибавить год
  124. select '2024-02-29'::date + '1 year'::interval;
  125. -- Эти запросы вернут одинаковое значение
  126. select '2024-02-28'::date - '1 year'::interval;
  127. select '2024-02-29'::date - '1 year'::interval;
  128. -- Запрос вернет ответ типа integer
  129. select '2024-02-01'::date - '2023-01-01'::date d;
  130. -- Запрос вернет ответи типа interval
  131. select '2024-02-01'::timestamp - '2023-01-01'::timestamp d;
  132. -- Форматирование даты
  133. select
  134. to_char(start, 'DD.MM.YYYY') start,
  135. to_char(finish, 'DD.MM.YYYY') finish
  136. extract(day from (finish - start) delta_in_days
  137. from records order by start, finish;
  138. -- С помощью функции age можно вывести дельту
  139. select
  140. to_char(start, 'DD.MM.YYYY') start,
  141. to_char(finish, 'DD.MM.YYYY') finish
  142. age(finish, start) delta
  143. from records order by start, finish;
  144. -- Достает email тех у кого в апреле день рождения
  145. select email from employees
  146. where extract('month' from birthday)=4
  147. order by email;
  148. -- -----------------------------------------------------------------
  149. -- 11.31 Работа с массивами
  150. drop table if exists log;
  151. table log;
  152. create temp table log (
  153. log_id bigint generated always as identity,
  154. created_at timestamp not null default current_timestamp,
  155. messages text not null
  156. );
  157. insert into log (created_at, messages) values(
  158. '2024-08-01 00:47:28.821', 'кажется, всё пропало|или нет, пытаемся восстановить связь|нет, точно всё пропало'
  159. );
  160. insert into log (created_at, messages) values(
  161. '2024-08-01 01:06:21.581', 'id=128|ничоси, опять всё сломалось, никогда такого не было и вот опять'
  162. );
  163. select log_id, created_at, (string_to_array(messages, '|'))
  164. [array_length(string_to_array(messages, '|'), 1)] as last_message
  165. from log;
  166. select log_id, created_at,
  167. split_part(messages, '|', array_length(string_to_array(messages, '|'), 1)) as last_message
  168. from log;
  169. select log_id, created_at, split_part(messages, '|', -1) as last_message from log;
  170. --
  171. select unnest(string_to_array(messages, '|')) as messages from log;
  172. select int_array from some_entity where 777=any(int_array);
  173. select unnest(string_to_array(messages, '|')) from log;
  174. select unnest as messages from (select unnest(string_to_array(messages, '|')) from log)
  175. where unnest like '%всё%';
  176. -- более короткое решение
  177. select t.* from (
  178. select unnest(string_to_array(messages, '|') messages
  179. from log
  180. ) t where t.messages '%всё%';
  181. -- -----------------------------------------------------------------
  182. -- 11.33 Работа с JSON и JSONB
  183. drop table if exists book_json;
  184. create temp table book_json (
  185. book_id bigint generated always as identity primary key,
  186. data jsonb not null
  187. );
  188. -- Данные в поле data (jsonb) могут различаться
  189. insert into book_json (data) values
  190. ('{"name": null}'),
  191. ('{"name": ""}'),
  192. ('{"name": "Тихий Дон"}'),
  193. ('{"name": 777}'),
  194. ('{}');
  195. table book_json;
  196. select book_id, data from book_json where data ? 'name';
  197. select book_id, data from book_json where data->>'name' is not null;
  198. select book_id, data from book_json where length(data->>'name') > 0;
  199. -- или вот такой вариант
  200. select * from book_json
  201. where data->>'name' is not null and data->>'name' != '';
  202. -- Создание таблицы с ограничениями по jsonb
  203. create table book_json(
  204. book_id bigint generated always as identity primary key,
  205. data jsonb not null check (
  206. data->>'name' is not null and
  207. data->>'pages' is not null and
  208. (data->>'pages')::int > 0
  209. )
  210. );
  211. -- -----------------------------------------------------------------
  212. -- 11.33 Изменение структуры таблиц
  213. -- Добавить ограничение на таблицу
  214. alter table book_json add check (
  215. data->>'name' is not null and
  216. data->>'pages' is not null and
  217. (data->>'pages')::int > 0
  218. );
  219. -- Добавить колонку к таблице
  220. alter table book_json
  221. add column created_at timestamp not null default current_timestamp;
  222. alter table book_json
  223. add column created_at timestamp not null default now();
  224. -- -----------------------------------------------------------------
  225. -- 11.38 INNER JOIN
  226. table species;
  227. table genus;
  228. select species_name as вид, genus_name as род from species
  229. join genus using(genus_id)
  230. order by species_name;
  231. -- Другие условия
  232. select species_name вид, genus_name род
  233. from species s join genus g on s.genus = g.genus_id
  234. order by species_name;
  235. --
  236. drop table if exists client, payment cascade;
  237. create temp table client (
  238. client_id bigint generated always as identity primary key,
  239. email varchar(360) not null
  240. );
  241. create temp table payment (
  242. payment_id bigint generated always as identity primary key,
  243. payment_time timestamp not null default current_timestamp,
  244. amount int not null check (amount > 0),
  245. client_id bigint not null references client(client_id)
  246. );
  247. insert into client (email) values
  248. ('client1@mail.ru'),
  249. ('client2@mail.ru'),
  250. ('client3@mail.ru');
  251. insert into payment (payment_time, amount, client_id) values
  252. ((now() - '1 month'::interval), 10, 1),
  253. ((now() - '2 month'::interval), 11, 2),
  254. ((now() - '3 month'::interval), 12, 3);
  255. select email from client
  256. join payment using(client_id)
  257. where payment_time::date + interval '1 month' = current_date
  258. order by email
  259. table species;
  260. table genus;
  261. table family;
  262. select s.species_name вид, g.genus_name род
  263. from species s
  264. join genus g on s.genus_id = g.genus_id
  265. order by s.species_name;
  266. -- -----------------------------------------------------------------
  267. -- 11.39 LEFT И RIGHT OUTER JOIN
  268. table species;
  269. table genus;
  270. select species_name вид, genus_name род
  271. from species s left join genus g using(genus_id)
  272. order by species_name;
  273. -- -----------------------------------------------------------------
  274. -- 11.40 FULL OUTER JOIN
  275. select species_name вид, genus_name род
  276. from species s full join genus g using(genus_id)
  277. order by species_name;
  278. select s.species_name вид, g.genus_name род
  279. from species s
  280. full join genus g using(genus_id)
  281. order by s.species_name;
  282. -- -----------------------------------------------------------------
  283. -- 11.44 JOIN LATERAL
  284. table species;
  285. table genus;
  286. table family;
  287. table observations;
  288. select
  289. species_name,
  290. to_char(last_observation.date, 'DD.MM.YYYY') last_observation
  291. from species left join lateral (
  292. select observation_date as date
  293. from observations
  294. where observations.species_id = species.species_id
  295. order by observation_date desc
  296. limit 1
  297. ) as last_observation on true
  298. order by species_name;
  299. -- -----------------------------------------------------------------
  300. -- 11.44 SEMI JOIN
  301. select species_name from species s
  302. where exists (
  303. select 1
  304. from observations o
  305. where o.species_id=s.species_id
  306. and extract('year' from observation_date)=2019
  307. ) order by species_name;
  308. select observer_name, observation_date
  309. from observations o, species s, genus g, family f
  310. where o.species_id = s.species_id and
  311. s.genus_id = g.genus_id and
  312. g.family_id = f.family_id and
  313. f.family_name = 'Синицевые'
  314. order by observer_name;
  315. --
  316. select family_id from family where family_name='Синицевые'
  317. table genus;
  318. select genus_id from genus g where exists (
  319. select 1
  320. from family f
  321. where family_name='Синицевые'
  322. and f.family_id=g.family_id
  323. );
  324. select species_id from species s where exists (
  325. select genus_id from genus g where exists (
  326. select 1
  327. from family f
  328. where family_name='Синицевые'
  329. and f.family_id=g.family_id
  330. ) and g.genus_id=s.genus_id
  331. );
  332. select observer_name, observation_date from observations o
  333. where exists (
  334. select 1 from species s where exists (
  335. select 1 from genus g where exists (
  336. select 1
  337. from family f
  338. where family_name='Синицевые'
  339. and f.family_id=g.family_id
  340. ) and g.genus_id=s.genus_id
  341. ) and s.species_id = o.species_id
  342. ) order by observer_name;
  343. select observer_name, observation_date from observations
  344. join species s using(species_id)
  345. join genus g using(genus_id)
  346. join family f using(family_id)
  347. where family_name = 'Синицевые'
  348. order by observer_name;
  349. -- -----------------------------------------------------------------
  350. -- Разное
  351. select div(11, 5);
  352. select extract(years from '2234-02-23'::date) as year;
  353. SELECT LENGTH('sql-academy') AS str_length;