🐘 Руководство ΠΏΠΎ SQL для Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‰ΠΈΡ…. Π§Π°ΡΡ‚ΡŒ 3: услоТняСм запросы, ΠΈΠΌΠ΅Π½ΡƒΠ΅ΠΌ Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ запросы, Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ запроса

Π’ послСднСй части Ρ†ΠΈΠΊΠ»Π° статСй ΠΌΡ‹ составим слоТныС запросы, ΠΏΠΎΡ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ с Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΌΠΈ запросами, ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎ сохранности Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΎ нСобходимости индСксов.

Π‘Π°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ объСдинСниС (self join)

Иногда Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ситуация, ΠΊΠΎΠ³Π΄Π° для получСния Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… Π½Π°ΠΌ понадобится ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ саму с собой. Наглядный ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΏΠΎ этой ссылкС. Π‘ΡƒΡ‚ΡŒ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ, Ссли строки Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ содСрТат Π΄Π°Π½Π½Ρ‹Π΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ связаны с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΈΡ… строк этой ΠΆΠ΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ id), ΠΌΡ‹ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ join Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΊ Π½Π΅ΠΉ самой.

Π”Π°Π²Π°ΠΉΡ‚Π΅ для Π½Π°Ρ‡Π°Π»Π° Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΠΏΠΎΠ»Π΅ с ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΎΠΌ Π»ΡƒΡ‡ΡˆΠ΅Π³ΠΎ Π΄Ρ€ΡƒΠ³Π° best_friend_id Π² Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ ΡƒΡ‡Π΅Π½ΠΈΠΊΠΎΠ² ΠΈ вставим Π² Π½Π΅Π³ΠΎ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅.

ALTER TABLE students
ADD best_friend_id INT;

UPDATE students
SET best_friend_id = 5
WHERE id = 1;

UPDATE students
SET best_friend_id = 4
WHERE id = 2;

UPDATE students
SET best_friend_id = 2
WHERE id = 3;

UPDATE students
SET best_friend_id = 2
WHERE id = 4;

UPDATE students
SET best_friend_id = 1
WHERE id = 5;

SELECT * FROM students;

/*
 id  | name     | classroom_id | best_friend_id
 --- | -------- | ------------ | --------------
   1 | Adam     |            1 |              5
   2 | Betty    |            1 |              4
   3 | Caroline |            2 |              2
   4 | Dina     |       [null] |              2
   5 | Evan     |       [null] |              1
*/

Π˜Ρ‚Π°ΠΊ, Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ ΠΌΡ‹ Ρ…Ρ€Π°Π½ΠΈΠΌ id Π»ΡƒΡ‡ΡˆΠ΅Π³ΠΎ Π΄Ρ€ΡƒΠ³Π° для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡƒΡ‡Π΅Π½ΠΈΠΊΠ°. Π­Ρ‚ΠΎ эффСктивно, Π½ΠΎ Π½Π΅ ΠΎΡ‡Π΅Π½ΡŒ Ρ‡ΠΈΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎ. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, ΠΊΡ‚ΠΎ ΠΆΠ΅ являСтся Π»ΡƒΡ‡ΡˆΠΈΠΌ Π΄Ρ€ΡƒΠ³ΠΎΠΌ, Π½Π°ΠΌ придётся ΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ саму с собой. Π’ΠΎΠ·ΡŒΠΌΠ΅ΠΌ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ students ΠΈ сдСлаСм соСдинСниС (join) снова с Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ students, Π² качСствС ΠΊΠ»ΡŽΡ‡Π΅ΠΉ для связи Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ id студСнта ΠΈ id Π»ΡƒΡ‡ΡˆΠ΅Π³ΠΎ Π΄Ρ€ΡƒΠ³Π° (best_friend_id). ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ псСвдонимы Ρ‚Π°Π±Π»ΠΈΡ† x ΠΈ y для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ понимания ΠΊΠΎΠ΄Π°.

SELECT
    x.name,
    y.name AS best_friend
FROM
    students AS x
INNER JOIN
    students AS y
    ON y.id = x.best_friend_id;

/*
 name     | best_friend
 -------- | -----------
 Adam     | Evan
 Betty    | Dina
 Caroline | Betty
 Dina     | Betty
 Evan     | Adam
*/

ΠžΠΊΠΎΠ½Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ (Window functions)

ΠžΠΊΠΎΠ½Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΎΡ‡Π΅Π½ΡŒ ΠΏΠΎΡ…ΠΎΠΆΠΈ Π½Π° Π°Π³Ρ€Π΅Π³Π°Ρ‚Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ (group by) Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ для вычислСний сгруппированных Π½Π°Π±ΠΎΡ€ΠΎΠ² Π΄Π°Π½Π½Ρ‹Ρ…. Но Π² ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Π°Π³Ρ€Π΅Π³Π°Ρ‚Π½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΎΠΊΠΎΠ½Π½Ρ‹Π΅ Π½Π΅ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°ΡŽΡ‚ количСство строк Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°Ρ… запроса.

Π”Π°Π²Π°ΠΉΡ‚Π΅ вычислим срСдний Π±Π°Π»Π» для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡƒΡ‡Π΅Π½ΠΈΠΊΠ°. На строках с Ρ‡Π΅Ρ‚Π²Π΅Ρ€Ρ‚ΠΎΠΉ ΠΏΠΎ ΡˆΠ΅ΡΡ‚ΡƒΡŽ Π² запросС Π½ΠΈΠΆΠ΅ ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ OVER ΠΈ PARTITION BY, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ· Π°Π³Ρ€Π΅Π³Π°Ρ‚Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΎΠΊΠΎΠ½Π½ΡƒΡŽ.

SELECT
    s.name,
    g.score,
    AVG(g.score) OVER (
        PARTITION BY s.name
    )
FROM
    students AS s
INNER JOIN
    grades AS g
    ON s.id = g.student_id;

/*
 name  | score | avg
 ------| ----- | ----------
 Adam  |    82 | 80.8000...
 Adam  |    82 | 80.8000...
 Adam  |    80 | 80.8000...
 Adam  |    75 | 80.8000...
 Adam  |    85 | 80.8000...
 Betty |    74 | 70.4000...
 Betty |    75 | 70.4000...
 ...   |   ... |        ...
*/

Для Π°Π³Ρ€Π΅Π³ΠΈΡ€ΡƒΡŽΡ‰ΠΈΡ… ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² AVG, MIN, ΠΈΠ»ΠΈ MAX, каТдая строка Π² Π³Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²ΠΊΠ΅ PARTITION BY Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅. Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, для ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Ρ… Π²ΠΈΠ΄ΠΎΠ² Π°Π½Π°Π»ΠΈΠ·Π° это ΠΈ понадобится, Π½ΠΎ Π½Π° самом Π΄Π΅Π»Π΅, сила ΠΎΠΊΠΎΠ½Π½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π² Π΄Ρ€ΡƒΠ³ΠΎΠΌ.

Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ранТирования Π΄Π°Π½Π½Ρ‹Ρ… Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ΠΉ случай. ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ это с ΠΎΡ†Π΅Π½ΠΊΠ°ΠΌΠΈ Π½Π°ΡˆΠΈΡ… ΡƒΡ‡Π΅Π½ΠΈΠΊΠΎΠ². Π§Ρ‚ΠΎΠ±Ρ‹ Ρ€Π°Π½ΠΆΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡ†Π΅Π½ΠΊΠΈ всСх ΡƒΡ‡Π΅Π½ΠΈΠΊΠΎΠ² ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ RANK() OVER, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΄ΠΈΠΌ Π½ΡƒΠΆΠ½Ρ‹ΠΉ Π½Π°ΠΌ столбСц.

SELECT
    s.name,
    g.score,
    RANK() OVER (
        ORDER BY g.score
    )
FROM
    grades AS g
INNER JOIN
    students AS s
    ON s.id = g.student_id;

/*
 name  | score | rank
 ----- | ----- | ----
 Betty |    64 |    1
 Dina  |    64 |    1
 Evan  |    67 |    3
 ...   |   ... |  ...
*/

Π”ΠΎΠ±Π°Π²ΠΈΠΌ всСго ΠΎΠ΄Π½Ρƒ строку Π² наш запрос, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ PARTITION BY s.name ΠΊ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Ρƒ OVER. Π’ ΠΈΡ‚ΠΎΠ³Π΅ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ Ρ€Π°Π½ΠΆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π² Ρ€Π°ΠΌΠΊΠ°Ρ… ΠΎΠ΄Π½ΠΎΠ³ΠΎ студСнта.

SELECT
    s.name,
    g.score,
    RANK() OVER (
        PARTITION BY s.name  -- ranks by student
        ORDER BY g.score
    )
FROM
    grades AS g
INNER JOIN
    students AS s
    ON s.id = g.student_id;

/*
 name     | score | rank
 -------- | ----- | ----
 Adam     |    75 |    1
 Adam     |    80 |    2
 Adam     |    82 |    3
 Adam     |    82 |    3
 Adam     |    85 |    5
 Betty    |    64 |    1
 Betty    |    69 |    2
 Betty    |    70 |    3
 Betty    |    74 |    4
 Betty    |    75 |    5
 Caroline |    90 |    1
 Caroline |    92 |    2
 ...      |   ... |  ...
*/

Π£ ΠΎΠΊΠΎΠ½Π½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π΅ΡΡ‚ΡŒ Π΅Ρ‰Π΅ нСсколько интСрСсных возмоТностСй. НапримСр, Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ распрСдСлСния cumulative distribution, Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ dense ΠΈ percent ranks. dense_rank – функция Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ€Π°Π½Π³ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ строки, Π½ΠΎ Π² ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ RANK, ΠΎΠ½Π° для ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Ρ… Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ€Π°Π½Π³, Π½Π΅ пропуская ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ. Π‘ функциями lag ΠΈ lead Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ ΠΎΠ·Π½Π°ΠΊΠΎΠΌΠΈΡ‚ΡŒΡΡ ΠΏΠΎ ссылкС.

ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ WITH

Π”Π°Π²Π°ΠΉΡ‚Π΅ познакомимся Π΅Ρ‰Π΅ с ΠΎΠ΄Π½ΠΈΠΌ инструмСнтом – ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠ΅ Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Ρ… запросов. ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ WITH позволяСт Π½Π°ΠΌ ΠΏΡ€ΠΈΡΠ²Π°ΠΈΠ²Π°Ρ‚ΡŒ имя Π½Π°ΡˆΠ΅ΠΌΡƒ подзапросу, Π° это Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ смоТСм ΠΎΠ±Ρ€Π°Ρ‰Π°Ρ‚ΡŒΡΡ ΠΊ Π΅Π³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°ΠΌ Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… мСстах.

НапримСр, ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ ΡΡ€Π°Π²Π½ΠΈΡ‚ΡŒ ΠΎΡ†Π΅Π½ΠΊΡƒ ΡƒΡ‡Π΅Π½ΠΈΠΊΠ° (ΠΊΠΎΠ»ΠΎΠ½ΠΊΠ° grades) с Π΅Π³ΠΎ срСдним Π±Π°Π»Π»ΠΎΠΌ. Π‘Π΄Π΅Π»Π°Ρ‚ΡŒ это Π² ΠΎΠ΄Π½ΠΎΠΌ запросС Π²Ρ€ΠΎΠ΄Π΅ Π±Ρ‹ нСслоТно, Π½Π°ΠΌ сначала Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚ΡŒ срСдний Π±Π°Π»Π» с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° GROUP BY, Π° Π·Π°Ρ‚Π΅ΠΌ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π²Ρ€ΠΎΠ΄Π΅ g.score > avg. НачнСм с Π°Π³Ρ€Π΅Π³Π°Ρ†ΠΈΠΈ GROUP BY.

SELECT
    s.name,
    ROUND(AVG(g.score),1) AS avg
FROM
    students AS s
INNER JOIN
    grades AS g
    ON s.id = g.student_id
GROUP BY
    s.name;

/*
 name     | avg
 -------- | ----
 Dina     | 79.6
 Evan     | 83.4
 Betty    | 70.4
 Caroline | 94.6
 Adam     | 80.8
*/

Π­Ρ‚ΠΎ Π±Ρ‹Π»ΠΎ просто. Но ΠΊΠ°ΠΊ ΠΆΠ΅ Π½Π°ΠΌ ΡΡ€Π°Π²Π½ΠΈΡ‚ΡŒ ΠΊΠ°ΠΆΠ΄ΡƒΡŽ ΠΎΡ†Π΅Π½ΠΊΡƒ со срСдним Π±Π°Π»Π»ΠΎΠΌ? ВзглянитС Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ запросов Π½ΠΈΠΆΠ΅, всС ΠΎΠ½ΠΈ Π²Ρ‹Π΄Π°Π΄ΡƒΡ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ.

SELECT
    s.name,
    ROUND(AVG(g.score),1) AS avg,
    g.score > avg
    ...
    -- ERROR: column "avg" does not exist

SELECT
    s.name,
    ROUND(AVG(g.score),1) AS avg,
    g.score > ROUND(AVG(g.score),1)
    ...
    -- ERROR: column "g.score" must appear in the GROUP BY
    -- clause or be used in an aggregate function

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π²Π°ΠΆΠ΄Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΊΠΎΠ½Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π½ΠΎ это выглядит ΠΊΠ°ΠΊ ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ Π½Π΅ ΠΎΡ‡Π΅Π½ΡŒ Ρ‡ΠΈΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎ.

SELECT
    s.name,
    AVG(g.score) OVER (PARTITION BY s.name),
    g.score > AVG(g.score) OVER (PARTITION BY s.name)
    ...

Π§Ρ‚ΠΎΠ±Ρ‹ наш запрос Π±Ρ‹Π» Ρ‡ΠΈΡ‚Π°Π±Π΅Π»ΡŒΠ½Ρ‹ΠΌ ΠΈ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΌ, Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ WITH. Π Π°Π·Π΄Π΅Π»ΠΈΠΌ наш запрос Π½Π° Π΄Π²Π° подзапроса: ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ срСдний Π±Π°Π»Π», Π° Π²Ρ‚ΠΎΡ€ΠΎΠΉ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ записи с ΠΈΠ½Π΄ΠΈΠ²ΠΈΠ΄ΡƒΠ°Π»ΡŒΠ½Ρ‹ΠΌΠΈ ΠΎΡ†Π΅Π½ΠΊΠ°ΠΌΠΈ grades.

WITH averages AS (
    SELECT
        s.id,
        ROUND(AVG(g.score),1) AS avg_score
    FROM
        students AS s
    INNER JOIN
        grades AS g
        ON s.id = g.student_id
    GROUP BY
        s.id
)
SELECT
    s.name,
    g.score,
    a.avg_score,
    g.score > a.avg_score AS above_avg
FROM
    students AS s
INNER JOIN
    grades AS g
    ON s.id = g.student_id
INNER JOIN
    averages AS a
    ON a.id = s.id;

/*
 name  | score | avg_score | above_avg
 ----- | ----- | --------- | ---------
 Adam  |    82 |      80.8 | true
 Adam  |    82 |      80.8 | true
 Adam  |    80 |      80.8 | false
 Adam  |    75 |      80.8 | false
 Adam  |    85 |      80.8 | true
 Betty |    74 |      70.4 | true
 Betty |    75 |      70.4 | true
*/

Π”Π°, бСзусловно этот запрос получился Π·Π°ΠΌΠ΅Ρ‚Π½ΠΎ большС, Π½Π΅ΠΆΠ΅Π»ΠΈ написаниС Π΄Π²ΡƒΡ… ΠΎΠΊΠΎΠ½Π½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ. Однако, Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Ρ‹ΠΉ запрос ΠΈΠΌΠ΅Π΅Ρ‚ Π΄Π²Π° Π³Π»Π°Π²Π½Ρ‹Ρ… прСимущСства: Ρ‡ΠΈΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ΠΈ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎΡΡ‚ΡŒ.

Запросы ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Ρ‡ΡƒΠ΄ΠΎΠ²ΠΈΡ‰Π½ΠΎ Π΄Π»ΠΈΠ½Π½Ρ‹Π΅. НапримСр Π² ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Meta*, ΠΌΠ½Π΅ встрСчался запрос, содСрТащий Π² сСбС 1000 строк ΠΈ Π²Ρ‹Π·Ρ‹Π²Π°Π» сразу 25 Ρ‚Π°Π±Π»ΠΈΡ†. Π­Ρ‚ΠΎΡ‚ запрос Π±Ρ‹Π» Π±Ρ‹ ΡΠΎΠ²Π΅Ρ€ΡˆΠ΅Π½Π½ΠΎ Π½Π΅Ρ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹ΠΌ Π±Π΅Π· примСнСния ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° WITH, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ€Π°Π·Π³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ участки ΠΊΠΎΠ΄Π° ΠΈ присваиваСт ΠΈΠΌ псСвдонимы.

Работая с большим объСмом Π΄Π°Π½Π½Ρ‹Ρ…, ΠΌΡ‹ Π½Π΅ ΠΈΠΌΠ΅Π΅ΠΌ Ρ‚Π°ΠΊΠΈΡ… Ρ€ΠΎΡΠΊΠΎΡˆΠ½Ρ‹Ρ… возмоТностСй ΠΊΠ°ΠΊ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ подзапросов, сохранСниС Π΄Π°Π½Π½Ρ‹Ρ… Π² CSV Ρ„ΠΎΡ€ΠΌΠ°Ρ‚, Π·Π°Ρ‚Π΅ΠΌ объСдинСниС ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Π°Π½Π°Π»ΠΈΠ·Π° ΠΈΡ… с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Python. ВсС взаимодСйствия с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π·Π° ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.

*Π”Π΅ΡΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Meta ΠΏΡ€ΠΈΠ·Π½Π°Π½Π° экстрСмистской, организация Π·Π°ΠΏΡ€Π΅Ρ‰Π΅Π½Π° Π½Π° Ρ‚Π΅Ρ€Ρ€ΠΈΡ‚ΠΎΡ€ΠΈΠΈ России.

Π”Π°Π²Π°ΠΉΡ‚Π΅ Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚. ΠŸΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Π² нашСй школС ΡƒΠ²ΠΎΠ»ΠΈΠ»ΠΈ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€Π°, ΠΈ систСма ΠΎΡ†Π΅Π½ΠΎΠΊ ΠΏΡ€Π΅Ρ‚Π΅Ρ€ΠΏΠ΅Π»Π° измСнСния. Π£ нас появился Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ΠΊΠ°ΠΊ ΡΡ€Π΅Π΄Π½Π΅Π²Π·Π²Π΅ΡˆΠ΅Π½Π½Ρ‹ΠΉ Π±Π°Π»Π», ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ вычисляСтся ΠΊΠ°ΠΊ ΠΎΡ†Π΅Π½ΠΊΠ° (grades) умноТСнная Π½Π° коэффициСнт слоТности (weight). Π’Π΅ΠΏΠ΅Ρ€ΡŒ для сдачи экзамСна Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΠΌΠ΅Ρ‚ΡŒ: ΡΡ€Π΅Π΄Π½Π΅Π²Π·Π²Π΅ΡˆΠ΅Π½Π½Ρ‹ΠΉ Π±Π°Π»Π» ΠΏΠΎ всСм ΠΏΡ€Π΅Π΄ΠΌΠ΅Ρ‚Π°ΠΌ Π½Π΅ Π½ΠΈΠΆΠ΅ 85% ΠΈΠ»ΠΈ этот ΠΆΠ΅ Π±Π°Π»Π» Π½Π΅ Π½ΠΈΠΆΠ΅ 70% ΠΏΠΎ собствСнному ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ. ОбъСдинСниС Π΄Π°Π½Π½ΠΎΠΉ Π»ΠΎΠ³ΠΈΠΊΠΈ Π² ΠΎΠ΄ΠΈΠ½ Π±Π»ΠΎΠΊ CASE WHEN достаточно слоТно, Π½ΠΎ, Ссли ΠΌΡ‹ Ρ€Π°Π·Π΄Π΅Π»ΠΈΠΌ запрос с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ WITH всё станСт Π³ΠΎΡ€Π°Π·Π΄ΠΎ ΠΏΡ€ΠΎΡ‰Π΅.

Π”Π°Π²Π°ΠΉΡ‚Π΅ Π½Π°Ρ‡Π½Π΅ΠΌ с Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ выявим ΡƒΡ‡Π΅Π½ΠΈΠΊΠΎΠ², Ρƒ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΡΡ€Π΅Π΄Π½Π΅Π²Π·Π²Π΅ΡˆΠ΅Π½Π½Ρ‹ΠΉ Π±Π°Π»Π» большС 85%.

SELECT
    s.name
FROM
    students AS s
INNER JOIN
    grades AS g
    ON s.id = g.student_id
INNER JOIN
    assignments AS a
    ON a.id = g.assignment_id
GROUP BY
    s.name
HAVING
    SUM(g.score * a.weight) > 85;

/*
 name
 --------
 Caroline
*/

ΠŸΡ€Π΅ΠΊΡ€Π°ΡΠ½ΠΎ. Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΡƒΠ·Π½Π°Π΅ΠΌ Ρƒ ΠΊΠΎΠ³ΠΎ ΠΈΠ· ΡƒΡ‡Π΅Π½ΠΈΠΊΠΎΠ² большС 70% ΠΏΠΎ ΠΏΠ΅Ρ€ΡΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠΌΡƒ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ.

SELECT
    s.name
FROM
    students AS s
INNER JOIN
    grades AS g
    ON s.id = g.student_id
INNER JOIN
    assignments AS a
    ON a.id = g.assignment_id
WHERE
    a.name = 'biography'
    AND g.score > 70

/*
 name
 --------
 Adam
 Caroline
 Evan
*/

Но, ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΏΠΎΠΌΠ½ΠΈΠΌ, Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ наш запрос Π²Ρ‹Π΄Π°Π» всСх ΡƒΡ‡Π΅Π½ΠΈΠΊΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡƒΠ΄ΠΎΠ²Π»Π΅Ρ‚Π²ΠΎΡ€ΡΡŽΡ‚ Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π²ΠΎΠΌΡƒ, Π»ΠΈΠ±ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΌΡƒ ΡƒΡΠ»ΠΎΠ²ΠΈΡŽ.

SELECT DISTINCT
    name
FROM
    students
WHERE
    name IN <people_who_passed_final>
    OR name IN <people_who_passed_project>;

Π­Ρ‚ΠΎ ΠΎΡ‡Π΅Π½ΡŒ просто с использованиСм WITH. ΠœΡ‹ присвоим псСвдонимы нашим запросам weighted_pass ΠΈ project_pass, Π° ΠΏΠΎΡ‚ΠΎΠΌ объСдиним ΠΈΡ….

WITH weighted_pass AS (
    SELECT
        s.name
    FROM
        students AS s
    INNER JOIN
        grades AS g
        ON s.id = g.student_id
    INNER JOIN
        assignments AS a
        ON a.id = g.assignment_id
    GROUP BY
        s.name
    HAVING
        SUM(g.score * a.weight) > 85
),
project_pass AS (
    SELECT
        s.name
    FROM
        students AS s
    INNER JOIN
        grades AS g
        ON s.id = g.student_id
    INNER JOIN
        assignments AS a
        ON a.id = g.assignment_id
    WHERE
        a.name = 'biography'
        AND g.score > 70
)
SELECT DISTINCT
    name
FROM
    students
WHERE
    name IN (SELECT name FROM weighted_pass)
    OR name IN (SELECT name FROM project_pass);

/*
 name
 --------
 Evan
 Caroline
 Adam
*/

Π‘ΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π²Π³Π»ΡƒΠ±ΡŒ – EXPLAIN

Π’ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ, Π΄Π°Π²Π°ΠΉΡ‚Π΅ Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ Π΅Ρ‰Π΅ ΠΎΠ΄Π½Ρƒ Π²Π°ΠΆΠ½ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ. Π§Π΅ΠΌ большС ΠΌΡ‹ ΠΈΠ·ΡƒΡ‡Π°Π΅ΠΌ SQL, Ρ‚Π΅ΠΌ большС способов построСния слоТных запросов Π½Π°ΠΌ извСстно. Когда Π»ΡƒΡ‡ΡˆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ EXCEPT, Π° ΠΊΠΎΠ³Π΄Π° NOT IN? НуТно Π»ΠΈ Π½Π°ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ нСсколько JOIN для объСдинСния Ρ‚Π°Π±Π»ΠΈΡ†, Π»ΠΈΠ±ΠΎ Π»ΡƒΡ‡ΡˆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ WITH ΠΈ UNION ALL?

И Π² ΠΈΡ‚ΠΎΠ³Π΅, ΠΊΠ°ΠΊ Π½Π°ΠΌ ΠΏΠΎΠ½ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠ΄ΠΈΠ½ запрос Π±ΠΎΠ»Π΅Π΅ эффСктивСн, Ρ‡Π΅ΠΌ Π΄Ρ€ΡƒΠ³ΠΎΠΉ?

Postgres ΠΌΠΎΠΆΠ΅Ρ‚ Π½Π°ΠΌ ΠΎΠ± этом Ρ€Π°ΡΡΠΊΠ°Π·Π°Ρ‚ΡŒ. ΠšΠ»ΡŽΡ‡Π΅Π²ΠΎΠ΅ слово explain прСдоставляСт Π½Π°ΠΌ ΠΏΠ»Π°Π½ выполнСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ описываСт ΠΊΠ°ΠΊ выполняСтся ваш запрос. ВСрнСмся ΠΊ запросу ΠΈΠ· Π½Π°Ρ‡Π°Π»Π° ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΈ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Postgres выполняСт запрос ΡΠΎΠ²Π΅Ρ€ΡˆΠ΅Π½Π½ΠΎ Π½Π΅ Π² Ρ‚ΠΎΠΌ порядкС, Π² ΠΊΠ°ΠΊΠΎΠΌ ΠΌΡ‹ написали.

EXPLAIN
SELECT
    s.id AS student_id,
    g.score
FROM
    students AS s
LEFT JOIN
    grades AS g
    ON s.id = g.student_id
WHERE
    g.score > 90
ORDER BY
    g.score DESC;
    
/*
 QUERY PLAN
 ----------
 Sort (cost=80.34..81.88 rows=617 width=8)
 [...] Sort Key: g.score DESC
 [...] -> Hash Join (cost=16.98..51.74 rows=617 width=8)
 [...] Hash Cond: (g.student_id = s.id)
 [...] -> Seq Scan on grades g (cost=0.00..33.13 rows=617 width=8)
 [...] Filter: (score > 90)
 [...] -> Hash (cost=13.10..13.10 rows=310 width=4)
 [...] -> Seq Scan on students s (cost=0.00..13.20 rows=320 width=4)
*/

МоТно ΠΏΠΎΠΉΡ‚ΠΈ Π΅Ρ‰Π΅ дальшС ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ EXPLAIN ANALYZE, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΡ‚ΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ Π΅Ρ‰Π΅ Π±ΠΎΠ»Π΅Π΅ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΡƒΡŽ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, врСмя выполнСния ΠΊΠ°ΠΆΠ΄ΠΎΠΉ части запроса ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡƒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ).

EXPLAIN ANALYZE
SELECT
    s.id AS student_id,
    g.score
FROM
    students AS s
LEFT JOIN
    grades AS g
    ON s.id = g.student_id
WHERE
    g.score > 90
ORDER BY
    g.score DESC;
    
/*
 QUERY PLAN
 ----------
 Sort (cost=80.34..81.88 rows=617 width=8)
   (actual tiem=0.169..0.171 rows=6 loops=1)
 [...] Sort Key: g.score DESC
 [...] Sort Method: quicksort Memory: 25kB
 [...] -> Hash Join (cost=16.98..51.74 rows=617 width=8)
   (actual time=0.115..0.145 rows=6 loops=1)
 [...] Hash Cond: (g.student_id = s.id)
 [...] -> Seq Scan on grades g (cost=0.00..33.13 rows=617 width=8)
   (actual time=0.045..0.052 rows=6 loops=1)
 [...] Filter: (score > 90)
   Rows removed by Filter: 19
 [...] -> Hash (cost=13.10..13.10 rows=310 width=4)
   (actual time=0.059..0.060 rows=5 loops=1)
 [...] Buckets: 1024 Batches: 1 Memory Usage: 9kB
 [...] -> Seq Scan on students s (cost=0.00..13.10 rows=310 width=4)
    (actual time=0.022..0.027 rows=5 loops=1)
 Planning Time: 0.379 ms
 Execution Time: 0.227 ms
*/

НапримСр Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Π²Ρ‹ΡˆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Postgres ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ сканируСт (Seq Scan) Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ grades ΠΈ students, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΈ Π½Π΅ индСксированы. Π˜Π½Π°Ρ‡Π΅ говоря, Postgres Π½Π΅ Π·Π½Π°Π΅Ρ‚ Ρ‡Ρ‚ΠΎ строка Π²Π½ΠΈΠ·Ρƒ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΈΠΌΠ΅Π΅Ρ‚ id мСньшС ΠΈΠ»ΠΈ большС Ρ‡Π΅ΠΌ строка Π½Π°Π²Π΅Ρ€Ρ…Ρƒ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹. Π’ нашСм случаС, это Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ особого значСния Π²Π²ΠΈΠ΄Ρƒ Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠ² нашСй Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, Π½ΠΎ Ссли Π±Ρ‹ ΠΌΡ‹ Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΈ с ΠΌΠΈΠ»Π»ΠΈΠΎΠ½Π°ΠΌΠΈ строк Π΄Π°Π½Π½Ρ‹Ρ…, Ρ‚ΠΎ Π½Π°ΠΌ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΎΠ²Π°Π»ΠΎΡΡŒ Π±Ρ‹ Π½Π°ΠΉΡ‚ΠΈ ΠΈ ΡƒΡΡ‚Ρ€Π°Π½ΠΈΡ‚ΡŒ Ρ‚Π°ΠΊΠΈΠ΅ ΡƒΠ·ΠΊΠΈΠ΅ мСста Π² ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.

***

Данная ΡΡ‚Π°Ρ‚ΡŒΡ Π±Ρ‹Π»Π° ΠΎΠ±Π·ΠΎΡ€ΠΎΠΌ Ρ‚Π΅Ρ… Π½Π°Π²Ρ‹ΠΊΠΎΠ² Π² SQL, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²Π°ΠΌ Ρ‚ΠΎΡ‡Π½ΠΎ понадобятся сразу послС получСния Π±Π°Π·ΠΎΠ²Ρ‹Ρ… Π·Π½Π°Π½ΠΈΠΉ. ΠœΡ‹ Π½Π°Ρ‡Π°Π»ΠΈ с установки Postgres ΠΈ pgAdmin, Ρ‚Π΅ΠΌ самым ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ² Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° своём ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π΅.

Π—Π°Ρ‚Π΅ΠΌ ΠΌΡ‹ ΡƒΠ·Π½Π°Π»ΠΈ ΠΏΡ€ΠΎ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Π΅ синтаксичСскиС конструкции, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΠ»ΠΈ Π½Π°ΠΌ ΡΠΎΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ слоТныС запросы. ΠœΡ‹ Π½Π°Ρ‡Π°Π»ΠΈ с Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ ΡƒΠ·Π½Π°Π»ΠΈ, Ρ‡Π΅ΠΌ отличаСтся WHERE ΠΎΡ‚ HAVING. Π”Π°Π»Π΅Π΅ ΠΌΡ‹ познакомились с условными конструкциями, ΡƒΠ·Π½Π°Π»ΠΈ ΠΊΠ°ΠΊ ΡΠ΅Π³ΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ CASE WHEN ΠΈ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ null, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ COALESCE. ΠœΡ‹ ΠΏΠ΅Ρ€Π΅ΡˆΠ»ΠΈ ΠΎΡ‚ Π³ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ ΠΊ Π²Π΅Ρ€Ρ‚ΠΈΠΊΠ°Π»ΡŒΠ½ΠΎΠΌΡƒ объСдинСнию Ρ‚Π°Π±Π»ΠΈΡ† с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ Π½Π°Π΄ мноТСствами, Ρ€Π°Π·ΠΎΠ±Ρ€Π°Π² ΠΊΠ°ΠΊ UNION, UNION ALL, INTERSECT, ΠΈ EXCEPT Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ с ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡŽΡ‰ΠΈΠΌΠΈΡΡ строками Π² Ρ‚Π°Π±Π»ΠΈΡ†Π°Ρ…. И Π² ΠΊΠΎΠ½Ρ†Π΅ Π²Ρ‚ΠΎΡ€ΠΎΠΉ части ΡΡ‚Π°Ρ‚ΡŒΠΈ ΡƒΠ·Π½Π°Π»ΠΈ ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ массивы ΠΈ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Π½ΠΈΠΌΠΈ.

Π’ Ρ„ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΉ части ΠΌΡ‹ Ρ€Π°Π·ΠΎΠ±Ρ€Π°Π»ΠΈ, ΠΊΠ°ΠΊ ΡΠΎΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π΅Ρ‰Π΅ Π±ΠΎΠ»Π΅Π΅ слоТныС запросы, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ объСдинСниС Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ с самой собой, ΠΎΠΊΠΎΠ½Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для сравнСния Π΄Π°Π½Π½Ρ‹Ρ…, ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ WITH для имСнования Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Ρ… запросов. И Π² ΠΊΠΎΠ½Ρ†Π΅ ΠΌΡ‹ ΡƒΠ·Π½Π°Π»ΠΈ, Ρ‡Ρ‚ΠΎ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ EXPLAIN ΠΈ EXPLAIN ANALYZE ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ†Π΅Π½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Π½Π°ΡˆΠΈΡ… запросов ΠΈ ΡƒΠ·Π½Π°Ρ‚ΡŒ Π² ΠΊΠ°ΠΊΠΈΡ… мСстах ΠΈΡ… ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ.

И ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ ΠΆΠ΅ это Π΄Π°Π»Π΅ΠΊΠΎ Π½Π΅ всё. Π•ΡΡ‚ΡŒ Π΅Ρ‰Π΅ ΠΌΠ½ΠΎΠ³ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΏΡ€ΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ стоит Π·Π½Π°Ρ‚ΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ CAST (для привСдСния ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ… ΠΊ Π΄Ρ€ΡƒΠ³ΠΎΠΌΡƒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ float ΠΊ integer), ΠΈΠ»ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, опрСдСляСмыС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΌ (user-defined functions), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для дальнСйшСго упрощСния ΠΊΠΎΠ΄Π°. Всё это бСзусловно ΠΎΡ‡Π΅Π½ΡŒ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ, Π½ΠΎ я Π±Ρ‹ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΠΎΠ²Π°Π» всСгда Π΄ΡƒΠΌΠ°Ρ‚ΡŒ ΠΎΠ± ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ запросов. Π”Π°ΠΆΠ΅ Π² FAANG компаниях с практичСски Π½Π΅ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π½Ρ‹ΠΌΠΈ Π²Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ рСсурсами, запросы ΠΌΠΎΠ³ΡƒΡ‚ Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒΡΡ с ошибкой Π² Ρ‚ΠΎΠΌ случаС, Ссли ΠΎΠ½ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ большС памяти, Ρ‡Π΅ΠΌ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ сСрвСр. Π’Ρ‹Π±ΠΎΡ€ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π° ΠΊ написанию запроса, ΡƒΠΏΡ€ΠΎΡ‰Π°Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ с ΠΏΠΎΡ‚ΠΎΠΊΠΎΠΌ Π΄Π°Π½Π½Ρ‹Ρ…, Ρ‡Ρ‚ΠΎ сниТаСт шанс ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π³Π½Π΅Π²Π½Ρ‹ΠΉ Π·Π²ΠΎΠ½ΠΎΠΊ Π² ΠΏΠΎΠ»Π½ΠΎΡ‡ΡŒ.

Π”ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅

1. CASCADE

Π§Ρ‚ΠΎ ΠΆΠ΅ Π½Π° самом Π΄Π΅Π»Π΅ происходит ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ CASCADE ΠΏΡ€ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΈ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹?

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ удаляСм Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ classrooms ΠΈ Π½Π΅ Π·Π°Ρ‚Ρ€Π°Π³ΠΈΠ²Π°Π΅ΠΌ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅. Π”Π°Π½Π½Ρ‹Π΅ Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ students Π½Π΅ Π·Π°Ρ‚Ρ€ΠΎΠ½ΡƒΡ‚Ρ‹, Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ запроса ΠΌΡ‹ ΠΏΠΎ ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ Π²ΠΈΠ΄ΠΈΠΌ id класса.

SELECT
    s.name,
    s.classroom_id,
    c.teacher
FROM
    students AS s
LEFT JOIN
    classrooms AS c
    ON c.id = s.classroom_id;

/*
 name     | classroom_id | teacher
 -------- | ------------ | -------
 Adam     |            1 | Mary
 Betty    |            1 | Mary
 Caroline |            2 | Jonah
 Dina     |       [null] | [null]
 Evan     |       [null] | [null]
*/

DROP TABLE classrooms CASCADE;

/*
DROP TABLE
Query returned successfully in 71 msec.
*/

SELECT * FROM students;

/*
 id | name     | classroom_id | best_friend_id
 -- | -------- | ------------ | --------------
  1 | Adam     |            1 |              5
  2 | Betty    |            1 |              4
  3 | Caroline |            2 |              2
  4 | Dina     |       [null] |              2
  5 | Evan     |       [null] |              1
*/

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π·Π°Π½ΠΎΠ²ΠΎ создадим Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ classrooms ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π² Π½Π΅Π΅ Π½ΠΎΠ²Ρ‹Ρ… ΡƒΡ‡ΠΈΡ‚Π΅Π»Π΅ΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π½Π΅ Π±Ρ‹Π»ΠΎ Π² ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Π΅. Бвязь ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ‚Π°Π±Π»ΠΈΡ†Π°ΠΌΠΈ students ΠΈ classrooms ΡƒΠΆΠ΅ Π½Π΅ точная, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΈΠΌΠ΅Π½Π° ΡƒΡ‡ΠΈΡ‚Π΅Π»Π΅ΠΉ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠ»ΠΈ Π² сравнСнии с ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ.

CREATE TABLE classrooms (
    id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    teacher VARCHAR(100)
);

/*
CREATE TABLE
Query returned successfully in 139 msec.
*/

INSERT INTO classrooms
    (teacher)
VALUES
    ('Dr. Random'),
    ('Alien Banana');

/*
INSERT 0 2
Query returned successfully in 99 msec.
*/

SELECT
    s.name,
    s.classroom_id,
    c.teacher
FROM
    students AS s
LEFT JOIN
    classrooms AS c
    ON c.id = s.classroom_id;

/*
 name     | classroom_id | teacher
 -------- | ------------ | -----------
 Adam     |            1 | Dr. Random
 Betty    |            1 | Dr. Random
 Caroline |            2 | Alien Banana
 Dina     |       [null] | [null]
 Evan     |       [null] | [null]
*/

Π’Π°ΠΊ ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»ΠΎ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ CASCADE ΡƒΠ΄Π°Π»ΠΈΠ» внСшний ΠΊΠ»ΡŽΡ‡ Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ students. ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ это ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ. ИзмСним Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ classroom_id Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ students, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ½ΠΎ большС Π½Π΅ являСтся внСшним ΠΊΠ»ΡŽΡ‡ΠΎΠΌ ΠΈ Π½Π΅ связано с Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ classrooms, запрос выполнится ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ. Но Ссли ΠΌΡ‹ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ‚ΠΎ ΠΆΠ΅ самоС с ΠΏΠΎΠ»Π΅ΠΌ student_id Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ grades, ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ student_id – это внСшний ΠΊΠ»ΡŽΡ‡.

UPDATE students
SET classroom_id = 10
WHERE id = 1;

/*
UPDATE 1
Query returned successfully in 37 msec.
*/

UPDATE grades
SET student_id = 10
WHERE id = 1;
/*
ERROR:  insert or update on table "grades" violates foreign key
    constraint "fk_students"
DETAIL:  Key (student_id)=(10) is not present in table
    "students".
SQL state: 23503
*/

И Π΅Ρ‰Π΅ ΠΎΠ΄Π½ΠΎ Π·Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅ ΠΏΠΎ ΠΏΠΎΠ²ΠΎΠ΄Ρƒ CASCADE. Если ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ON DELETE CASCADE ΠΏΡ€ΠΈ создании внСшнСго ΠΊΠ»ΡŽΡ‡Π° Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ students, Π° ΠΏΠΎΡ‚ΠΎΠΌ удаляСм запись Π² classrooms, Ρƒ нас Ρ‚Π°ΠΊΠΆΠ΅ исчСзнут связанныС строки Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ students. Π’Π°ΠΊΠΎΠΉ способ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΠΎΠ»Π΅Π·Π΅Π½ ΠΏΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π΅ с Π»ΠΈΡ‡Π½Ρ‹ΠΌΠΈ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ всС Π΄Π°Π½Π½Ρ‹Π΅ ΠΎ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π΅ ΠΈΠ»ΠΈ ΠΎ сотрудникС.

DROP TABLE IF EXISTS students CASCADE;

CREATE TABLE students (
    id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    name VARCHAR(100),
    classroom_id INT,
    CONSTRAINT fk_classrooms
        FOREIGN KEY(classroom_id)
        REFERENCES classrooms(id) ON DELETE CASCADE
);

INSERT INTO students
    (name, classroom_id)
 VALUES
    ('Adam', 1),
    ('Betty', 1),
    ('Caroline', 2);

SELECT * FROM students;
/*
 id | name     | classroom_id
 -- | -------- | ------------
  1 | Adam     |            1
  2 | Betty    |            1
  3 | Caroline |            2
*/

DELETE FROM classrooms
WHERE id = 1;

SELECT * FROM students;
/*
 id | name     | classroom_id
 -- | -------- | ------------
  3 | Caroline |            2
*/

2. Π‘ΠΎΡ…Ρ€Π°Π½Π½ΠΎΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Ρ…

БистСматизированиС схСмы Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ созданиС скриптов – это Π»ΡƒΡ‡ΡˆΠ°Ρ ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ° с ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ€Π½ΠΎΠΉ Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния, Π½ΠΎ ΠΏΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π΅ с Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΌΠΈ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΎΡ‡Π΅Π½ΡŒ часто ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Ρ€Π΅Π·Π΅Ρ€Π²Π½Ρ‹Π΅ ΠΊΠΎΠΏΠΈΠΈ. БущСствуСт ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΎΠ², ΠΈΠ½ΠΎΠ³Π΄Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ ΠΏΠΎΠ»Π½Ρ‹Π΅ ΠΊΠΎΠΏΠΈΠΈ Π±Π°Π· Π΄Π°Π½Π½Ρ‹Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π·Π°Π½ΠΈΠΌΠ°ΡŽΡ‚ большоС количСство памяти, Π° ΠΈΠ½ΠΎΠ³Π΄Π° Ρ„ΠΈΠΊΡΠΈΡ€ΡƒΡŽΡ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Π΅ измСнСния. Π’ ΠΈΠ΄Π΅Π°Π»Π΅, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠΎΠΏΠΈΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒΡΡ Π½Π° гСографичСски ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΌ сСрвСрС, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠ½ΠΈΠ·ΠΈΡ‚ΡŒ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠ³ΠΎ влияния стихии Π½Π° ΡΠΎΡ…Ρ€Π°Π½Π½ΠΎΡΡ‚ΡŒ Π²Π°ΡˆΠΈΡ… Π΄Π°Π½Π½Ρ‹Ρ….

3. Π”Π»ΠΈΠ½Π° строк

ΠœΡ‹ установили, Ρ‡Ρ‚ΠΎ Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ… Π² ΠΊΠΎΠ»ΠΎΠ½ΠΊΠ΅ ΡƒΡ‡ΠΈΡ‚Π΅Π»ΡŒ – это строка с максимальной Π΄Π»ΠΈΠ½ΠΎΠΉ Π² 100 символов, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Π½Π΅ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ Π±ΡƒΠ΄ΡƒΡ‚ значСния Π΄Π»ΠΈΠ½Π½Π΅Π΅. Но Π½Π° самом Π»ΠΈ Π΄Π΅Π»Π΅ ΠΌΡ‹ экономим Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ мСсто Π½Π° дискС?

Π‘ тСхничСской Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния, Π² Postgres Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ значСния, ΠΊΠ°ΠΊΡƒΡŽ Π΄Π»ΠΈΠ½Ρƒ строки ΠΌΡ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ (10, 100 ΠΈΠ»ΠΈ 500 символов). Π£ΠΊΠ°Π·Π°Π½ΠΈΠ΅ Π΄Π»ΠΈΠ½Ρ‹ строки – это скорСС Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΉ способ ΠΊΠΎΠΌΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌΠΈ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ Π²Ρ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚Π΅, Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΎΠΆΠΈΠ΄Π°Π΅Ρ‚Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π² этом ΠΏΠΎΠ»Π΅.

Но, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² MySQL Π΄Π»ΠΈΠ½Π° строк ΠΈΠΌΠ΅Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅: Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΈ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ MEMORY Π±ΡƒΠ΄ΡƒΡ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ строки ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎΠΉ Π΄Π»ΠΈΠ½Ρ‹ ΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΈΡ… Π΄ΠΎ максимального значСния. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ, Ссли Π²Ρ‹ ΡƒΠΊΠ°Π·Π°Π»ΠΈ Ρ‚ΠΈΠΏ поля VARCHAR(1000), Ρ‚ΠΎ всС Π΄Π°Π½Π½Ρ‹Π΅ Π² этой ΠΊΠΎΠ»ΠΎΠ½ΠΊΠ΅ Π±ΡƒΠ΄ΡƒΡ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ Π΄ΠΎ ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ Π΄Π»ΠΈΠ½Ρ‹, Π΄Π°ΠΆΠ΅ Ссли строка состоит ΠΈΠ· 100 символов.

4. ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ If

Если Π²Π°ΠΌ интСрСсно, Π½ΠΈΠΆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ Π² Postgres выглядит синтаксис с ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠΌ if.

DO $$

BEGIN
    IF
        (SELECT COUNT(*) FROM grades) >
        (SELECT COUNT(*) FROM students)
    THEN
        RAISE NOTICE 'More grades than students.';
    ELSE
        RAISE NOTICE 'Equal or more students than grades.';
    END IF;

END $$;

/*
NOTICE: More grades than students.
*/

5. Π˜Π½Π΄Π΅ΠΊΡΡ‹

ΠŸΡ€ΠΈ ΡƒΠ²Π΅Π»ΠΈΡ‡Π΅Π½ΠΈΠΈ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, установка индСксов становится критичСски Π²Π°ΠΆΠ½ΠΎΠΉ. Для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°, Π΄Π°Π²Π°ΠΉΡ‚Π΅ создадим индСкс Π½Π° ΠΏΠΎΠ»Π΅ с ΠΎΡ†Π΅Π½ΠΊΠ°ΠΌΠΈ Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ grades:

CREATE INDEX
    score_index
ON
    grades(score);

Π’Π΅ΠΌ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅, Ссли сСйчас ΠΌΡ‹ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ EXPLAIN ANALYZE, ΠΌΡ‹ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Postgres ΠΏΠΎ-ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ выполняСт ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ сканированиС. Π’Π°ΠΊ происходит ΠΏΠΎΡ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ Postgres ΡƒΠΆΠ΅ достаточно Π½Π΅ΠΏΠ»ΠΎΡ…ΠΎ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½. Если количСство записСй Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ Π½Π΅Π²Π΅Π»ΠΈΠΊΠΎ, быстрСС Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ сканированиС, Π½Π΅ΠΆΠ΅Π»ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ индСксы. Π’ΠΎ Π΅ΡΡ‚ΡŒ Postgres сам Π²Ρ‹Π±Ρ€Π°Π» Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ быстрый ΠΏΡƒΡ‚ΡŒ.

***

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ ΠΏΠΎ Ρ‚Π΅ΠΌΠ΅

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

eFusion
08 января 2020

11 Ρ‚ΠΈΠΏΠΎΠ² соврСмСнных Π±Π°Π· Π΄Π°Π½Π½Ρ‹Ρ…: ΠΊΡ€Π°Ρ‚ΠΊΠΈΠ΅ описания, схСмы ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Π‘Π”

Π›ΡŽΠ±Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Π³Π΄Π΅-Ρ‚ΠΎ хранятся. Π‘ΡƒΠ΄ΡŒ это ΠΈΠ½Ρ‚Π΅Ρ€Π½Π΅Ρ‚ Π²Π΅Ρ‰Π΅ΠΉ ΠΈΠ»ΠΈ ΠΏΠ°Ρ€ΠΎΠ»ΠΈ Π² *nix. По...
Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° программиста
29 июня 2017

5 сайтов для оттачивания Π½Π°Π²Ρ‹ΠΊΠΎΠ² написания SQL-запросов

Одним ΠΈΠ· ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Ρ… Π½Π°Π²Ρ‹ΠΊΠΎΠ² ΠΏΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π΅ с Π±Π°Π·Π°ΠΌΠΈ Π΄Π°Π½Π½Ρ‹Ρ… являСтся ΡƒΠΌΠ΅Π½ΠΈΠ΅ ΠΏΠΈΡΠ°Ρ‚ΡŒ...
admin
23 фСвраля 2017

SQL Π·Π° 20 ΠΌΠΈΠ½ΡƒΡ‚

ΠŸΡ€Π΅Π΄Π»Π°Π³Π°Π΅ΠΌ Π²Π°ΡˆΠ΅ΠΌΡƒ вниманию ΡΡ‚Π°Ρ‚ΡŒΡŽ с ΠΊΡ€ΠΈΡ‡Π°Ρ‰ΠΈΠΌ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ "SQL Π·Π° 20 ΠΌΠΈΠ½ΡƒΡ‚". К...