diff --git a/course/module-0/intro-community/article.md b/course/module-0/intro-community/article.md index 0fa3ee8..90fa730 100644 --- a/course/module-0/intro-community/article.md +++ b/course/module-0/intro-community/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Сообщество SQL Academy' - description: 'Информация о нашем SQL сообществе и целях, для которых оно организовано, а также о доступных способах связи с администрацией данного сервиса.' + title: "Сообщество SQL Academy" + description: "Информация о нашем SQL сообществе и целях, для которых оно организовано, а также о доступных способах связи с администрацией данного сервиса." --- # Сообщество @@ -11,10 +11,12 @@ meta: Коммуникация организована через: -- **чат в Telegram** -- **сообщество ВКонтакте** +- **группу в Telegram** +- **сообщество ВКонтакте** -На странице сообщества мы выкладываем информацию по последним наиболее важным обновлениям, а также много образовательного контента по SQL, реляционным базам данных, и как с помощью них найти работу или получить повышение. +На странице сообщества мы выкладываем информацию по последним наиболее важным обновлениям, а также много +образовательного контента по SQL, реляционным базам данных, и как с помощью них найти работу или +получить повышение. Для общения между участниками есть чат **в Telegram **. @@ -23,9 +25,9 @@ meta: По вопросам, возникающим при работе сервиса, замечаниям и рекомендациям по содержанию курса или же при проблемах с оплатой премиум аккаунта можно использовать следующие способы связи: -- Написать письмо на адрес - **[feedback@sql-academy.org](mailto:feedback@sql-academy.org)** -- Написать сообщение в сообщество - ** сообщество ВКонтакте** +- Написать письмо на адрес + **[feedback@sql-academy.org](mailto:feedback@sql-academy.org)** +- Написать сообщение в сообщество\ + ** сообщество ВКонтакте** Рады видеть Вас в нашем сообществе 😍 diff --git a/course/module-0/intro-intro/article.md b/course/module-0/intro-intro/article.md index 4c9940a..5351e40 100644 --- a/course/module-0/intro-intro/article.md +++ b/course/module-0/intro-intro/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Введение в курс по SQL' - description: 'Информация о нашем бесплатном онлайн курсе по SQL, об поддержке работа на различных устройствах и об опциональности приобретения премиум аккаунта' + title: "Введение в курс по SQL" + description: "Информация о нашем бесплатном онлайн курсе по SQL, об поддержке работа на различных устройствах и об опциональности приобретения премиум аккаунта" --- # О курсе @@ -14,7 +14,7 @@ meta: сильно задумываться при составлении запросов к базам данных. При прохождении курса мы настоятельно рекомендуем вам культивировать «мышление роста»: если вы будете сталкиваться с какими-либо сложностями, пытаясь -понять новую тему или выполняя упражнения, пытайтесь трансформировать возникающий разочаровывающий опыт в продуктивный. +понять новую тему или выполняя упражнения, пытайтесь трансформировать возникающий разочаровывающий опыт в продуктивный.\ И самая важная вещь в данном курсе – **получайте удовольствие!** ## Проходите курс публично @@ -30,14 +30,14 @@ meta: ## Как организован наш ресурс -![Как организован наш ресурс](https://sql-academy.org/static/guidePage/intro-intro/connections.webp) +![Как организован наш ресурс](https://sql-academy.org/static/guidePage/intro-intro/connections.webp)\ На нашем ресурсе есть четыре основных раздела, каждый из которых будет по-разному полезен: -- ** Данный курс** – это ваш пошаговый помощник при изучении SQL. Здесь представлены последовательные, структурированные материалы, а также связанные упражнения для закрепления знаний. -- **Продвинутые курсы** – это отдельные практические программы для тех, кто уже освоил базу и хочет углубиться в более прикладные темы, например оптимизацию SQL-запросов или анализ данных. -- **Тренажёр** – это инструмент проверки ваших знаний. Задания в нем проранжированы по сложности, поэтому вы можете подбирать подходящие для вашего текущего уровня. - Также прорешивание заданий из тренажёра необходимо для получения сертификата, подтверждающего знания в области SQL. -- **Песочница** – это пространство для свободного знакомства со структурой наших баз данных. +- ** Данный курс** – это ваш пошаговый помощник при изучении SQL. Здесь представлены последовательные, структурированные материалы, а также связанные упражнения для закрепления знаний. +- **Продвинутые курсы** – это отдельные практические программы для тех, кто уже освоил базу и хочет углубиться в более прикладные темы, например оптимизацию SQL-запросов или анализ данных. +- **Тренажёр** – это инструмент проверки ваших знаний. Задания в нем проранжированы по сложности, поэтому вы можете подбирать подходящие для вашего текущего уровня. + Также прорешивание заданий из тренажёра необходимо для получения сертификата, подтверждающего знания в области SQL. +- **Песочница** – это пространство для свободного знакомства со структурой наших баз данных. Кроме того, в шапке нашего ресурса доступен глобальный поиск, который помогает находить материалы по всем разделам платформы: курсам, заданиям и функциям из справочника. @@ -60,7 +60,7 @@ meta: Сертификат тренажёра подтверждает, что вы не только изучили теорию, но и умеете самостоятельно решать практические задачи по SQL. Его можно добавить в резюме или портфолио, а подлинность сертификата легко проверить по публичной ссылке. -Сертификат станет доступен после 50 самостоятельно решённых заданий в **Тренажёре**. Задания, в которых вы посмотрели готовое решение, не учитываются. +Сертификат станет доступен после 40 самостоятельно решённых заданий в **Тренажёре**. Задания, в которых вы посмотрели готовое решение, не учитываются. Следить за количеством самостоятельно решённых заданий можно по прогресс-бару в тренажёре. diff --git a/course/module-0/intro-structure-of-course/article.md b/course/module-0/intro-structure-of-course/article.md index 7639aa6..ad7f54c 100644 --- a/course/module-0/intro-structure-of-course/article.md +++ b/course/module-0/intro-structure-of-course/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Структура курса' - description: 'Подробная информация о данном курсе по SQL' + title: "Структура курса" + description: "Подробная информация о данном курсе по SQL" --- # Структура курса @@ -28,13 +28,13 @@ SELECT 'Hi, I am code playground 😊' AS hello; Если в нем есть активная синяя кнопка, то такой код можно исполнить. При клике по кнопке исполнения запроса код откроется в новой вкладке в песочнице. -![Описание блока с исполняемым кодом](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_codeplayground_description.png 'Описание блока с исполняемым кодом') +![Описание блока с исполняемым кодом](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_codeplayground_description.png "Описание блока с исполняемым кодом") ### Задания для самопроверки Настоятельно рекомендуется не пропускать задачи в конце каждой статьи. Они выглядят следующим образом: -![Описание заданий для самопроверки](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_exercises_description.png 'Описание заданий для самопроверки') +![Описание заданий для самопроверки](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_exercises_description.png "Описание заданий для самопроверки") Перед решением задач рекомендуется войти в свой аккаунт, так все ваши решения будут сохраняться. @@ -44,16 +44,16 @@ SELECT 'Hi, I am code playground 😊' AS hello; **Как с ним общаться:** -- **Выделение текста** на странице — появится кнопка «Уточнить» для получения дополнительных объяснений выделенного фрагмента +- **Выделение текста** на странице — появится кнопка «Уточнить» для получения дополнительных объяснений выделенного фрагмента - ![Кнопка «Уточнить» при выделении текста](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_ai_explain.png 'Кнопка «Уточнить» при выделении текста') +![Кнопка «Уточнить» при выделении текста](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_ai_explain.png "Кнопка «Уточнить» при выделении текста") -- **Быстрые действия** в окне помощника, например, «Задай вопрос» для самопроверки по текущей теме +- **Быстрые действия** в окне помощника, например, «Задай вопрос» для самопроверки по текущей теме - ![Окно AI-ассистента с быстрыми действиями](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_ai_window.png 'Окно AI-ассистента с быстрыми действиями') + ![Окно AI-ассистента с быстрыми действиями](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_ai_window.png "Окно AI-ассистента с быстрыми действиями") -- **Объяснение ошибок** — если при выполнении SQL-запроса в упражнениях возникает ошибка, помощник поможет разобраться в причинах и подскажет, как исправить запрос +- **Объяснение ошибок** — если при выполнении SQL-запроса в упражнениях возникает ошибка, помощник поможет разобраться в причинах и подскажет, как исправить запрос - ![AI-ассистент объясняет ошибку в SQL-запросе](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_ai_explain_error.png 'AI-ассистент объясняет ошибку в SQL-запросе') + ![AI-ассистент объясняет ошибку в SQL-запросе](https://sql-academy.org/static/guidePage/intro-structure-of-course/ru_ai_explain_error.png "AI-ассистент объясняет ошибку в SQL-запросе") -Ассистент работает для **зарегистрированных пользователей**. У каждого пользователя есть несколько бесплатных запросов, а у [премиум-пользователей](https://sql-academy.org/premium) они безлимитные! 😊 +Ассистент работает для **зарегистрированных пользователей**. У каждого пользователя есть несколько бесплатных запросов, а у премиум-пользователей они безлимитные! 😊 diff --git a/course/module-1/basic-database-concepts/article.md b/course/module-1/basic-database-concepts/article.md index 5c96410..ff63dbd 100644 --- a/course/module-1/basic-database-concepts/article.md +++ b/course/module-1/basic-database-concepts/article.md @@ -1,10 +1,10 @@ --- meta: - title: 'Базы данных и СУБД' - description: 'Определение база данных и система управления базами данных. Принцип работы баз данных. Рейтинг и популярность реляционных баз данных. Особенности реляционных баз данных. Язык запросов SQL.' + title: "Что такое база данных: основные понятия простыми словами" + description: "Что такое база данных и СУБД простыми словами: как устроено хранение данных, чем база отличается от системы управления и при чём здесь язык SQL. Первый урок бесплатного курса." --- -# Базы данных и СУБД +# Что такое база данных и СУБД Перед тем как начать изучение SQL, давайте познакомимся с основными понятиями баз данных. Это поможет нам понять области применения SQL и его среду выполнения. @@ -22,21 +22,29 @@ meta: Простейшая схема работы с базой данных: -![Схема работы базы данных](https://sql-academy.org/static/guidePage/basic-database-concepts/ru_schema_of_db_work.png 'title') +![Схема работы базы данных](https://sql-academy.org/static/guidePage/basic-database-concepts/ru_schema_of_db_work.png "title") ## Рейтинг СУБД -На данный момент рейтинг систем управления базами данных на основании db-engines имеет следующий вид: +На данный момент рейтинг систем управления базами данных имеет следующий вид: -- `Oracle` - реляционная СУБД -- `MySQL` - реляционная СУБД -- `Microsoft SQL Server` - реляционная СУБД -- `PostgreSQL` - реляционная СУБД -- `MongoDB` - документоориентированная СУБД -- `Redis` - хранилище по типу «ключ-значение» -- `Snowflake` - облачная реляционная СУБД -- `Elasticsearch` - поисковой движок -- `IBM Db2` - реляционная СУБД -- `SQLite` - реляционная СУБД +- `Oracle` - реляционная СУБД +- `MySQL` - реляционная СУБД +- `Microsoft SQL Server` - реляционная СУБД +- `PostgreSQL` - реляционная СУБД +- `MongoDB` - документоориентированная СУБД +- `Redis` - хранилище по типу «ключ-значение» +- `Snowflake` - облачная реляционная СУБД +- `Elasticsearch` - поисковой движок +- `IBM Db2` - реляционная СУБД +- `SQLite` - реляционная СУБД Можно обратить внимание, что 7 из 10 самых популярных СУБД — реляционные. Вы сделали правильный выбор изучать именно их 😉. + +Давайте проверим, как вы усвоили тему. Выберите правильное утверждение: + +1. СУБД никак не взаимодействует с БД — Системы управления базами данных (СУБД) позволяют управлять, изменять и удалять базы данных. Так что СУБД взаимодействует с БД, на схеме выше отражена схема их работы. + +2. **Правильный ответ:** СУБД управляет данными, хранящимися в БД — База данных - это только некая совокупность данных. Для управления ими действительно нужна система управления базами данных. + +3. Для взаимодействия со всеми СУБД можно использовать язык SQL — СУБД бывают разными и не все из них используют язык запросов SQL. SQL - это стандарт для реляционных СУБД. diff --git a/course/module-1/database-types/article.md b/course/module-1/database-types/article.md index a8a3ec7..b433f75 100644 --- a/course/module-1/database-types/article.md +++ b/course/module-1/database-types/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Типы баз данных' - description: 'Типы и классификации баз данных, наиболее востребованные тип систем управления базами данных' + title: "Типы баз данных" + description: "Типы и классификации баз данных, наиболее востребованные тип систем управления базами данных" --- # Типы баз данных @@ -17,6 +17,8 @@ meta: Классификаций баз данных достаточно много, но давайте остановимся на наиболее востребованных: -- Реляционные базы данных -- Key-value базы данных -- Документоориентированные базы данных +| Тип базы данных | Описание | +| ------------------------ | ---------------------------------------------- | +| Реляционные | Данные в связанных таблицах — строки и столбцы | +| Key-value | Быстрый доступ к значению по ключу | +| Документоориентированные | Гибкие документы в формате JSON | diff --git a/course/module-1/document-oriented-databases/article.md b/course/module-1/document-oriented-databases/article.md index 8264f47..4efb6ca 100644 --- a/course/module-1/document-oriented-databases/article.md +++ b/course/module-1/document-oriented-databases/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Документоориентированные базы данных' - description: 'Определение документно-ориентированных баз данных, примеры хранения данных, особенности и рейтинг популярных документно-ориентированных СУБД.' + title: "Документоориентированные базы данных" + description: "Определение документно-ориентированных баз данных, примеры хранения данных, особенности и рейтинг популярных документно-ориентированных СУБД." --- # Документоориентированные БД diff --git a/course/module-1/intro-sql/article.md b/course/module-1/intro-sql/article.md index 9d148a5..800935d 100644 --- a/course/module-1/intro-sql/article.md +++ b/course/module-1/intro-sql/article.md @@ -1,10 +1,10 @@ --- meta: - title: "Вводная информация о SQL" - description: "Определение языка SQL. Диалекты (расширения) языка SQL. Отличия T-SQL, PL/SQL, PL/pgSQL." + title: "Что такое SQL: язык структурированных запросов простыми словами" + description: "Что такое SQL и зачем он нужен: язык запросов к реляционным базам данных, его возможности и диалекты (T-SQL, PL/SQL, PL/pgSQL). Урок бесплатного интерактивного курса с практикой." --- -# Вводная информация о SQL +# Что такое SQL > SQL — язык структурированных запросов (SQL, Structured Query Language), > который используется в качестве эффективного способа сохранения данных, @@ -14,32 +14,35 @@ meta: **Данные** -- `SELECT` — извлекать данные из базы данных -- `INSERT` — вставлять записи в базу данных -- `UPDATE` — обновлять записи в базе данных -- `DELETE` — удалять записи из базы данных +- `SELECT` — Извлекать данные из базы данных +- `INSERT` — Вставлять записи в базу данных +- `UPDATE` — Обновлять записи в базе данных +- `DELETE` — Удалять записи из базы данных **Структура** -- `CREATE DATABASE` — создавать новые базы данных -- `CREATE TABLE` — создавать новые таблицы в базе данных +- `CREATE DATABASE` — Создавать новые базы данных +- `CREATE TABLE` — Создавать новые таблицы в базе данных **Логика и доступ** -- `CREATE PROCEDURE` — создавать хранимые процедуры -- `CREATE VIEW` — создавать представления -- `GRANT` — выдавать разрешения для таблиц, процедур и представлений +- `CREATE PROCEDURE` — Создавать хранимые процедуры +- `CREATE VIEW` — Создавать представления +- `GRANT` — Выдавать разрешения для таблиц, процедур и представлений ## Диалекты SQL (расширения SQL) Язык SQL – универсальный язык для всех реляционных систем управления базами данных, но многие СУБД вносят свои изменения в язык, применяемый в них, тем самым отступая от стандарта. Такие языки называют диалектами или расширениями языка. -Вот некоторые из них: +Вот некоторые из них. Для примера посмотрим, как в каждой из этих СУБД выбираются первые 3 строки. -- T-SQL – диалект Microsoft SQL Server -- PL/SQL – диалект Oracle Database -- PL/pgSQL – диалект PostgreSQL +| Диалект | СУБД | Пример | +| -------- | -------------------- | ------------------- | +| T-SQL | Microsoft SQL Server | `SELECT TOP 3 name` | +| PL/SQL | Oracle Database | `WHERE ROWNUM <= 3` | +| MySQL | MySQL | `name LIMIT 3` | +| PL/pgSQL | PostgreSQL | `name LIMIT 3` | ### Какой диалект учить? @@ -48,9 +51,18 @@ meta: что разные базы данных могут использовать немного отличающийся синтаксис. В нашем курсе мы предлагаем вам на выбор СУБД MySQL или СУБД PostgreSQL, как 2 наиболее популярных решения. -Выбрать СУБД и поменять её в любой момент можно одним из способов: +Попробуйте выбрать одну из них прямо сейчас — все примеры и задания курса подстроятся под ваш выбор: -- в меню под шестерёнкой в шапке сайта -- в интерфейсе редактора кода +**MySQL** - ![интерфейс редактора SQL кода](https://sql-academy.org/static/guidePage/intro-sql/ru_changing_dbms.png "интерфейс редактора SQL кода") +- Классика веба: просто начать, работает повсюду +- Самая распространённая открытая СУБД в мире +- На ней работают WordPress, YouTube и Booking.com + +**PostgreSQL** + +- Мощь и строгость: любимая СУБД стартапов +- Богатый синтаксис и точное следование стандарту SQL +- Её выбирают Instagram, Spotify и Reddit + +СУБД можно поменять в любой момент — прямо здесь, в меню под шестерёнкой в шапке сайта или в редакторе кода. diff --git a/course/module-1/key-value-databases/article.md b/course/module-1/key-value-databases/article.md index e53ad36..e230805 100644 --- a/course/module-1/key-value-databases/article.md +++ b/course/module-1/key-value-databases/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Key-value базы данных' - description: 'Базы данных по типу ключ-значение. Их преимущества и недостатки. Рейтинг key-value БД по популярности.' + title: "Key-value базы данных" + description: "Базы данных по типу ключ-значение. Их преимущества и недостатки. Рейтинг key-value БД по популярности." --- # Key-value базы данных diff --git a/course/module-1/relation-databases/article.md b/course/module-1/relation-databases/article.md index b9d04f3..3c46bd0 100644 --- a/course/module-1/relation-databases/article.md +++ b/course/module-1/relation-databases/article.md @@ -1,17 +1,13 @@ --- meta: - title: 'Реляционные базы данных' - description: 'Понятие реляционных СУБД, их особенности и принципы работы. Рейтинг реляционные БД по популярности.' + title: "Реляционная база данных: что это такое простыми словами" + description: "Что такое реляционная база данных: таблицы, строки и связи через ключи. Особенности реляционной модели, примеры и рейтинг популярных реляционных СУБД." --- - - # Реляционные базы данных > Реляционными называются базы данных, в основе построения которых лежит реляционная модель. +> В такой базе данные структурированы в виде таблиц, которые содержат строки и столбцы. Данные в реляционных структурах организованы в виде набора таблиц, называемых отношениями, состоящих из столбцов и строк. Каждая строка таблицы представляет собой набор связанных значений, относящихся к одному объекту или сущности. @@ -32,7 +28,8 @@ meta: - Запросы к базе данных возвращают результат в виде таблиц Более детальные особенности и принципы работы реляционных баз данных мы ещё рассмотрим в дальнейшем, так как именно они представляют -наш особый интерес при изучении SQL. +наш особый интерес при изучении SQL. Как именно устроены таблицы — записи, атрибуты, первичные и внешние ключи — мы подробно разбираем +в следующем уроке: [Структура реляционных баз данных](https://sql-academy.org/ru/guide/structure-of-relation-databases). ## Рейтинг реляционных БД по популярности diff --git a/course/module-1/structure-of-relation-databases/article.md b/course/module-1/structure-of-relation-databases/article.md index 730191f..0843595 100644 --- a/course/module-1/structure-of-relation-databases/article.md +++ b/course/module-1/structure-of-relation-databases/article.md @@ -1,12 +1,12 @@ --- meta: - title: 'Структура реляционных баз данных' - description: 'Структура таблиц в реляционных базах данных, понятия записей и атрибутов. Определение понятия первичный и внешний ключ.' + title: "Структура реляционной базы данных: таблицы, записи, ключи" + description: "Как устроена реляционная база данных изнутри: таблицы, записи и атрибуты, первичные и внешние ключи, типы данных столбцов. Разбор структуры с примерами и упражнениями." --- # Структура реляционных баз данных -Мы кратко уже знакомились с реляционными базами данных в предыдущей статье. Но нам ведь недостаточно +Мы кратко уже знакомились с реляционными базами данных в предыдущей статье. Но нам ведь недостаточно поверхностного понимания? Давайте заплывём за буйки и погрузимся глубже в структуру и терминологию реляционных баз данных. @@ -18,7 +18,7 @@ meta: - строк, которые называют «записями» - столбцов, которые называют «полями» или же «атрибутами» -![Структура таблицы](https://sql-academy.org/static/guidePage/structure-of-relation-databases/ru_structure_db.png 'Структура таблицы') +![Структура таблицы](https://sql-academy.org/static/guidePage/structure-of-relation-databases/ru_structure_db.png "Структура таблицы") В каждой таблице каждый столбец имеет заранее определённый тип данных. Например, такими типами могут выступать: @@ -29,22 +29,22 @@ meta: И каждая строка таблицы должна иметь соответствующий тип для каждого столбца. СУБД не допустит попытку добавления в поле с типом `DATETIME` произвольной строки. -Для того чтобы узнать типы данных атрибутов, можно выполнить SQL команду и указать название таблицы. +Для того чтобы узнать типы данных атрибутов, можно выполнить SQL команду и указать название таблицы: -Для MySQL нужно выполнить SQL-команду `DESCRIBE` +**MySQL** ```sql DESCRIBE FamilyMembers ``` -| Field | Type | Null | Key | -| ----------- | ----------- | ---- | --- | -| member_id | int | NO | PRI | -| status | varchar(50) | NO | | -| member_name | varchar(50) | NO | | -| birthday | datetime | NO | | +| Field | Type | Null | Key | Default | Extra | +| ----------- | ----------- | ---- | --- | ------- | ----- | +| member_id | int | NO | PRI | | | +| status | varchar(50) | NO | | | | +| member_name | varchar(50) | NO | | | | +| birthday | datetime | NO | | | | -Для PostgreSQL можно воспользоваться SQL-запросом к информационной схеме: +**PostgreSQL** ```sql SELECT column_name, data_type, is_nullable @@ -62,13 +62,15 @@ WHERE table_name = 'familymembers' Или же посмотреть на ER-диаграмму схемы базы данных: +ER-диаграмма базы данных Family: [открыть на SQL Academy](https://sql-academy.org/ru/guide/structure-of-relation-databases). + ## Первичный ключ Любая СУБД имеет встроенную систему целостности и непротиворечивости данных. Эта система работает на наборе правил, определённых в схеме базы данных. Первичный ключ и внешние ключи как раз являются одними из таких правил. -Чтобы избегать неоднозначности при поиске в таблицах, существует первичный ключ или, как его ещё называют, +Чтобы избежать неоднозначности при поиске в таблицах, существует первичный ключ или, как его ещё называют, «ключевое поле». > Ключевое поле (первичный ключ) – это поле (или набор полей), значение которого однозначно определяет запись в таблице. @@ -87,10 +89,18 @@ WHERE table_name = 'familymembers' Правило внешнего ключа гарантирует, что при создании записей в дочерней таблице, значение поля, являющегося внешним ключом, есть в родительской таблице. -![Пример внешних ключей](https://sql-academy.org/static/guidePage/structure-of-relation-databases/ru_keys.png 'Пример внешних ключей') +![Пример внешних ключей](https://sql-academy.org/static/guidePage/structure-of-relation-databases/ru_keys.png "Пример внешних ключей") Наличие внешнего ключа – это такое же необязательное требование, как и в случае с первичным ключом. Если внешний ключ не определён, то всё также будет работать, но СУБД не будет проверять, что, например, при создании записи в таблице `Purchase` в полях `buyer_id` и `good_id` лежат значения, которые определены в соответствующих таблицах в поле `id`. + +Какое из утверждений **неверное** относительно ключей в реляционных СУБД? + +1. В каждой таблице может быть лишь 1 первичный ключ — В каждой таблице может быть лишь только 1 первичный ключ, благодаря которому можно однозначно определить запись в таблице. Это ключ может состоять из нескольких полей таблицы, но он всегда один. + +2. Таблица может содержать как несколько внешних ключей, так и ни одного внешнего ключа — Определение правила внешнего ключа - опциональное, его может и не быть. В тоже время, если у таблицы несколько полей, отсылающих к идентификаторам других таблиц, то мы можем определить несколько внешних ключей. + +3. **Правильный ответ:** Правила первичного и внешнего ключа служат для одной цели — Все же цели у правила первичного ключа и правила внешнего ключа разные. Первичный ключ отвечает за обеспечение однозначного определения каждой записи внутри одной таблицы. Внешний же ключ отвечает за ссылочную целостность. diff --git a/course/module-2/aggregate-functions/article.md b/course/module-2/aggregate-functions/article.md index 19cc027..c597a63 100644 --- a/course/module-2/aggregate-functions/article.md +++ b/course/module-2/aggregate-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Агрегатные функции' - description: 'Агрегатные функции в SQL запросах, синтаксис и примеры' + title: "Агрегатные функции" + description: "Агрегатные функции в SQL запросах, синтаксис и примеры" --- # Агрегатные функции @@ -46,9 +46,9 @@ GROUP BY home_type ## Примеры - +ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/aggregate-functions). -- Найдём количество каждого вида жилья и отсортируем полученный список по убыванию: +- Найдём количество каждого вида жилья и отсортируем полученный список по убыванию: ```sql SELECT home_type, COUNT(*) as amount FROM Rooms @@ -62,30 +62,30 @@ GROUP BY home_type | Entire home/apt | 21 | | Shared room | 1 | -- Для каждого жилого помещения найдём самую позднюю дату выезда (поле `end_date`) +- Для каждого жилого помещения найдём самую позднюю дату выезда (поле `end_date`) ```sql SELECT room_id, MAX(end_date) AS last_end_date FROM Reservations GROUP BY room_id ``` - | room_id | last_end_date | - | ------- | -------------------- | - | 1 | 2019-02-04T12:00:00Z | - | 2 | 2020-03-23T09:00:00Z | - | 13 | 2020-04-21T10:00:00Z | - | 16 | 2019-06-24T10:00:00Z | - | 21 | 2020-02-29T10:00:00Z | - | 19 | 2020-05-02T10:00:00Z | - | 8 | 2020-01-21T12:00:00Z | - | 7 | 2019-09-17T10:00:00Z | - | 5 | 2020-05-15T10:00:00Z | - | 50 | 2019-11-25T11:00:00Z | - | 49 | 2020-06-11T10:00:00Z | - | 48 | 2019-11-10T10:00:00Z | - | 32 | 2020-01-18T13:00:00Z | - | 17 | 2019-11-05T09:00:00Z | - | 25 | 2020-04-22T09:00:00Z | - | 14 | 2020-02-12T10:00:00Z | - | 39 | 2019-12-09T10:00:00Z | - | 38 | 2020-03-23T10:00:00Z | + | room_id | last_end_date | + | ------- | ------------------------ | + | 1 | 2019-02-04T12:00:00.000Z | + | 2 | 2020-03-23T09:00:00.000Z | + | 13 | 2020-04-21T10:00:00.000Z | + | 16 | 2019-06-24T10:00:00.000Z | + | 21 | 2020-02-29T10:00:00.000Z | + | 19 | 2020-05-02T10:00:00.000Z | + | 8 | 2020-01-21T12:00:00.000Z | + | 7 | 2019-09-17T10:00:00.000Z | + | 5 | 2020-05-15T10:00:00.000Z | + | 50 | 2019-11-25T11:00:00.000Z | + | 49 | 2020-06-11T10:00:00.000Z | + | 48 | 2019-11-10T10:00:00.000Z | + | 32 | 2020-01-18T13:00:00.000Z | + | 17 | 2019-11-05T09:00:00.000Z | + | 25 | 2020-04-22T09:00:00.000Z | + | 14 | 2020-02-12T10:00:00.000Z | + | 39 | 2019-12-09T10:00:00.000Z | + | 38 | 2020-03-23T10:00:00.000Z | diff --git a/course/module-2/basic-syntax-sql-query/article.md b/course/module-2/basic-syntax-sql-query/article.md index 1e132e4..1207f6d 100644 --- a/course/module-2/basic-syntax-sql-query/article.md +++ b/course/module-2/basic-syntax-sql-query/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Базовый синтаксис SQL запроса' - description: 'Пример простых SQL запросов к базе данных. Использование псевдонимов (алиасов) в SQL запросах.' + title: "Базовый синтаксис SQL запроса" + description: "Пример простых SQL запросов к базе данных. Использование псевдонимов (алиасов) в SQL запросах." --- # Базовый синтаксис SQL запроса @@ -15,7 +15,7 @@ meta: но и произвольные строки, числа, даты и т.д. Например, так можно вывести произвольную строку: ```sql -SELECT "Hello world" +SELECT 'Hello world' ``` ## Вывод всех данных из таблицы @@ -23,21 +23,21 @@ SELECT "Hello world" Для вывода всех полей из определённой таблицы используется символ `*`. Давайте взглянем на схему базы данных и выведем данные одной из таблиц. - +ER-диаграмма базы данных Family: [открыть на SQL Academy](https://sql-academy.org/ru/guide/basic-syntax-sql-query). ```sql SELECT * FROM FamilyMembers ``` -| member_id | status | member_name | birthday | -| --------- | -------- | ----------------- | -------------------- | -| 1 | father | Headley Quincey | 1960-05-13T00:00:00Z | -| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00Z | -| 3 | son | Andie Quincey | 1983-06-05T00:00:00Z | -| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00Z | -| 5 | daughter | Annie Quincey | 1988-04-10T00:00:00Z | -| 6 | father | Ernest Forrest | 1961-09-11T00:00:00Z | -| 7 | mother | Constance Forrest | 1968-09-06T00:00:00Z | +| member_id | status | member_name | birthday | +| --------- | -------- | ----------------- | ------------------------ | +| 1 | father | Headley Quincey | 1960-05-13T00:00:00.000Z | +| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00.000Z | +| 3 | son | Andie Quincey | 1983-06-05T00:00:00.000Z | +| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00.000Z | +| 5 | daughter | Annie Quincey | 1988-04-10T00:00:00.000Z | +| 6 | father | Ernest Forrest | 1961-09-11T00:00:00.000Z | +| 7 | mother | Constance Forrest | 1968-09-06T00:00:00.000Z | ## Вывод данных из определённых колонок таблицы diff --git a/course/module-2/conditional-where-operator/article.md b/course/module-2/conditional-where-operator/article.md index 40a42a6..b420161 100644 --- a/course/module-2/conditional-where-operator/article.md +++ b/course/module-2/conditional-where-operator/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Условный оператор WHERE" - description: "Условный оператор WHERE в SQL запросе. Логические операторы и операторы сравнение. Примеры SELECT FROM WHERE" + title: "Условный оператор WHERE" + description: "Условный оператор WHERE в SQL запросе. Логические операторы и операторы сравнение. Примеры SELECT FROM WHERE" --- # Условный оператор WHERE @@ -21,40 +21,37 @@ WHERE условие_на_ограничение_строк Например, запрос с использованием оператора `WHERE` может выглядеть следующим образом: - +**MySQL** -```sql-executable-Schedule +```sql SELECT * FROM Student WHERE first_name = "Grigorij" AND YEAR(birthday) > 2000; ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql SELECT * FROM Student WHERE first_name = 'Grigorij' AND EXTRACT(YEAR FROM birthday) > 2000; ``` - +| id | first_name | middle_name | last_name | birthday | address | +| --- | ---------- | ----------- | --------- | ------------------------ | ------------------------------- | +| 33 | Grigorij | Gennadevich | Kapustin | 2001-12-13T00:00:00.000Z | ul. Pervomajskaya, d. 45, kv. 6 | +| 65 | Grigorij | Kirillovich | Kolobov | 2003-07-17T00:00:00.000Z | ul. CHernova, d. 9, kv. 34 | В этом примере мы используем сразу два условия: - +**MySQL** - `first_name = "Grigorij"` — имя студента должно быть «Grigorij» - `YEAR(birthday) > 2000` — год рождения больше 2000 - - - +**PostgreSQL** - `first_name = 'Grigorij'` — имя студента должно быть «Grigorij» - `EXTRACT(YEAR FROM birthday) > 2000` — год рождения больше 2000 - - Между ними стоит логический оператор `AND`, который требует, чтобы оба условия выполнялись одновременно. В результате мы получаем только тех студентов, которые подходят под оба критерия. ## Операторы сравнения @@ -65,7 +62,7 @@ WHERE first_name = 'Grigorij' AND EXTRACT(YEAR FROM birthday) > 2000; - `false` (то же, что 0) - `NULL` (если результат сравнения не определён, например, при сравнении с NULL) - +**MySQL** | Оператор | Обозначение | Описание | | :--------------- | :------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -79,9 +76,7 @@ WHERE first_name = 'Grigorij' AND EXTRACT(YEAR FROM birthday) > 2000; > Результатом сравнения любого значения с `NULL` является `NULL`. Исключением является оператор эквивалентности. - - - +**PostgreSQL** | Оператор | Обозначение | Описание | | :--------------- | :------------ | --------------------------------------------------------------------------------------- | @@ -94,13 +89,11 @@ WHERE first_name = 'Grigorij' AND EXTRACT(YEAR FROM birthday) > 2000; > Результатом сравнения любого значения с `NULL` является `NULL`. - - Попробуйте сами поиграться с этими операторами в песочнице и посмотреть, какие результаты они дадут: - +**MySQL** -```sql-executable +```sql SELECT 2 = 1, 'a' = 'a', @@ -113,22 +106,26 @@ SELECT 8 >= 10; ``` - +| 2 = 1 | 'a' = 'a' | 1 \<=> NULL | NULL \<=> NULL | 2 \<> 2 | 3 \< 4 | 10 \<= 10 | 7 > 1 | 8 >= 10 | +| ----- | --------- | ----------- | -------------- | ------- | ------ | --------- | ----- | ------- | +| 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | - +**PostgreSQL** -```sql-executable +```sql SELECT - 2 = 1, - 'a' = 'a', - 2 <> 2, - 3 < 4, - 10 <= 10, - 7 > 1, - 8 >= 10; + 2 = 1 AS "2 = 1", + 'a' = 'a' AS "'a' = 'a'", + 2 <> 2 AS "2 <> 2", + 3 < 4 AS "3 < 4", + 10 <= 10 AS "10 <= 10", + 7 > 1 AS "7 > 1", + 8 >= 10 AS "8 >= 10"; ``` - +| 2 = 1 | 'a' = 'a' | 2 \<> 2 | 3 \< 4 | 10 \<= 10 | 7 > 1 | 8 >= 10 | +| ----- | --------- | ------- | ------ | --------- | ----- | ------- | +| false | true | false | true | true | true | false | ## Логические операторы @@ -136,121 +133,114 @@ SELECT - `AND` — оба условия должны быть верны. - Представьте, что вы ищете рейсы, которые одновременно соответствуют двум требованиям: например, самолёт должен быть определённой модели, и вылетать не из какого-то города. Оператор `AND` помогает объединить эти условия. - - + Представьте, что вы ищете рейсы, которые одновременно соответствуют двум требованиям: например, самолёт должен быть определённой модели, и вылетать из какого-то города. Оператор `AND` помогает объединить эти условия. - ```sql-executable - SELECT * FROM Trip - WHERE plane = 'Boeing' AND town_from = 'London'; - ``` + **MySQL** - + ```sql + SELECT * FROM Trip + WHERE plane = 'Boeing' AND town_from = 'London'; + ``` - + **PostgreSQL** - ```sql-executable - SELECT * FROM Trip - WHERE plane = 'Boeing' AND town_from = 'London'; - ``` + ```sql + SELECT * FROM Trip + WHERE plane = 'Boeing' AND town_from = 'London'; + ``` - + | id | company | plane | town_from | town_to | time_out | time_in | + | ---- | ------- | ------ | --------- | --------- | ------------------------ | ------------------------ | + | 7771 | 5 | Boeing | London | Singapore | 1900-01-01T01:00:00.000Z | 1900-01-01T11:00:00.000Z | + | 7773 | 5 | Boeing | London | Singapore | 1900-01-01T03:00:00.000Z | 1900-01-01T13:00:00.000Z | + | 7775 | 5 | Boeing | London | Singapore | 1900-01-01T09:00:00.000Z | 1900-01-01T20:00:00.000Z | + | 7777 | 5 | Boeing | London | Singapore | 1900-01-01T18:00:00.000Z | 1900-01-02T06:00:00.000Z | + | 8881 | 5 | Boeing | London | Paris | 1900-01-01T03:00:00.000Z | 1900-01-01T04:00:00.000Z | - Такой запрос выберет только те рейсы, где модель самолёта — `Boeing` и город вылета — `London`. + Такой запрос выберет только те рейсы, где модель самолёта — `Boeing` и город вылета — `London`. - Если хотя бы одно из условий не выполняется (например, самолёт не `Boeing` или вылет не из `London`), такой рейс не попадёт в результат. + Если хотя бы одно из условий не выполняется (например, самолёт не `Boeing` или вылет не из `London`), такой рейс не попадёт в результат. - `OR` — достаточно, чтобы выполнилось хотя бы одно условие. - Оператор `OR` работает как "или". Если хотя бы одно из условий верно — строка попадёт в результат. Это удобно, когда вы хотите увидеть все рейсы, которые соответствуют хотя бы одному из ваших критериев. + Оператор `OR` работает как "или". Если хотя бы одно из условий верно — строка попадёт в результат. Это удобно, когда вы хотите увидеть все рейсы, которые соответствуют хотя бы одному из ваших критериев. - + **MySQL** - ```sql-executable - SELECT * FROM Trip - WHERE town_to = 'Paris' OR plane = 'Airbus'; - ``` + ```sql + SELECT * FROM Trip + WHERE town_to = 'Paris' OR plane = 'Airbus'; + ``` - + **PostgreSQL** - + ```sql + SELECT * FROM Trip + WHERE town_to = 'Paris' OR plane = 'Airbus'; + ``` - ```sql-executable - SELECT * FROM Trip - WHERE town_to = 'Paris' OR plane = 'Airbus'; - ``` + | id | company | plane | town_from | town_to | time_out | time_in | + | ---- | ------- | ------ | --------- | ------- | ------------------------ | ------------------------ | + | 1100 | 4 | Boeing | Rostov | Paris | 1900-01-01T14:30:00.000Z | 1900-01-01T17:50:00.000Z | + | 8881 | 5 | Boeing | London | Paris | 1900-01-01T03:00:00.000Z | 1900-01-01T04:00:00.000Z | - + В результате вы получите все рейсы, которые прилетают в `Paris`, а также все рейсы на самолёте `Airbus` (даже если они летят не в `Paris`). - В результате вы получите все рейсы, которые прилетают в `Paris`, а также все рейсы на самолёте `Airbus` (даже если они летят не в `Paris`). - - Если рейс и на `Airbus`, и в `Paris` — он тоже попадёт в результат. + Если рейс и на `Airbus`, и в `Paris` — он тоже попадёт в результат. - `NOT` — условие становится противоположным. - Оператор `NOT` инвертирует условие: если оно было истинным, станет ложным, и наоборот. Это удобно, когда вы хотите исключить какие-то значения. - - - - ```sql-executable - SELECT * FROM Trip WHERE NOT town_to = 'Moscow'; - ``` + Оператор `NOT` инвертирует условие: если оно было истинным, станет ложным, и наоборот. Это удобно, когда вы хотите исключить какие-то значения. - + **MySQL** - + ```sql + SELECT * FROM Trip WHERE NOT town_to = 'Moscow'; + ``` - ```sql-executable - SELECT * FROM Trip WHERE NOT town_to = 'Moscow'; - ``` + **PostgreSQL** - + ```sql + SELECT * FROM Trip WHERE NOT town_to = 'Moscow'; + ``` - Такой запрос выберет все рейсы, которые прилетают **не** в `Moscow`. + Такой запрос выберет все рейсы, которые прилетают **не** в `Moscow`. - То есть, если город прилёта — `Moscow`, такой рейс не попадёт в результат. Всё остальное — попадёт. + То есть, если город прилёта — `Moscow`, такой рейс не попадёт в результат. Всё остальное — попадёт. - `XOR` — это оператор, который помогает выбрать строки, где выполняется только одно из двух условий, но не оба сразу. - Допустим, вы хотите найти рейсы, которые или вылетают из `Moscow`, или прилетают в `Paris`, но не оба варианта сразу. Давайте посмотрим на все возможные случаи: - - | Вылетает
из Moscow | Прилетает
в Paris | Попадёт
в результат | Объяснение | - | :----------------------: | :---------------------: | :-----------------------: | ---------------------------------------------------- | - | Да | Нет | ✅ Да | Выполняется только первое условие | - | Нет | Да | ✅ Да | Выполняется только второе условие | - | Да | Да | ❌ Нет | Выполняются оба условия — XOR исключает такие случаи | - | Нет | Нет | ❌ Нет | Не выполняется ни одно условие | - - + Допустим, вы хотите найти рейсы, которые или вылетают из `Moscow`, или прилетают в `Paris`, но не оба варианта сразу. Давайте посмотрим на все возможные случаи: - ```sql-executable - SELECT * FROM trip - WHERE town_from = 'Moscow' XOR town_to = 'Paris'; - ``` + | Вылетает
из Moscow | Прилетает
в Paris | Попадёт
в результат | Объяснение | + | :----------------------: | :---------------------: | :-----------------------: | ---------------------------------------------------- | + | Да | Нет | ✅ Да | Выполняется только первое условие | + | Нет | Да | ✅ Да | Выполняется только второе условие | + | Да | Да | ❌ Нет | Выполняются оба условия — XOR исключает такие случаи | + | Нет | Нет | ❌ Нет | Не выполняется ни одно условие | -
+ **MySQL** - + ```sql + SELECT * FROM trip + WHERE town_from = 'Moscow' XOR town_to = 'Paris'; + ``` - ```sql-executable - SELECT * FROM trip - WHERE (town_from = 'Moscow' AND town_to != 'Paris') - OR (town_from != 'Moscow' AND town_to = 'Paris'); - ``` + **PostgreSQL** - + ```sql + SELECT * FROM trip + WHERE (town_from = 'Moscow' AND town_to != 'Paris') + OR (town_from != 'Moscow' AND town_to = 'Paris'); + ``` - + **MySQL** - > Обратите внимание: оператор XOR есть не во всех базах данных. Если его нет, можно обойтись комбинацией AND и OR. + > Обратите внимание: оператор XOR есть не во всех базах данных. Если его нет, можно обойтись комбинацией AND и OR. - + **PostgreSQL** - - - > В PostgreSQL нет оператора XOR, поэтому используется комбинация AND и OR для достижения того же результата. - - + > В PostgreSQL нет оператора XOR, поэтому используется комбинация AND и OR для достижения того же результата. ## Приоритет логических операторов @@ -267,9 +257,9 @@ SELECT Посмотрим на такой пример: - +**MySQL** -```sql-executable +```sql SELECT * FROM Trip WHERE town_to = 'Paris' @@ -277,11 +267,9 @@ WHERE town_to = 'Paris' AND NOT town_from = 'Moscow'; ``` - - - +**PostgreSQL** -```sql-executable +```sql SELECT * FROM Trip WHERE town_to = 'Paris' @@ -289,7 +277,20 @@ WHERE town_to = 'Paris' AND NOT town_from = 'Moscow'; ``` - +| id | company | plane | town_from | town_to | time_out | time_in | +| ---- | ------- | ------ | --------- | --------- | ------------------------ | ------------------------ | +| 1100 | 4 | Boeing | Rostov | Paris | 1900-01-01T14:30:00.000Z | 1900-01-01T17:50:00.000Z | +| 1101 | 4 | Boeing | Paris | Rostov | 1900-01-01T08:12:00.000Z | 1900-01-01T11:45:00.000Z | +| 7771 | 5 | Boeing | London | Singapore | 1900-01-01T01:00:00.000Z | 1900-01-01T11:00:00.000Z | +| 7772 | 5 | Boeing | Singapore | London | 1900-01-01T12:00:00.000Z | 1900-01-02T02:00:00.000Z | +| 7773 | 5 | Boeing | London | Singapore | 1900-01-01T03:00:00.000Z | 1900-01-01T13:00:00.000Z | +| 7774 | 5 | Boeing | Singapore | London | 1900-01-01T14:00:00.000Z | 1900-01-02T06:00:00.000Z | +| 7775 | 5 | Boeing | London | Singapore | 1900-01-01T09:00:00.000Z | 1900-01-01T20:00:00.000Z | +| 7776 | 5 | Boeing | Singapore | London | 1900-01-01T18:00:00.000Z | 1900-01-02T08:00:00.000Z | +| 7777 | 5 | Boeing | London | Singapore | 1900-01-01T18:00:00.000Z | 1900-01-02T06:00:00.000Z | +| 7778 | 5 | Boeing | Singapore | London | 1900-01-01T22:00:00.000Z | 1900-01-02T12:00:00.000Z | +| 8881 | 5 | Boeing | London | Paris | 1900-01-01T03:00:00.000Z | 1900-01-01T04:00:00.000Z | +| 8882 | 5 | Boeing | Paris | London | 1900-01-01T22:00:00.000Z | 1900-01-01T23:00:00.000Z | Что здесь происходит: @@ -306,9 +307,9 @@ WHERE town_to = 'Paris' Если вы хотите изменить порядок проверки условий или сделать его более понятным, используйте **скобки**. Всё, что в скобках, выполняется в первую очередь. К примеру, если вручную расставить скобки согласно приоритетам логических операторов, то сразу становится понятно, как будет выполняться запрос! - +**MySQL** -```sql-executable +```sql SELECT * FROM Trip WHERE ( @@ -320,11 +321,9 @@ WHERE ( ); ``` - +**PostgreSQL** - - -```sql-executable +```sql SELECT * FROM Trip WHERE ( @@ -336,6 +335,10 @@ WHERE ( ); ``` - - А теперь попробуйте сами: допустим, вы хотите получить список рейсов, которые вылетают из `Paris` или на самолёте `Boeing`, и летят **не** в `Moscow`. Это можно сделать, правильно расставив скобки в исходном запросе из примера. Как бы вы это сделали? + +1. town_from = 'Paris' OR (plane = 'Boeing' AND NOT town_to = 'Moscow'); — Этот вариант выберет все рейсы из Paris, а также рейсы на Boeing, которые не летят в Moscow. Скобки расставлены неверно: рейсы из Paris попадут в выборку даже если они летят в Moscow. + +2. **Правильный ответ:** (town_from = 'Paris' OR plane = 'Boeing') AND NOT town_to = 'Moscow'; — Такой запрос выберет рейсы, которые либо из Paris, либо на Boeing, и при этом не летят в Moscow. + +3. town_from = 'Paris' OR plane = 'Boeing' AND NOT town_to = 'Moscow'; — Этот вариант без скобок будет работать не так, как ожидается: сначала выполнится AND, а затем OR. Это приведёт к неверному результату diff --git a/course/module-2/distinct-operator/article.md b/course/module-2/distinct-operator/article.md index 6dc49c2..b069974 100644 --- a/course/module-2/distinct-operator/article.md +++ b/course/module-2/distinct-operator/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Исключение дубликатов, оператор DISTINCT' - description: 'Примеры для чего необходим SQL оператор DISTINCT, исключение повторений в SQL для одной и нескольких колонок.' + title: "Исключение дубликатов, оператор DISTINCT" + description: "Примеры для чего необходим SQL оператор DISTINCT, исключение повторений в SQL для одной и нескольких колонок." --- # Исключение дубликатов, DISTINCT @@ -10,7 +10,7 @@ meta: Например, давайте выведем поле `class` из таблицы `Student_in_class` из базы данных, в которой организовано хранение информации о расписании занятий в школе. - +ER-диаграмма базы данных Schedule: [открыть на SQL Academy](https://sql-academy.org/ru/guide/distinct-operator). ```sql SELECT class FROM Student_in_class; @@ -30,6 +30,7 @@ SELECT class FROM Student_in_class; | 9 | | 9 | | 9 | +| 9 | | 8 | | 8 | | 8 | @@ -51,6 +52,7 @@ SELECT class FROM Student_in_class; | 6 | | 6 | | 6 | +| 6 | | 5 | | 5 | | 5 | @@ -104,7 +106,7 @@ SELECT [DISTINCT] поля_таблиц FROM наименование_табли То есть в нашем случае запрос на получение уникальных классов, в которых есть хотя бы один студент, будет выглядеть следующим образом: -``` +```sql SELECT DISTINCT class FROM Student_in_class; ``` diff --git a/course/module-2/groupping/article.md b/course/module-2/groupping/article.md index d65422a..d99ae41 100644 --- a/course/module-2/groupping/article.md +++ b/course/module-2/groupping/article.md @@ -1,17 +1,59 @@ --- meta: - title: "Группировка, оператор GROUP BY" - description: "Структура SQL запроса с оператором группировки group by, группировка по нескольким полям и примеры" + title: "Группировка, оператор GROUP BY" + description: "Структура SQL запроса с оператором группировки group by, группировка по нескольким полям и примеры" --- # Группировка, оператор GROUP BY Давайте выполним запрос: -```sql-executable-Airbnb +```sql SELECT id, home_type, has_tv, price FROM Rooms; ``` +**MySQL** + +| id | home_type | has_tv | price | +| --- | --------------- | ------ | ----- | +| 1 | Private room | 1 | 149 | +| 2 | Entire home/apt | 0 | 225 | +| 3 | Private room | 1 | 150 | +| 4 | Entire home/apt | 1 | 89 | +| 5 | Entire home/apt | 0 | 80 | +| 6 | Entire home/apt | 0 | 200 | +| 7 | Private room | 0 | 60 | +| 8 | Private room | 1 | 79 | +| 9 | Private room | 1 | 79 | +| 10 | Entire home/apt | 1 | 150 | +| 11 | Entire home/apt | 1 | 135 | +| 12 | Private room | 0 | 85 | +| 13 | Private room | 0 | 89 | +| 14 | Private room | 0 | 85 | +| 15 | Entire home/apt | 1 | 120 | +| 40 | Shared room | 1 | 40 | + +**PostgreSQL** + +| id | home_type | has_tv | price | +| --- | --------------- | ------ | ----- | +| 1 | Private room | true | 149 | +| 2 | Entire home/apt | false | 225 | +| 3 | Private room | true | 150 | +| 4 | Entire home/apt | true | 89 | +| 5 | Entire home/apt | false | 80 | +| 6 | Entire home/apt | false | 200 | +| 7 | Private room | false | 60 | +| 8 | Private room | true | 79 | +| 9 | Private room | true | 79 | +| 10 | Entire home/apt | true | 150 | +| 11 | Entire home/apt | true | 135 | +| 12 | Private room | false | 85 | +| 13 | Private room | false | 89 | +| 14 | Private room | false | 85 | +| 15 | Entire home/apt | true | 120 | +| 40 | Shared room | true | 40 | + Так мы получили информацию по каждому сдаваемому жилому помещению. А что если мы хотим получить информацию не о каждой записи отдельно, а о группах, которые они образуют? Например, такими группами могут выступать записи, разбитые по типу жилья: @@ -39,11 +81,17 @@ GROUP BY поля_группировки; Для того, чтобы записи у нас образовали группы по типу жилья, мы должны после `GROUP BY` указать `home_type`, т.е. поле, по которому будет происходить группировка. -```sql-executable-Airbnb +```sql SELECT home_type FROM Rooms GROUP BY home_type ``` +| home_type | +| --------------- | +| Private room | +| Entire home/apt | +| Shared room | + > Следует иметь в виду, что для `GROUP BY` все значения `NULL` трактуются как равные, > т.е. при группировке по полю, содержащему `NULL`-значения, все такие строки попадут в одну группу @@ -55,44 +103,62 @@ GROUP BY home_type - литералы, т.е. указанные явным образом фиксированные значения. - Мы можем их выводить, так как это фиксированные значения, которые ни от чего не зависят. - Например, + Мы можем их выводить, так как это фиксированные значения, которые ни от чего не зависят.\ + Например, + + ```sql + SELECT home_type, 'literal' FROM Rooms + GROUP BY home_type + ``` - ```sql-executable-Airbnb - SELECT home_type, 'literal' FROM Rooms - GROUP BY home_type - ``` + | home_type | literal | + | --------------- | ------- | + | Private room | literal | + | Entire home/apt | literal | + | Shared room | literal | - результаты агрегатных функций, т.е. вычисленные значения на основании набора значений. - Более детальную информацию об агрегатных функциях мы затронем на следующем уроке. Но для примера рассмотрим агрегатную функцию `AVG`. - Функция `AVG` принимает в качестве аргумента название поля, по которому мы хотим вычислить среднее значение для каждой группы. + Более детальную информацию об агрегатных функциях мы затронем на следующем уроке. Но для примера рассмотрим агрегатную функцию `AVG`.\ + Функция `AVG` принимает в качестве аргумента название поля, по которому мы хотим вычислить среднее значение для каждой группы. - ```sql-executable-Airbnb - SELECT home_type, AVG(price) as avg_price FROM Rooms - GROUP BY home_type - ``` + ```sql + SELECT home_type, AVG(price) as avg_price FROM Rooms + GROUP BY home_type + ``` - Так, выполненный запрос сначала разбивает все записи из таблицы `Rooms` на 3 группы, опираясь на поле `home_type`. - Далее, для каждой группы суммирует все значения, взятые из поля `price` у каждой записи, входящей в текущую группу, и затем полученный результат - делится на количество записей в данной группе. + | home_type | avg_price | + | --------------- | --------- | + | Private room | 89.4286 | + | Entire home/apt | 148.6667 | + | Shared room | 40 | + + Так, выполненный запрос сначала разбивает все записи из таблицы `Rooms` на 3 группы, опираясь на поле `home_type`. + Далее, для каждой группы суммирует все значения, взятые из поля `price` у каждой записи, входящей в текущую группу, и затем полученный результат + делится на количество записей в данной группе. - поля группировки. - Мы можем их выводить, так как в рамках одной группы поля, по которым осуществлялась группировка, одинаковые. + Мы можем их выводить, так как в рамках одной группы поля, по которым осуществлялась группировка, одинаковые. ## Группировка по 2 и более полям Мы уже рассмотрели, как записи в таблице группируются по одному полю. Для дополнительной иллюстрации это выглядит примерно так, когда поле группировки `home_type`: - ![Группировка по 1 полю](https://sql-academy.org/static/guidePage/groupping/groupping_by_1_field.png 'Группировка по 1 полю') +![Группировка по 1 полю](https://sql-academy.org/static/guidePage/groupping/groupping_by_1_field.png "Группировка по 1 полю") - При группировке по 2 и более полям принцип остается такой же, только теперь образовавшиеся группы дополнительно разбиваются на более мелкие группы в зависимости - от второго поля группировки. +При группировке по 2 и более полям принцип остается такой же, только теперь образовавшиеся группы дополнительно разбиваются на более мелкие группы в зависимости +от второго поля группировки. - Пример группировки по `home_type` и `has_tv`: +Пример группировки по `home_type` и `has_tv`: - ![Группировка по 2 полям](https://sql-academy.org/static/guidePage/groupping/groupping_by_2_field.png 'Группировка по 2 полям') +![Группировка по 2 полям](https://sql-academy.org/static/guidePage/groupping/groupping_by_2_field.png "Группировка по 2 полям") Давайте проверим себя? При использовании оператора `GROUP BY` в `SELECT` выражение мы можем выводить: + +1. **Правильный ответ:** Только литералы, результаты агрегатных функции и поля группировки — При группировке в SELECT можно выводить только литералы, результаты агрегатных функций и поля, по которым осуществлялась группировка + +2. Все те же самые поля, что мы могли выводить по каждой записи в таблице — При группировке в SELECT можно выводить только литералы, результаты агрегатных функций и поля, по которым осуществлялась группировка. + +3. Только литералы и результаты агрегатных функций — Помимо литералов и результатов агрегатных функции можно также выводить и поля, по которым осуществлялась группировка diff --git a/course/module-2/is-null-between-in-operators/article.md b/course/module-2/is-null-between-in-operators/article.md index 23399f2..8a382dc 100644 --- a/course/module-2/is-null-between-in-operators/article.md +++ b/course/module-2/is-null-between-in-operators/article.md @@ -1,16 +1,16 @@ --- meta: - title: 'Операторы IS NULL, BETWEEN, IN' - description: 'Синтаксис и примеры использования SQL операторов IS NULL, BETWEEN, IN' + title: "Операторы IS NULL, BETWEEN, IN" + description: "Синтаксис и примеры использования SQL операторов IS NULL, BETWEEN, IN" --- # Операторы IS NULL, BETWEEN, IN Мы уже познакомились с синтаксисом оператора `WHERE` и операторами сравнения, но помимо них в условных запросах мы можем использовать следующие полезные операторы: -- `IS NULL` -- `BETWEEN` -- `IN` +- `IS NULL` +- `BETWEEN` +- `IN` Давайте рассмотрим их применение. diff --git a/course/module-2/literals/article.md b/course/module-2/literals/article.md index e2b3ab8..37dc6da 100644 --- a/course/module-2/literals/article.md +++ b/course/module-2/literals/article.md @@ -1,14 +1,14 @@ --- meta: - title: "Литералы в SQL" - description: 'Литерал — указанное явным образом фиксированное значение, например, число 12 или строка "SQL". В MySQL существуют следующие типы литералов: числовой, строковый, логический, NULL, битовый, шестнадцатеричный и литерал даты и времени.' + title: "Литералы в SQL" + description: 'Литерал — указанное явным образом фиксированное значение, например, число 12 или строка "SQL". В MySQL существуют следующие типы литералов: числовой, строковый, логический, NULL, битовый, шестнадцатеричный и литерал даты и времени.' --- # Литералы в SQL На прошлом уроке выводили строку, а если говорить более формальным языком, то так называемый строковый литерал. -```sql-executable +```sql SELECT 'Hello world' ``` @@ -24,31 +24,51 @@ SELECT 'Hello world' ## Строковые литералы - +**MySQL** Строка — это последовательность символов, заключённых в одинарные (') или двойные (") кавычки. Например, `'это строка'` и `"это строка"`. - - - +**PostgreSQL** Строка — это последовательность символов, заключённых в одинарные кавычки ('). Например, `'это строка'`. В PostgreSQL двойные кавычки (") используются для идентификаторов (имен таблиц, столбцов), для строковых литералов их использовать нельзя. - +**MySQL** Строки могут содержать специальные последовательности символов, начинающиеся с `"\"` (экранирующий символ). Они нужны для того, чтобы СУБД придала обычным символам (буквам и другим знакам) новое особое значение. Например, последовательность `"\n"` буквально означает "перевод строки", а без предваряющего слеша это была бы обычная буква `"n"`. -- ```sql-Family-executable +**PostgreSQL** + +Строки могут содержать специальные последовательности символов, начинающиеся с `"\"` (экранирующий символ). Они нужны для того, чтобы СУБД придала обычным символам (буквам и другим знакам) новое особое значение. Например, последовательность `"\n"` буквально означает "перевод строки", а без предваряющего слеша это была бы обычная буква `"n"`. + +Для использования escape-последовательностей в PostgreSQL необходимо использовать E-строки. + +- ```sql SELECT 'Строка Другая строка' as String ``` -- ```sql-Family-executable - SELECT 'Строка \n Другая строка' as String - ``` + | String | + | -------------------- | + | Строка Другая строка | + +- **MySQL** + + ```sql + SELECT 'Строка \n Другая строка' as String + ``` + + **PostgreSQL** + + ```sql + SELECT E'Строка \n Другая строка' as String + ``` + + | String | + | ------------------------- | + | Строка
Другая строка | ## Числовые литералы @@ -63,7 +83,7 @@ SELECT 'Hello world' Для числовых литералов в SQL есть все привычные нам арифметические операторы: - +**MySQL** | Оператор | Описание | Пример | | :--------: | :-------------------- | :-------------- | @@ -74,9 +94,7 @@ SELECT 'Hello world' | `/` | Деление | `1 / 2 = 0.5` | | `DIV` | Целочисленное деление | `10 DIV 4 = 2` | - - - +**PostgreSQL** | Оператор | Описание | Пример | | :------: | :---------------- | :-------------- | @@ -86,36 +104,34 @@ SELECT 'Hello world' | `-` | Вычитание | `50 - 51 = -1` | | `/` | Деление | `1 / 2 = 0.5` | - - Используя эти операторы, можно построить любое арифметическое выражение, применяя стандартные правила арифметики. Для примера: -```sql-Family-executable +```sql SELECT (5 * 2 - 6) / 2 AS Result; ``` +| Result | +| ------ | +| 2 | + ## Литералы даты и времени Значения даты и времени могут быть представлены в формате строки или числа. - +**MySQL** Например, если мы хотим указать какую-то дату в запросе, то мы можем это сделать с помощью строки `"1970-12-30"`, `"19701230"` или же числа `19701230`. В обоих случаях эти значения будут интерпретироваться как дата «30 декабря 1970 года». - - - +**PostgreSQL** Например, если мы хотим указать какую-то дату в запросе, то мы можем это сделать с помощью строки `'1970-12-30'` или `'19701230'`. - - Ниже приведён пример использования литерала даты: -```sql-Family-executable +```sql SELECT * FROM FamilyMembers WHERE birthday > '1970-12-30' ``` @@ -133,10 +149,10 @@ SELECT * FROM FamilyMembers WHERE birthday > '1970-12-30' Логический литерал - значения `TRUE` и `FALSE`, означающие истинность и ошибочность какого-либо утверждения. - - При интерпретации запроса, MySQL преобразует их в числа: `TRUE` и `FALSE` становятся - `1` и `0` соответственно. - +**MySQL** + +При интерпретации запроса, MySQL преобразует их в числа: `TRUE` и `FALSE` становятся +`1` и `0` соответственно. ## NULL diff --git a/course/module-2/operator-having/article.md b/course/module-2/operator-having/article.md index c99615a..ea7c322 100644 --- a/course/module-2/operator-having/article.md +++ b/course/module-2/operator-having/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Оператор HAVING' - description: 'Использование оператора HAVING в SQL' + title: "Оператор HAVING" + description: "Использование оператора HAVING в SQL" --- # Оператор HAVING @@ -9,7 +9,7 @@ meta: Мы уже рассматривали запрос получения средней стоимости аренды жилых помещений в зависимости от типа жилья: - +ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/operator-having). ```sql SELECT home_type, AVG(price) as avg_price FROM Rooms @@ -35,6 +35,16 @@ WHERE avg_price > 50 Говоря наперёд, для фильтрации групп мы должны использовать оператор `HAVING`: +**MySQL** + +```sql +SELECT home_type, AVG(price) as avg_price FROM Rooms +GROUP BY home_type +HAVING avg_price > 50 +``` + +**PostgreSQL** + ```sql SELECT home_type, AVG(price) as avg_price FROM Rooms GROUP BY home_type @@ -46,13 +56,15 @@ HAVING AVG(price) > 50 | Private room | 89.4286 | | Entire home/apt | 148.6667 | -
+**PostgreSQL** + +> В PostgreSQL алиасы, объявленные в `SELECT`, недоступны в `HAVING` ## Порядок выполнения SQL запроса Но почему же мы не могли использовать `WHERE`, и зачем нужен отдельный оператор для этой цели? Все дело в порядке выполнения SQL запроса. -![Схема порядка выполнения SQL запроса](https://sql-academy.org/static/guidePage/operator-having/sql_query_order_ru.png 'Схема порядка выполнения SQL запроса') +![Схема порядка выполнения SQL запроса](https://sql-academy.org/static/guidePage/operator-having/sql_query_order_ru.png "Схема порядка выполнения SQL запроса") Наш первый запрос был неверный, потому что мы пытались использовать поле `avg_price` у образовавшихся групп ещё до их образования, так как выполнение оператора `WHERE` предшествует группировке. @@ -92,20 +104,20 @@ ORDER BY условие_сортировки Чтобы получить такой результат, мы должны: -- Сначала получить все данные из таблицы +- Сначала получить все данные из таблицы ```sql SELECT ... FROM Rooms; ``` -- Затем выбрать из всех записей таблицы `Room` только интересующие нас, т.е. только жильё с телевизором +- Затем выбрать из всех записей таблицы `Room` только интересующие нас, т.е. только жильё с телевизором ```sql SELECT ... FROM Rooms WHERE has_tv = True ``` -- Затем сгруппировать данные записи о жилых помещениях по их типу +- Затем сгруппировать данные записи о жилых помещениях по их типу ```sql SELECT ... FROM Rooms @@ -113,7 +125,7 @@ ORDER BY условие_сортировки GROUP BY home_type ``` -- После этого отфильтровать полученные группы по условию. Нас интересуют группы, имеющие как минимум 5 представителей +- После этого отфильтровать полученные группы по условию. Нас интересуют группы, имеющие как минимум 5 представителей ```sql SELECT ... FROM Rooms @@ -122,8 +134,8 @@ ORDER BY условие_сортировки HAVING COUNT(*) >= 5 ``` -- И под конец посмотреть, что нас просят в задании и, соответственно, добавить вывод необходимой информации. В нашем случае, нам - необходимо вывести название типа жилья и его минимальную стоимость. +- И под конец посмотреть, что нас просят в задании и, соответственно, добавить вывод необходимой информации. В нашем случае, нам + необходимо вывести название типа жилья и его минимальную стоимость. ```sql SELECT home_type, MIN(price) as min_price FROM Rooms WHERE has_tv = True diff --git a/course/module-2/operator-like/article.md b/course/module-2/operator-like/article.md index c33c56f..b9273d3 100644 --- a/course/module-2/operator-like/article.md +++ b/course/module-2/operator-like/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Оператор LIKE" - description: "Синтаксис SQL оператор LIKE и ILIKE для поиска записей по шаблонной строке" + title: "Оператор LIKE" + description: "Синтаксис SQL оператор LIKE и ILIKE для поиска записей по шаблонной строке" --- # Оператор LIKE @@ -10,15 +10,23 @@ meta: Например, у нас есть таблица `Users`, в которой есть поле `email`: -```sql-executable-Airbnb +```sql SELECT name, email FROM Users; ``` +| name | email | +| ----------------- | ---------------------- | +| Bruce Willis | barjam\@hotmail.com | +| George Clooney | tellis\@me.com | +| Kevin Costner | metzzo\@hotmail.com | +| Samuel L. Jackson | moonlapse\@outlook.com | +| Kurt Russell | gator\@live.com | + Допустим, мы хотим найти всех пользователей, чья почта лежит в домене второго уровня «hotmail». Т.е. нужно отобрать только те записи, что отвечают условию: -- после символа «@» следует «hotmail» -- после «hotmail» следует символ «.» и далее любая последовательность символов +- после символа «@» следует «hotmail» +- после «hotmail» следует символ «.» и далее любая последовательность символов Для таких нетривиальных поисков по строковым полям и нужен оператор `LIKE`. @@ -28,60 +36,66 @@ SELECT name, email FROM Users; ... WHERE поле_таблицы [NOT] LIKE шаблон_строки ``` -Шаблон может включать следующие специальные символы: +Шаблон может включать два специальных символа — `%` и `_`. Вот что каждый из них означает: -| Символ | Описание | -| :----- | :---------------------------------------------------------------------------------------------- | -| `%` | Последовательность любых символов (число символов в последовательности может быть от 0 и более) | -| `_` | Любой единичный символ | +| Символ | Описание | +| ------ | ----------------------------------------------------------------------- | +| `%` | Любая последовательность символов: 0 символов, 1 символ, Много символов | +| `_` | Ровно один символ | Так наш запрос на поиск пользователей в домене «hotmail» может выглядеть следующим образом: -```sql-executable-Airbnb +```sql SELECT name, email FROM Users WHERE email LIKE '%@hotmail.%' ``` +| name | email | +| -------------------- | --------------------- | +| Bruce Willis | barjam\@hotmail.com | +| Kevin Costner | metzzo\@hotmail.com | +| Jennifer Lopez | barjam\@hotmail.com | +| Harrison Ford | kostas\@hotmail.com | +| Michael Douglas | timtroyr\@hotmail.com | +| Catherine Zeta-Jones | flakeg\@hotmail.com | + ## Примеры -- ```sql - ... WHERE поле_таблицы LIKE 'text%' - ``` +- ```sql + ... WHERE поле_таблицы LIKE 'text%' + ``` Сопоставляется любым строкам, начинающимся на «text» -- ```sql - ... WHERE поле_таблицы LIKE '%text' - ``` +- ```sql + ... WHERE поле_таблицы LIKE '%text' + ``` Сопоставляется любым строкам, заканчивающимся на «text» -- ```sql - ... WHERE поле_таблицы LIKE '_ext' - ``` +- ```sql + ... WHERE поле_таблицы LIKE '_ext' + ``` Сопоставляется строкам, имеющим длину 4 символа, при этом 3 последних обязательно должны быть «ext». Например, слова «text» и «next» -- ```sql - ... WHERE поле_таблицы LIKE 'begin%end' - ``` +- ```sql + ... WHERE поле_таблицы LIKE 'begin%end' + ``` Сопоставляется строкам, начинающихся на «begin» и заканчивающихся на «end» - +**MySQL** > В MySQL по умолчанию шаблоны не чувствительны к регистру - - - +**PostgreSQL** > В PostgreSQL шаблоны чувствительны к регистру. Для поиска без учета регистра используйте оператор `ILIKE` - - ## Экранирование специальных символов Иногда нужно найти строки, в которых символы `%` и `_` являются частью самого текста, а не элементами шаблона. В таких случаях эти символы нужно экранировать. + В шаблонах `LIKE` для экранирования по умолчанию используется символ `\`. Например, если нужно получить идентификаторы задач, прогресс которых равен `3%`, можно написать так: ```sql @@ -110,5 +124,7 @@ WHERE progress LIKE '3!%' ESCAPE '!'; ## Интерактивное упражнение -Теперь давайте закрепим полученные знания на практике! +Теперь давайте закрепим полученные знания на практике!\ В упражнении ниже вам нужно распределить email адреса по шаблонам LIKE, перетаскивая их в подходящие области. + +Интерактивная демонстрация доступна [в уроке на SQL Academy](https://sql-academy.org/ru/guide/operator-like). diff --git a/course/module-2/operator-regexp/article.md b/course/module-2/operator-regexp/article.md index bfc1ffe..deaaf60 100644 --- a/course/module-2/operator-regexp/article.md +++ b/course/module-2/operator-regexp/article.md @@ -1,26 +1,23 @@ --- meta: - title: "Операторы REGEXP и ~ в SQL" - description: "Использование регулярных выражений в SQL с помощью операторов REGEXP в MySQL и ~ в PostgreSQL" + title: "Операторы REGEXP и ~ в SQL" + description: "Использование регулярных выражений в SQL с помощью операторов REGEXP в MySQL и ~ в PostgreSQL" --- - +**MySQL** + # Оператор REGEXP для регулярных выражений Оператор `REGEXP` (или его синоним `RLIKE`) в MySQL используется для поиска и обработки строковых данных с помощью регулярных выражений. - - - +**PostgreSQL** -# Оператор регулярных выражений ~ +# Оператор регулярных выражений \~ Операторы `~` и `~*` в PostgreSQL используются для поиска и обработки строковых данных с помощью регулярных выражений. - - Регулярные выражения предоставляют мощные возможности для сложных шаблонов поиска, которые трудно реализовать с помощью оператора `LIKE`. @@ -35,7 +32,7 @@ meta: ## Синтаксис регулярных выражений - +**MySQL** ```sql ... WHERE table_field REGEXP 'pattern'; @@ -43,9 +40,7 @@ meta: Где `pattern` — это регулярное выражение, задающее шаблон поиска. - - - +**PostgreSQL** ```sql ... WHERE table_field ~ 'pattern'; -- с учетом регистра @@ -54,43 +49,37 @@ meta: Где `pattern` — это регулярное выражение, задающее шаблон поиска. - - ## Важные нюансы - +**MySQL** 1. **Регистронезависимость** - По умолчанию регулярные выражения в MySQL не чувствительны к регистру. - Например, выражение `REGEXP 'abc'` найдёт строку и `abc`, и `Abc`, и `ABC`. + По умолчанию регулярные выражения в MySQL не чувствительны к регистру. + Например, выражение `REGEXP 'abc'` найдёт строку и `abc`, и `Abc`, и `ABC`. 2. **Специальные символы** - Некоторые символы имеют особое значение в регулярных выражениях и требуют экранирования - (например, `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `\`). - - Для экранирования таких символов используйте двойной обратный слеш — `\\`. + Некоторые символы имеют особое значение в регулярных выражениях и требуют экранирования + (например, `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `\`). - + Для экранирования таких символов используйте двойной обратный слеш — `\\`. - +**PostgreSQL** 1. **Регистрозависимость** - По умолчанию регулярные выражения в PostgreSQL чувствительны к регистру. + По умолчанию регулярные выражения в PostgreSQL чувствительны к регистру. - - Оператор `~` — с учетом регистра - - Оператор `~*` — без учета регистра + - Оператор `~` — с учетом регистра + - Оператор `~*` — без учета регистра 2. **Специальные символы** - Некоторые символы имеют особое значение в регулярных выражениях и требуют экранирования - (например, `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `\`). - - Для экранирования таких символов используйте одинарный обратный слеш — `\`. + Некоторые символы имеют особое значение в регулярных выражениях и требуют экранирования + (например, `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `\`). - + Для экранирования таких символов используйте одинарный обратный слеш — `\`. ## Специальные символы и структуры @@ -115,116 +104,131 @@ meta: - **Получим всех пользователей, чьи имена начинаются на «John»:** - + **MySQL** - ```sql-executable-Airbnb - SELECT * FROM Users WHERE name REGEXP '^John' - ``` + ```sql + SELECT * FROM Users WHERE name REGEXP '^John' + ``` - + **PostgreSQL** - + ```sql + SELECT * FROM Users WHERE name ~ '^John' + ``` - ```sql-executable-Airbnb - SELECT * FROM Users WHERE name ~ '^John' - ``` + | id | name | email | email_verified_at | password | phone_number | + | --- | ------------- | ----------------- | ------------------------ | -------------------- | --------------- | + | 18 | John Travolta | wainwrig\@msn.com | 2016-11-19T12:30:43.000Z | fzjhl0v82o0amalr8649 | +1 202 555 0176 | + | 28 | Johnny Depp | cgarcia\@yahoo.ca | 2017-05-26T01:19:06.000Z | qpp6hbnae42cdhmxlk4j | +7 401 195 7363 | - - - Это выражение ищет строки, начинающиеся с «John». Символ `^` указывает на начало строки. + Это выражение ищет строки, начинающиеся с «John». Символ `^` указывает на начало строки. - **Выведем все школьные предметы, название которых оканчивается на букву «e» или «y»:** - - - ```sql-executable-Schedule - SELECT * FROM Subject WHERE name REGEXP '[ey]$' - ``` + **MySQL** - + ```sql + SELECT * FROM Subject WHERE name REGEXP '[ey]$' + ``` - + **PostgreSQL** - ```sql-executable-Schedule - SELECT * FROM Subject WHERE name ~ '[ey]$' - ``` + ```sql + SELECT * FROM Subject WHERE name ~ '[ey]$' + ``` - + | id | name | + | --- | ---------------- | + | 2 | Russian language | + | 3 | Literature | + | 5 | Chemistry | + | 6 | Geography | + | 7 | History | + | 8 | Biology | + | 9 | English language | + | 11 | Physical Culture | + | 13 | Technology | - В этом примере, `[ey]` определяет список возможных значений для паттерна `$`, определяющего, на что должна заканчиваться строка. + В этом примере, `[ey]` определяет список возможных значений для паттерна `$`, определяющего, на что должна заканчиваться строка. - **Найдём всех пользователей, чей адрес электронной почты oканчивается на «@outlook.com» или на «@icloud.com»:** - + **MySQL** - ```sql-executable-Airbnb - SELECT * FROM Users WHERE email REGEXP '@(outlook\\.com|icloud\\.com)$' - ``` + ```sql + SELECT * FROM Users WHERE email REGEXP '@(outlook\\.com|icloud\\.com)$' + ``` - + **PostgreSQL** - + ```sql + SELECT * FROM Users WHERE email ~ '@(outlook\.com|icloud\.com)$' + ``` - ```sql-executable-Airbnb - SELECT * FROM Users WHERE email ~ '@(outlook\.com|icloud\.com)$' - ``` + | id | name | email | email_verified_at | password | phone_number | + | --- | ----------------- | ---------------------- | ------------------------ | -------------------- | ----------------- | + | 7 | Samuel L. Jackson | moonlapse\@outlook.com | 2018-07-19T11:16:13.000Z | i6yvht95527z3idgqx9y | +1 202 555 0162 | + | 13 | Steve Martin | nelson\@outlook.com | 2016-07-29T04:25:00.000Z | w76yphg3kvzg77ilmxfs | +1 202 555 0138 | + | 29 | Pierce Brosnan | treeves\@icloud.com | 2019-03-08T01:56:00.000Z | lqiwecclne9rv8woo2go | +7 401 749 3620 | + | 30 | Sean Connery | jschauma\@icloud.com | 2016-05-21T00:45:17.000Z | lyh4jkdxkvtvulvqi5db | +7 401 511 6783 | + | 31 | Bruce Willis | kewley\@icloud.com | 2016-12-08T20:18:59.000Z | 0ofa2khvnptiackbssv0 | +375 154 771 3462 | - - - Здесь также используется `$` для обозначения конца строки и `|` для указания нескольких вариантов. + Здесь также используется `$` для обозначения конца строки и `|` для указания нескольких вариантов. - **Найдём всех пользователей, чей номер телефона не содержит цифр «2» и «8»:** - - - ```sql-executable-Airbnb - SELECT * FROM Users WHERE phone_number REGEXP '^[^28]*$' - ``` + **MySQL** - + ```sql + SELECT * FROM Users WHERE phone_number REGEXP '^[^28]*$' + ``` - + **PostgreSQL** - ```sql-executable-Airbnb - SELECT * FROM Users WHERE phone_number ~ '^[^28]*$' - ``` + ```sql + SELECT * FROM Users WHERE phone_number ~ '^[^28]*$' + ``` - + | id | name | email | email_verified_at | password | phone_number | + | --- | ----------- | --------------------- | ------------------------ | -------------------- | --------------- | + | 27 | Brad Pitt | kewley\@optonline.net | 2017-02-11T05:45:15.000Z | 829j2ygocn8btzae49kv | +7 401 741 3797 | + | 28 | Johnny Depp | cgarcia\@yahoo.ca | 2017-05-26T01:19:06.000Z | qpp6hbnae42cdhmxlk4j | +7 401 195 7363 | - В этом примере символ `[^28]` обозначает любой символ, кроме «2» и «8», а - `*` означает любое количество таких символов. Символы `^` и `$` указывают на начало и конец строки - соответственно, гарантируя, что вся строка соответствует шаблону. + В этом примере символ `[^28]` обозначает любой символ, кроме «2» и «8», а + `*` означает любое количество таких символов. Символы `^` и `$` указывают на начало и конец строки + соответственно, гарантируя, что вся строка соответствует шаблону. - **Найдём всех пользователей, чей номер телефона начинается на «+7»** - - - ```sql-executable-Airbnb - SELECT name, phone_number FROM Users WHERE phone_number REGEXP '^\\+7' - ``` - - - - + **MySQL** - ```sql-executable-Airbnb - SELECT name, phone_number FROM Users WHERE phone_number ~ '^\+7' - ``` + ```sql + SELECT name, phone_number FROM Users WHERE phone_number REGEXP '^\\+7' + ``` - + **PostgreSQL** - В этом примере `^` означает начало строки. То есть, мы ищем строки, которые начинаются с определённого шаблона. + ```sql + SELECT name, phone_number FROM Users WHERE phone_number ~ '^\+7' + ``` - + | name | phone_number | + | -------------- | --------------- | + | Hideo Kojima | +7 401 452 0052 | + | ClINT Eastwood | +7 401 722 0912 | + | Brad Pitt | +7 401 741 3797 | + | Johnny Depp | +7 401 195 7363 | + | Pierce Brosnan | +7 401 749 3620 | + | Sean Connery | +7 401 511 6783 | - Поскольку `+` является специальным символом в регулярных выражениях, его нужно экранировать двойным обратным слэшем (`\\`), - чтобы он воспринимался как обычный символ `+`. В результате, `\\+` соответствует знаку `+` в строке. + В этом примере `^` означает начало строки. То есть, мы ищем строки, которые начинаются с определённого шаблона. - + **MySQL** - + Поскольку `+` является специальным символом в регулярных выражениях, его нужно экранировать двойным обратным слэшем (`\\`), + чтобы он воспринимался как обычный символ `+`. В результате, `\\+` соответствует знаку `+` в строке. - Поскольку `+` является специальным символом в регулярных выражениях, его нужно экранировать одинарным обратным слэшем (`\`), - чтобы он воспринимался как обычный символ `+`. В результате, `\+` соответствует знаку `+` в строке. + **PostgreSQL** - + Поскольку `+` является специальным символом в регулярных выражениях, его нужно экранировать одинарным обратным слэшем (`\`), + чтобы он воспринимался как обычный символ `+`. В результате, `\+` соответствует знаку `+` в строке. diff --git a/course/module-2/sorting/article.md b/course/module-2/sorting/article.md index 3512062..dbb623d 100644 --- a/course/module-2/sorting/article.md +++ b/course/module-2/sorting/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Сортировка данных в SQL, оператор order by" - description: "SQL оператор сортировки order by, сортировка по нескольким столбцам, примеры использования" + title: "Сортировка данных в SQL, оператор order by" + description: "SQL оператор сортировки order by, сортировка по нескольким столбцам, примеры использования" --- # Сортировка, оператор ORDER BY @@ -27,13 +27,21 @@ ORDER BY столбец_1 [ASC | DESC][, столбец_n [ASC | DESC]] Например, выведем названия авиакомпаний в алфавитном порядке из таблицы `Company`: -```sql-executable-Airo +```sql SELECT name FROM Company ORDER BY name; ``` +| name | +| ---------- | +| Aeroflot | +| air_France | +| British_AW | +| Dale_avia | +| Don_avia | + ## Сортировка по возрастанию и убыванию для основных типов - +**MySQL** | Тип данных | ASC (по возрастанию) | DESC (по убыванию) | | :------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | @@ -43,9 +51,7 @@ SELECT name FROM Company ORDER BY name; | Булевый тип | `False` идёт перед `True` | `True` идёт перед `False` | | NULL значения | `NULL` значения идут первыми | `NULL` значения идут последними | - - - +**PostgreSQL** | Тип данных | ASC (по возрастанию) | DESC (по убыванию) | | :------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | @@ -55,8 +61,6 @@ SELECT name FROM Company ORDER BY name; | Булевый тип | `false` идёт перед `true` | `true` идёт перед `false` | | NULL значения | `NULL` значения идут последними | `NULL` значения идут первыми | - - ## Сортировка по нескольким столбцам Для сортировки результатов по двум или более столбцам их следует указывать @@ -79,11 +83,25 @@ SELECT name FROM Company ORDER BY name; Выведем информацию о полётах, отсортированную по городу вылета самолёта в порядке возрастания и по городу прибытия в аэропорт в порядке убывания, из таблицы `Trip`: -```sql-executable-Airo +```sql SELECT DISTINCT town_from, town_to FROM Trip ORDER BY town_from, town_to DESC; ``` +| town_from | town_to | +| ----------- | ----------- | +| London | Singapore | +| London | Paris | +| Moscow | Rostov | +| Paris | Rostov | +| Rostov | Vladivostok | +| Rostov | Paris | +| Rostov | Moscow | +| Singapore | London | +| Vladivostok | Rostov | + В данном примере в начале записи сортируются по полю `town_from`. Затем отрабатывает обратная сортировка по полю `town_to` для групп строк, у которых в столбце `town_from` одинаковое значение. ## Демонстрация работы сортировки + +Интерактивная демонстрация доступна [в уроке на SQL Academy](https://sql-academy.org/ru/guide/sorting). diff --git a/course/module-2/using-functions/article.md b/course/module-2/using-functions/article.md index 3deb1ad..b3d29f9 100644 --- a/course/module-2/using-functions/article.md +++ b/course/module-2/using-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Применение функций' - description: 'Примеры скалярных SQL функций и примеры их применений над литералами и над значениями полей из таблиц' + title: "Применение функций" + description: "Примеры скалярных SQL функций и примеры их применений над литералами и над значениями полей из таблиц" --- # Применение функций @@ -9,10 +9,14 @@ meta: При составлении SQL запросов мы можем использовать встроенные функции. Например, если мы хотим вывести строку в верхнем регистре, то для этого мы можем использовать функцию `UPPER`. -```sql-executable +```sql SELECT UPPER('Hello world') AS upper_string; ``` +| upper_string | +| ------------ | +| HELLO WORLD | + ## Что такое встроенная функция? Встроенная функция – реализованный в СУБД кусок кода, с помощью которого можно выполнять преобразования строковых, числовых и других данных в запросах. @@ -23,97 +27,131 @@ SELECT UPPER('Hello world') AS upper_string; ## Примеры функций -Функций достаточно много, но основные всегда можно найти с помощью поиска в шапке или же на странице справочника функций. +Функций достаточно много, но основные всегда можно найти с помощью поиска в шапке или же на странице справочника функций. Вот некоторые из них: - +**MySQL** + +- + **LOWER** + -- - **LOWER** - Возвращает строку, в которой все символы записаны в нижнем регистре - ```sql-executable + ```sql SELECT LOWER('SQL Academy') AS lower_string; ``` -- - **YEAR** - + | lower_string | + | ------------ | + | sql academy | + +- + **YEAR** + + Возвращает год для указанной даты - ```sql-executable + ```sql SELECT YEAR('2022-06-16') AS year; ``` -- - **INSTR** - - Осуществляет поиск подстроки в строке, возвращая позицию её первого символа. При этом отсчёт - начинается с единицы, а не нуля, как в большинстве языков программирования. + | year | + | ---- | + | 2022 | + +- + **INSTR** + + + Осуществляет поиск подстроки в строке, возвращая позицию её первого символа. При этом + отсчёт начинается с единицы, а не нуля, как в большинстве языков программирования. Функция работает путём посимвольного сравнения исходной строки с искомой. Например, в строке `sql-academy` подстрока `academy` появляется, начиная с пятого символа. - ```sql-executable + ```sql SELECT INSTR('sql-academy', 'academy') AS idx; ``` -- - **LENGTH** - + | idx | + | --- | + | 5 | + +- + **LENGTH** + Возвращает длину указанной строки. - ```sql-executable + ```sql SELECT LENGTH('sql-academy') AS str_length; ``` - + | str_length | + | ---------- | + | 11 | + +**PostgreSQL** - +- + **LOWER** + -- - **LOWER** - Возвращает строку, в которой все символы записаны в нижнем регистре - ```sql-executable + ```sql SELECT LOWER('SQL Academy') AS lower_string; ``` -- - **EXTRACT** - + | lower_string | + | ------------ | + | sql academy | + +- + **EXTRACT** + + Извлекает часть даты (год, месяц, день и т.д.) для указанной даты - ```sql-executable + ```sql SELECT EXTRACT(YEAR FROM DATE '2022-06-16') AS year; ``` -- - **POSITION** - - Осуществляет поиск подстроки в строке, возвращая позицию её первого символа. При этом отсчёт - начинается с единицы, а не нуля, как в большинстве языков программирования. + | year | + | ---- | + | 2022 | + +- + **POSITION** + + + Осуществляет поиск подстроки в строке, возвращая позицию её первого символа. При этом + отсчёт начинается с единицы, а не нуля, как в большинстве языков программирования. Функция работает путём посимвольного сравнения исходной строки с искомой. Например, в строке `sql-academy` подстрока `academy` появляется, начиная с пятого символа. - ```sql-executable + ```sql SELECT POSITION('academy' IN 'sql-academy') AS idx; ``` -- - **LENGTH** - + | idx | + | --- | + | 5 | + +- + **LENGTH** + Возвращает длину указанной строки. - ```sql-executable + ```sql SELECT LENGTH('sql-academy') AS str_length; ``` - + | str_length | + | ---------- | + | 11 | ## Применение функций над значениями полей таблицы @@ -121,35 +159,50 @@ SELECT UPPER('Hello world') AS upper_string; Например, давайте вернёмся к нашей базе данных и рассмотрим таблицу `FamilyMembers`: она содержит имя, статус и дату рождения людей. - +ER-диаграмма базы данных Family: [открыть на SQL Academy](https://sql-academy.org/ru/guide/using-functions). Каждое значение этих полей мы можем изменить при выводе. Так, нижележащий запрос высчитывает длину полного имени для каждого из членов семьи. -```sql-executable-Family-format +```sql SELECT member_name, LENGTH(member_name) AS fullname_length FROM FamilyMembers; ``` +| member_name | fullname_length | +| ----------------- | --------------- | +| Headley Quincey | 15 | +| Flavia Quincey | 14 | +| Andie Quincey | 13 | +| Lela Quincey | 12 | +| Annie Quincey | 13 | +| Ernest Forrest | 14 | +| Constance Forrest | 17 | +| Wednesday Addams | 16 | + ## Операции над результатом функции Поскольку мы знаем, что каждая функция должна вернуть какой-либо из возможных литералов, то её результат также можно использовать в дальнейших расчётах и преобразованиях. К примеру, мы хотим получить первые три буквы в строке и преобразовать их в заглавные. Для этого нам будет достаточно скомбинировать две функции: `LEFT` и `UPPER`, где результат одной функции будет аргументом для второй. -```sql-executable-format +```sql SELECT UPPER(LEFT('sql-academy', 3)) AS str; ``` +| str | +| --- | +| SQL | + Или хотим вычислить длину фамилии человека, имея строку в формате `имя<пробел>фамилия`. Одним из возможных способов вычисления длины фамилии может быть применение функций `LENGTH` и поиска позиции пробела, используя формулу `<длина фамилии> = <длина всей строки> - (<длина имени> + <длина пробела>)`: -- Значение `<длина всей строки>` можно получить с помощью функции `LENGTH` +- Значение `<длина всей строки>` можно получить с помощью функции `LENGTH` - +**MySQL** -- Для `<длина имени> + <длина пробела>` нужно вычислить позицию символа, где заканчивается имя, и прибавить единицу, т.к. пробел имеет длину «1». Мы можем сделать это, используя лишь функцию `INSTR`, ориентируясь на символ «пробел» +- Для `<длина имени> + <длина пробела>` нужно вычислить позицию символа, где заканчивается имя, и прибавить единицу, т.к. пробел имеет длину «1». Мы можем сделать это, используя лишь функцию `INSTR`, ориентируясь на символ «пробел» Так как обе функции возвращают числовые литералы, мы можем выполнять арифметические операции над ними. Давайте вычтем одно из другого и получим длину фамилии (lastname_length): -```sql-executable-Family-format +```sql SELECT member_name, LENGTH(member_name) AS full_length, @@ -158,15 +211,13 @@ SELECT FROM FamilyMembers; ``` - - - +**PostgreSQL** -- Для `<длина имени> + <длина пробела>` нужно вычислить позицию символа, где заканчивается имя, и прибавить единицу, т.к. пробел имеет длину «1». Мы можем сделать это, используя лишь функцию `POSITION`, ориентируясь на символ «пробел» +- Для `<длина имени> + <длина пробела>` нужно вычислить позицию символа, где заканчивается имя, и прибавить единицу, т.к. пробел имеет длину «1». Мы можем сделать это, используя лишь функцию `POSITION`, ориентируясь на символ «пробел» Так как обе функции возвращают числовые литералы, мы можем выполнять арифметические операции над ними. Давайте вычтем одно из другого и получим длину фамилии (lastname_length): -```sql-executable-Family-format +```sql SELECT member_name, LENGTH(member_name) AS full_length, @@ -175,4 +226,13 @@ SELECT FROM FamilyMembers; ``` - +| member_name | full_length | firstname_with_space_length | lastname_length | +| ----------------- | ----------- | --------------------------- | --------------- | +| Headley Quincey | 15 | 8 | 7 | +| Flavia Quincey | 14 | 7 | 7 | +| Andie Quincey | 13 | 6 | 7 | +| Lela Quincey | 12 | 5 | 7 | +| Annie Quincey | 13 | 6 | 7 | +| Ernest Forrest | 14 | 7 | 7 | +| Constance Forrest | 17 | 10 | 7 | +| Wednesday Addams | 16 | 10 | 6 | diff --git a/course/module-3/case-expression/article.md b/course/module-3/case-expression/article.md index 5a8ed90..8817c24 100644 --- a/course/module-3/case-expression/article.md +++ b/course/module-3/case-expression/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Условная логика, оператор CASE" - description: "Условная логика в SQL, использование оператор CASE WHEN THEN END" + title: "Условная логика, оператор CASE" + description: "Условная логика в SQL, использование оператор CASE WHEN THEN END" --- # Условная логика, оператор CASE @@ -18,13 +18,13 @@ SQL, подобно многим языкам программирования, есть ли студенту 18 лет. Это и есть пример условной логики, при которой должно вывестись либо одно значение, либо другое в зависимости от конкретного условия. - +ER-диаграмма базы данных Schedule: [открыть на SQL Academy](https://sql-academy.org/ru/guide/case-expression). Реализация такого запроса с помощью `CASE` может выглядеть следующим образом: - +**MySQL** -```sql-executable-Schedule +```sql SELECT first_name, last_name, CASE WHEN TIMESTAMPDIFF(YEAR, birthday, NOW()) >= 18 THEN 'Совершеннолетний' @@ -33,11 +33,9 @@ END AS status FROM Student ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql SELECT first_name, last_name, CASE WHEN EXTRACT(YEAR FROM AGE(NOW(), birthday)) >= 18 THEN 'Совершеннолетний' @@ -46,7 +44,30 @@ END AS status FROM Student ``` - +| first_name | last_name | status | +| ---------- | ------------ | ------------------ | +| Nikolaj | Sokolov | Совершеннолетний | +| Vyacheslav | Eliseev | Совершеннолетний | +| Ivan | Efremov | Совершеннолетний | +| Anatolij | ZHdanov | Несовершеннолетний | +| Georgij | Noskov | Совершеннолетний | +| Artyom | Sergeev | Несовершеннолетний | +| Arina | Evseeva | Совершеннолетний | +| Angelina | Voroncova | Совершеннолетний | +| Ekaterina | Ustinova | Совершеннолетний | +| Raisa | Lapina | Совершеннолетний | +| Leonid | Ignatov | Несовершеннолетний | +| Snezhana | Seliverstova | Совершеннолетний | +| Semyon | Biryukov | Совершеннолетний | +| Georgij | Baranov | Совершеннолетний | +| YUliya | Vishnyakova | Совершеннолетний | +| Valentina | Bolshakova | Совершеннолетний | +| Leonid | Kryukov | Совершеннолетний | +| Vladislav | Cvetkov | Совершеннолетний | +| Snezhana | Morozova | Совершеннолетний | +| Lyubov | Borisova | Совершеннолетний | +| Anfisa | Kalashnikova | Совершеннолетний | +| Anna | Osipova | Совершеннолетний | ## Синтаксис поискового выражения CASE @@ -69,9 +90,9 @@ END ![Этапы школьного образования](https://sql-academy.org/static/guidePage/case-expression/ru_school_education_stages.png "Этапы школьного образования") - +**MySQL** -```sql-executable-Schedule +```sql SELECT name, CASE WHEN SUBSTRING(name, 1, INSTR(name, ' ')) IN (10, 11) THEN 'Старшая школа' @@ -81,11 +102,9 @@ END AS stage FROM Class ``` - +**PostgreSQL** - - -```sql-executable-Schedule +```sql SELECT name, CASE WHEN SUBSTRING(name, 1, POSITION(' ' IN name) - 1) IN ('10', '11') THEN 'Старшая школа' @@ -95,28 +114,41 @@ END AS stage FROM Class ``` - - - +| name | stage | +| ---- | --------------- | +| 8 A | Средняя школа | +| 8 B | Средняя школа | +| 9 C | Средняя школа | +| 9 B | Средняя школа | +| 9 A | Средняя школа | +| 10 B | Старшая школа | +| 10 A | Старшая школа | +| 11 B | Старшая школа | +| 11 A | Старшая школа | +| 7 A | Средняя школа | +| 7 B | Средняя школа | +| 6 A | Средняя школа | +| 6 B | Средняя школа | +| 5 A | Средняя школа | +| 5 B | Средняя школа | +| 4 A | Начальная школа | + +**MySQL** - Сначала мы извлекаем номер класса из его названия - ```sql - SUBSTRING(name, 1, INSTR(name, ' ')) - ``` - - + ```sql + SUBSTRING(name, 1, INSTR(name, ' ')) + ``` - +**PostgreSQL** - Сначала мы извлекаем номер класса из его названия - ```sql - SUBSTRING(name, 1, POSITION(' ' IN name) - 1) - ``` + ```sql + SUBSTRING(name, 1, POSITION(' ' IN name) - 1) + ``` - - -- Далее мы проверяем вхождение данного номера в список классов, относящихся к «Старшая школа» и «Средняя школа». -- Если номер класса не находится в диапазоне 5–11, мы выводим «Начальная школа». +* Далее мы проверяем вхождение данного номера в список классов, относящихся к «Старшая школа» и «Средняя школа». +* Если номер класса не находится в диапазоне 5–11, мы выводим «Начальная школа». ## Синтаксис простого выражения CASE @@ -136,9 +168,9 @@ END Используя этот синтаксис, можно переписать наш предыдущий пример таким образом: - +**MySQL** -```sql-executable-Schedule +```sql SELECT name, CASE SUBSTRING(name, 1, INSTR(name, ' ')) WHEN 11 THEN 'Старшая школа' @@ -153,11 +185,9 @@ END AS stage FROM Class ``` - +**PostgreSQL** - - -```sql-executable-Schedule +```sql SELECT name, CASE SUBSTRING(name, 1, POSITION(' ' IN name) - 1) WHEN '11' THEN 'Старшая школа' @@ -172,7 +202,24 @@ END AS stage FROM Class ``` - +| name | stage | +| ---- | --------------- | +| 8 A | Средняя школа | +| 8 B | Средняя школа | +| 9 C | Средняя школа | +| 9 B | Средняя школа | +| 9 A | Средняя школа | +| 10 B | Старшая школа | +| 10 A | Старшая школа | +| 11 B | Старшая школа | +| 11 A | Старшая школа | +| 7 A | Средняя школа | +| 7 B | Средняя школа | +| 6 A | Средняя школа | +| 6 B | Средняя школа | +| 5 A | Средняя школа | +| 5 B | Средняя школа | +| 4 A | Начальная школа | ### Проверьте себя @@ -185,3 +232,9 @@ CASE 2 ELSE 'Много' END ``` + +1. Ноль — Оператор CASE не может вернуть "Ноль", потому что значения "2" и "0" не равны. + +2. Один — Оператор CASE не может вернуть "Один", потому что значения "2" и "1" не равны. + +3. **Правильный ответ:** Много — Всё верно, оператор CASE действительно вернёт "Много", потому что ни одно из значений, переданных в WHEN, не совпало с "2". diff --git a/course/module-3/combining-queries/article.md b/course/module-3/combining-queries/article.md index 1318b35..f8d8908 100644 --- a/course/module-3/combining-queries/article.md +++ b/course/module-3/combining-queries/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Объединение запросов, оператор Union' - description: 'Пример использования sql оператора union для объединения выборок' + title: "Объединение запросов, оператор Union" + description: "Пример использования sql оператора union для объединения выборок" --- # Объединение запросов, оператор Union @@ -18,8 +18,8 @@ SELECT поля_таблиц FROM список_таблиц ... ; `UNION` по умолчанию убирает повторения в результирующей таблице. Для отображения с повторением есть необязательный параметр `ALL`. -- Не путайте операции объединения запросов с операциями объединения таблиц. Для этого служит оператор `JOIN`. -- Не путайте операции объединения запросов с подзапросами. Подзапросы выполняются для связанных таблиц. +- Не путайте операции объединения запросов с операциями объединения таблиц. Для этого служит оператор `JOIN`. +- Не путайте операции объединения запросов с подзапросами. Подзапросы выполняются для связанных таблиц. Объединение таблиц оператором `UNION` выполняется для таблиц никак не связанных, но со схожей структурой. @@ -32,10 +32,10 @@ SELECT поля_таблиц FROM список_таблиц ... ; Существует два других оператора, чьё поведение крайне схоже с `UNION`: -- `INTERSECT` - Комбинирует два запроса `SELECT`, но возвращает записи только первого `SELECT`, которые имеют совпадения во втором элементе `SELECT`. -- `EXCEPT` - Комбинирует два запроса `SELECT`, но возвращает записи только первого `SELECT`, которые не имеют совпадения во втором элементе `SELECT`. +- `INTERSECT` + Комбинирует два запроса `SELECT`, но возвращает записи только первого `SELECT`, которые имеют совпадения во втором элементе `SELECT`. +- `EXCEPT` + Комбинирует два запроса `SELECT`, но возвращает записи только первого `SELECT`, которые не имеют совпадения во втором элементе `SELECT`. ## Примеры использования diff --git a/course/module-3/correlated-subqueries/article.md b/course/module-3/correlated-subqueries/article.md index 2e8b9e3..962d509 100644 --- a/course/module-3/correlated-subqueries/article.md +++ b/course/module-3/correlated-subqueries/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Коррелированные подзапросы' - description: 'Коррелированные и некоррелированные подзапросы в SQL, их синтаксис' + title: "Коррелированные подзапросы" + description: "Коррелированные и некоррелированные подзапросы в SQL, их синтаксис" --- # Коррелированные подзапросы @@ -30,9 +30,9 @@ FROM FamilyMembers; | Andie Quincey | 3600 | | Lela Quincey | 650 | | Annie Quincey | 1060 | -| Ernest Forrest | | -| Constance Forrest | | -| Wednesday Addams | | +| Ernest Forrest | \ | +| Constance Forrest | \ | +| Wednesday Addams | \ | В данном случае, коррелированный подзапрос ссылается к столбцу `member_id` из основного запроса. diff --git a/course/module-3/if-function/article.md b/course/module-3/if-function/article.md index 2bb6af1..91f44f1 100644 --- a/course/module-3/if-function/article.md +++ b/course/module-3/if-function/article.md @@ -1,10 +1,10 @@ --- meta: - title: "Условная логика в SQL, функции IFNULL, NULLIF" - description: "Условная логика в SQL: функция IF в MySQL и дополнительные функции в PostgreSQL (COALESCE, NULLIF)" + title: "Условная логика в SQL, функции IFNULL, NULLIF" + description: "Условная логика в SQL: функция IF в MySQL и дополнительные функции в PostgreSQL (COALESCE, NULLIF)" --- - +**MySQL** # Условная функция IF @@ -21,9 +21,7 @@ IF(условное_выражение, значение_1, значение_2); Если условное выражение, передаваемое в качестве первого аргумента в функцию `IF`, истинно, функция вернёт значение второго аргумента `значение_1`, иначе возвращается значение третьего аргумента `значение_2`. - - - +**PostgreSQL** # Дополнительные функции условной логики @@ -40,92 +38,298 @@ PostgreSQL предоставляет дополнительные функци Эти функции являются стандартными SQL функциями и делают код более читаемым в определенных ситуациях. - - ### Примеры - +**MySQL** - Простое сравнение двух чисел. Так как 10 не больше 20, функция вернёт 'FALSE'. - ```sql-executable-Airbnb - SELECT IF(10 > 20, 'TRUE', 'FALSE'); - ``` + ```sql + SELECT IF(10 > 20, 'TRUE', 'FALSE'); + ``` - + | IF(10 > 20, "TRUE", "FALSE") | + | ---------------------------- | + | FALSE | - +**PostgreSQL** - Простой пример условной логики с помощью оператора CASE из предыдущего урока: - ```sql-executable-Airbnb - SELECT CASE WHEN 10 > 20 THEN 'TRUE' ELSE 'FALSE' END; - ``` + ```sql + SELECT CASE WHEN 10 > 20 THEN 'TRUE' ELSE 'FALSE' END; + ``` - + | case | + | ----- | + | FALSE | - +**MySQL** - Пример использования с реальной БД. Необходимо на основании цены определить принадлежность жилья к одному из двух классов: "Комфорт-класс" и "Эконом-класс". Если цена больше или равна `150`, то это жильё относится к "Комфорт-класс". - - - ```sql-executable-Airbnb - SELECT id, price, - IF(price >= 150, 'Комфорт-класс', 'Эконом-класс') AS category - FROM Rooms - ``` - - - - + ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/if-function). + + ```sql + SELECT id, price, + IF(price >= 150, 'Комфорт-класс', 'Эконом-класс') AS category + FROM Rooms + ``` + + | id | price | category | + | --- | ----- | ------------- | + | 1 | 149 | Эконом-класс | + | 2 | 225 | Комфорт-класс | + | 3 | 150 | Комфорт-класс | + | 4 | 89 | Эконом-класс | + | 5 | 80 | Эконом-класс | + | 6 | 200 | Комфорт-класс | + | 7 | 60 | Эконом-класс | + | 8 | 79 | Эконом-класс | + | 9 | 79 | Эконом-класс | + | 10 | 150 | Комфорт-класс | + | 11 | 135 | Эконом-класс | + | 12 | 85 | Эконом-класс | + | 13 | 89 | Эконом-класс | + | 14 | 85 | Эконом-класс | + | 15 | 120 | Эконом-класс | + | 16 | 140 | Эконом-класс | + | 17 | 215 | Комфорт-класс | + | 18 | 140 | Эконом-класс | + | 19 | 99 | Эконом-класс | + | 20 | 190 | Комфорт-класс | + | 21 | 299 | Комфорт-класс | + | 22 | 130 | Эконом-класс | + | 23 | 80 | Эконом-класс | + | 24 | 110 | Эконом-класс | + | 25 | 120 | Эконом-класс | + | 26 | 60 | Эконом-класс | + | 27 | 80 | Эконом-класс | + | 28 | 150 | Комфорт-класс | + | 29 | 44 | Эконом-класс | + | 30 | 180 | Комфорт-класс | + | 31 | 50 | Эконом-класс | + | 32 | 52 | Эконом-класс | + | 33 | 55 | Эконом-класс | + | 34 | 50 | Эконом-класс | + | 35 | 70 | Эконом-класс | + | 36 | 89 | Эконом-класс | + | 37 | 35 | Эконом-класс | + | 38 | 85 | Эконом-класс | + | 39 | 150 | Комфорт-класс | + | 40 | 40 | Эконом-класс | + | 41 | 68 | Эконом-класс | + | 42 | 120 | Эконом-класс | + | 43 | 120 | Эконом-класс | + | 44 | 135 | Эконом-класс | + | 45 | 150 | Комфорт-класс | + | 46 | 150 | Комфорт-класс | + | 47 | 130 | Эконом-класс | + | 48 | 110 | Эконом-класс | + | 49 | 115 | Эконом-класс | + | 50 | 80 | Эконом-класс | + +**PostgreSQL** - Пример с реальными данными. Оператор CASE помогает категоризировать жильё по цене: - - - ```sql-executable-Airbnb - SELECT id, price, - CASE WHEN price >= 150 THEN 'Комфорт-класс' ELSE 'Эконом-класс' END AS category - FROM Rooms - ``` - - - - + ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/if-function). + + ```sql + SELECT id, price, + CASE WHEN price >= 150 THEN 'Комфорт-класс' ELSE 'Эконом-класс' END AS category + FROM Rooms + ``` + + | id | price | category | + | --- | ----- | ------------- | + | 1 | 149 | Эконом-класс | + | 2 | 225 | Комфорт-класс | + | 3 | 150 | Комфорт-класс | + | 4 | 89 | Эконом-класс | + | 5 | 80 | Эконом-класс | + | 6 | 200 | Комфорт-класс | + | 7 | 60 | Эконом-класс | + | 8 | 79 | Эконом-класс | + | 9 | 79 | Эконом-класс | + | 10 | 150 | Комфорт-класс | + | 11 | 135 | Эконом-класс | + | 12 | 85 | Эконом-класс | + | 13 | 89 | Эконом-класс | + | 14 | 85 | Эконом-класс | + | 15 | 120 | Эконом-класс | + | 16 | 140 | Эконом-класс | + | 17 | 215 | Комфорт-класс | + | 18 | 140 | Эконом-класс | + | 19 | 99 | Эконом-класс | + | 20 | 190 | Комфорт-класс | + | 21 | 299 | Комфорт-класс | + | 22 | 130 | Эконом-класс | + | 23 | 80 | Эконом-класс | + | 24 | 110 | Эконом-класс | + | 25 | 120 | Эконом-класс | + | 26 | 60 | Эконом-класс | + | 27 | 80 | Эконом-класс | + | 28 | 150 | Комфорт-класс | + | 29 | 44 | Эконом-класс | + | 30 | 180 | Комфорт-класс | + | 31 | 50 | Эконом-класс | + | 32 | 52 | Эконом-класс | + | 33 | 55 | Эконом-класс | + | 34 | 50 | Эконом-класс | + | 35 | 70 | Эконом-класс | + | 36 | 89 | Эконом-класс | + | 37 | 35 | Эконом-класс | + | 38 | 85 | Эконом-класс | + | 39 | 150 | Комфорт-класс | + | 40 | 40 | Эконом-класс | + | 41 | 68 | Эконом-класс | + | 42 | 120 | Эконом-класс | + | 43 | 120 | Эконом-класс | + | 44 | 135 | Эконом-класс | + | 45 | 150 | Комфорт-класс | + | 46 | 150 | Комфорт-класс | + | 47 | 130 | Эконом-класс | + | 48 | 110 | Эконом-класс | + | 49 | 115 | Эконом-класс | + | 50 | 80 | Эконом-класс | + +**MySQL** - Функции `IF` можно также вкладывать друг в друга, эмулируя оператор `CASE`. - ```sql-executable-Airbnb - SELECT id, price, - IF(price >= 200, 'Бизнес-класс', - IF(price >= 150, - 'Комфорт-класс', 'Эконом-класс')) AS category - FROM Rooms - ``` - - - - + ```sql + SELECT id, price, + IF(price >= 200, 'Бизнес-класс', + IF(price >= 150, + 'Комфорт-класс', 'Эконом-класс')) AS category + FROM Rooms + ``` + + | id | price | category | + | --- | ----- | ------------- | + | 1 | 149 | Эконом-класс | + | 2 | 225 | Бизнес-класс | + | 3 | 150 | Комфорт-класс | + | 4 | 89 | Эконом-класс | + | 5 | 80 | Эконом-класс | + | 6 | 200 | Бизнес-класс | + | 7 | 60 | Эконом-класс | + | 8 | 79 | Эконом-класс | + | 9 | 79 | Эконом-класс | + | 10 | 150 | Комфорт-класс | + | 11 | 135 | Эконом-класс | + | 12 | 85 | Эконом-класс | + | 13 | 89 | Эконом-класс | + | 14 | 85 | Эконом-класс | + | 15 | 120 | Эконом-класс | + | 16 | 140 | Эконом-класс | + | 17 | 215 | Бизнес-класс | + | 18 | 140 | Эконом-класс | + | 19 | 99 | Эконом-класс | + | 20 | 190 | Комфорт-класс | + | 21 | 299 | Бизнес-класс | + | 22 | 130 | Эконом-класс | + | 23 | 80 | Эконом-класс | + | 24 | 110 | Эконом-класс | + | 25 | 120 | Эконом-класс | + | 26 | 60 | Эконом-класс | + | 27 | 80 | Эконом-класс | + | 28 | 150 | Комфорт-класс | + | 29 | 44 | Эконом-класс | + | 30 | 180 | Комфорт-класс | + | 31 | 50 | Эконом-класс | + | 32 | 52 | Эконом-класс | + | 33 | 55 | Эконом-класс | + | 34 | 50 | Эконом-класс | + | 35 | 70 | Эконом-класс | + | 36 | 89 | Эконом-класс | + | 37 | 35 | Эконом-класс | + | 38 | 85 | Эконом-класс | + | 39 | 150 | Комфорт-класс | + | 40 | 40 | Эконом-класс | + | 41 | 68 | Эконом-класс | + | 42 | 120 | Эконом-класс | + | 43 | 120 | Эконом-класс | + | 44 | 135 | Эконом-класс | + | 45 | 150 | Комфорт-класс | + | 46 | 150 | Комфорт-класс | + | 47 | 130 | Эконом-класс | + | 48 | 110 | Эконом-класс | + | 49 | 115 | Эконом-класс | + | 50 | 80 | Эконом-класс | + +**PostgreSQL** - CASE отлично подходит для множественных условий: - ```sql-executable-Airbnb - SELECT id, price, - CASE - WHEN price >= 200 THEN 'Бизнес-класс' - WHEN price >= 150 THEN 'Комфорт-класс' - ELSE 'Эконом-класс' - END AS category - FROM Rooms - ``` + ```sql + SELECT id, price, + CASE + WHEN price >= 200 THEN 'Бизнес-класс' + WHEN price >= 150 THEN 'Комфорт-класс' + ELSE 'Эконом-класс' + END AS category + FROM Rooms + ``` + + | id | price | category | + | --- | ----- | ------------- | + | 1 | 149 | Эконом-класс | + | 2 | 225 | Бизнес-класс | + | 3 | 150 | Комфорт-класс | + | 4 | 89 | Эконом-класс | + | 5 | 80 | Эконом-класс | + | 6 | 200 | Бизнес-класс | + | 7 | 60 | Эконом-класс | + | 8 | 79 | Эконом-класс | + | 9 | 79 | Эконом-класс | + | 10 | 150 | Комфорт-класс | + | 11 | 135 | Эконом-класс | + | 12 | 85 | Эконом-класс | + | 13 | 89 | Эконом-класс | + | 14 | 85 | Эконом-класс | + | 15 | 120 | Эконом-класс | + | 16 | 140 | Эконом-класс | + | 17 | 215 | Бизнес-класс | + | 18 | 140 | Эконом-класс | + | 19 | 99 | Эконом-класс | + | 20 | 190 | Комфорт-класс | + | 21 | 299 | Бизнес-класс | + | 22 | 130 | Эконом-класс | + | 23 | 80 | Эконом-класс | + | 24 | 110 | Эконом-класс | + | 25 | 120 | Эконом-класс | + | 26 | 60 | Эконом-класс | + | 27 | 80 | Эконом-класс | + | 28 | 150 | Комфорт-класс | + | 29 | 44 | Эконом-класс | + | 30 | 180 | Комфорт-класс | + | 31 | 50 | Эконом-класс | + | 32 | 52 | Эконом-класс | + | 33 | 55 | Эконом-класс | + | 34 | 50 | Эконом-класс | + | 35 | 70 | Эконом-класс | + | 36 | 89 | Эконом-класс | + | 37 | 35 | Эконом-класс | + | 38 | 85 | Эконом-класс | + | 39 | 150 | Комфорт-класс | + | 40 | 40 | Эконом-класс | + | 41 | 68 | Эконом-класс | + | 42 | 120 | Эконом-класс | + | 43 | 120 | Эконом-класс | + | 44 | 135 | Эконом-класс | + | 45 | 150 | Комфорт-класс | + | 46 | 150 | Комфорт-класс | + | 47 | 130 | Эконом-класс | + | 48 | 110 | Эконом-класс | + | 49 | 115 | Эконом-класс | + | 50 | 80 | Эконом-класс | Однако для специальных случаев PostgreSQL предоставляет более специализированные функции. - - - +**MySQL** ## Функции IFNULL и NULLIF @@ -141,9 +345,7 @@ IFNULL(значение, альтернативное_значение); Функция `IFNULL` возвращает `значение`, переданное первым аргументом, если оно не равно `NULL`, иначе возвращает `альтернативное_значение`. - - - +**PostgreSQL** ## Функция COALESCE @@ -176,61 +378,73 @@ END COALESCE(значение1, значение2, значение3) ``` - +**MySQL** - ### Примеры с функцией IFNULL - Если первый аргумент не равен `NULL`, то вернётся именно он. - ```sql-executable-Airbnb - SELECT IFNULL('SQL Academy', 'Альтернатива SQL Academy') AS sql_trainer; - ``` + ```sql + SELECT IFNULL('SQL Academy', 'Альтернатива SQL Academy') AS sql_trainer; + ``` + + | sql_trainer | + | ----------- | + | SQL Academy | - +**PostgreSQL** - ### Примеры с функцией COALESCE - Если первый аргумент не равен `NULL`, то вернётся именно он. - ```sql-executable-Airbnb - SELECT COALESCE('SQL Academy', 'Альтернатива SQL Academy') AS sql_trainer; - ``` + ```sql + SELECT COALESCE('SQL Academy', 'Альтернатива SQL Academy') AS sql_trainer; + ``` - + | coalesce | + | ----------- | + | SQL Academy | - +**MySQL** - Если первый аргумент равен `NULL`, то вернётся значение, переданное вторым аргументом. - ```sql-executable-Airbnb - SELECT IFNULL(NULL, 'Альтернатива SQL Academy') AS sql_trainer; - ``` + ```sql + SELECT IFNULL(NULL, 'Альтернатива SQL Academy') AS sql_trainer; + ``` - + | sql_trainer | + | ------------------------ | + | Альтернатива SQL Academy | - +**PostgreSQL** - Если первый аргумент равен `NULL`, то вернётся следующее не-NULL значение. - ```sql-executable-Airbnb - SELECT COALESCE(NULL, 'Альтернатива SQL Academy') AS sql_trainer; - ``` + ```sql + SELECT COALESCE(NULL, 'Альтернатива SQL Academy') AS sql_trainer; + ``` + + | coalesce | + | ------------------------ | + | Альтернатива SQL Academy | - `COALESCE` может принимать множество аргументов, что делает код очень читаемым: - ```sql-executable-Airbnb - SELECT COALESCE(NULL, NULL, 'SQL Academy', 'Запасной вариант') AS sql_trainer; - ``` + ```sql + SELECT COALESCE(NULL, NULL, 'SQL Academy', 'Запасной вариант') AS sql_trainer; + ``` + + | coalesce | + | ----------- | + | SQL Academy | ## Функция NULLIF Функция `NULLIF` полезна, когда нужно заменить определенное значение на NULL. Это может пригодиться для фильтрации или обработки "пустых" значений. - - ### Синтаксис NULLIF ```sql @@ -241,47 +455,55 @@ NULLIF(значение_1, значение_2); ### Примеры с функцией NULLIF - +**MySQL** - Если значение первого аргумента равно значению второго аргумента, то возвращается `NULL`. - ```sql-executable-Airbnb - SELECT NULLIF('SQL Academy', 'SQL Academy') AS sql_trainer; - ``` + ```sql + SELECT NULLIF('SQL Academy', 'SQL Academy') AS sql_trainer; + ``` - + | sql_trainer | + | ----------- | + | null | - +**PostgreSQL** - Если значение первого аргумента равно значению второго аргумента, то возвращается `NULL`. - ```sql-executable-Airbnb - SELECT NULLIF('SQL Academy', 'SQL Academy') AS sql_trainer; - ``` + ```sql + SELECT NULLIF('SQL Academy', 'SQL Academy') AS sql_trainer; + ``` - + | nullif | + | ------ | + | null | - +**MySQL** - Если значения первого и второго аргумента различаются, то возвращается значение первого аргумента. - ```sql-executable-Airbnb - SELECT NULLIF('SQL Academy', 'Альтернатива SQL Academy') AS sql_trainer; - ``` + ```sql + SELECT NULLIF('SQL Academy', 'Альтернатива SQL Academy') AS sql_trainer; + ``` - + | sql_trainer | + | ----------- | + | SQL Academy | - +**PostgreSQL** - Если значения первого и второго аргумента различаются, то возвращается значение первого аргумента. - ```sql-executable-Airbnb - SELECT NULLIF('SQL Academy', 'Альтернатива SQL Academy') AS sql_trainer; - ``` + ```sql + SELECT NULLIF('SQL Academy', 'Альтернатива SQL Academy') AS sql_trainer; + ``` - + | nullif | + | ----------- | + | SQL Academy | - +**PostgreSQL** ### Когда использовать каждую функцию: @@ -290,5 +512,3 @@ NULLIF(значение_1, значение_2); - **NULLIF**: Когда нужно превратить определенные значения в NULL Эти функции делают код более читаемым и являются частью стандарта SQL. - - diff --git a/course/module-3/inner-join/article.md b/course/module-3/inner-join/article.md index ca7750e..d8be86c 100644 --- a/course/module-3/inner-join/article.md +++ b/course/module-3/inner-join/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Внутреннее соединение INNER JOIN' - description: 'Описание и синтаксис внутреннего соединения INNER JOIN' + title: "Внутреннее соединение INNER JOIN" + description: "Описание и синтаксис внутреннего соединения INNER JOIN" --- # Внутреннее соединение INNER JOIN @@ -30,7 +30,7 @@ FROM таблица_1 Например, запрос может выглядеть следующим образом: - +ER-диаграмма базы данных Family: [открыть на SQL Academy](https://sql-academy.org/ru/guide/inner-join). ```sql SELECT family_member, member_name FROM Payments @@ -64,7 +64,7 @@ INNER JOIN FamilyMembers Для наглядности это выглядит следующим образом: -![Схема внутреннего соединения](https://sql-academy.org/static/guidePage/inner-join/inner-join-example.png 'Схема внутреннего соединения') +![Схема внутреннего соединения](https://sql-academy.org/static/guidePage/inner-join/inner-join-example.png "Схема внутреннего соединения") Так как в нашем условии указано равенство полей `Payments.good_id` и `Goods.good_id`, то при внутреннем соединении в итоговой выборке окажутся только записи, где в обеих таблицах есть одинаковое значение `good_id`. diff --git a/course/module-3/limit/article.md b/course/module-3/limit/article.md index 0f8aca1..0a32eb0 100644 --- a/course/module-3/limit/article.md +++ b/course/module-3/limit/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Ограничение выборки, оператор LIMIT" - description: "Описание и синтаксис оператора ограничения числа записей SQL LIMIT, примеры использования и задания для самопроверки." + title: "Ограничение выборки, оператор LIMIT" + description: "Описание и синтаксис оператора ограничения числа записей SQL LIMIT, примеры использования и задания для самопроверки." --- # Ограничение выборки, оператор LIMIT @@ -10,7 +10,7 @@ meta: ## Общая структура запроса с оператором LIMIT - +**MySQL** **Синтаксис с запятой:** @@ -30,9 +30,7 @@ LIMIT количество_записей_для_вывода [OFFSET колич Если не указать количество пропущенных записей, то их отсчёт будет вестись с начала таблицы. - - - +**PostgreSQL** ```sql SELECT поля_выборки @@ -42,38 +40,48 @@ LIMIT количество_записей_для_вывода [OFFSET колич Если не указать `OFFSET`, то отсчёт будет вестись с начала таблицы. - - ## Пример использования Возьмём таблицу `Company`: -Для того, чтобы вывести строки с 3 по 5, нужно использовать такой запрос: +| id | name | +| --- | ---------- | +| 1 | Don_avia | +| 2 | Aeroflot | +| 3 | Dale_avia | +| 4 | air_France | +| 5 | British_AW | + +Для того чтобы вывести строки с 3 по 5, нужно использовать такой запрос: - +**MySQL** -```sql-executable-Airo +```sql SELECT * FROM Company LIMIT 2, 3; ``` Или, что то же самое: -```sql-executable-Airo +```sql SELECT * FROM Company LIMIT 3 OFFSET 2; ``` - +**PostgreSQL** - - -```sql-executable-Airo +```sql SELECT * FROM Company LIMIT 3 OFFSET 2; ``` - - В результате запроса вернётся следующая выборка: +| id | name | +| --- | ---------- | +| 3 | Dale_avia | +| 4 | air_France | +| 5 | British_AW | + В данном запросе происходит пропуск первых двух строк таблицы (1, 2), после чего выводятся следующие три записи (3, 4, 5). А теперь попробуйте сами ⚡️ + +Интерактивная демонстрация доступна [в уроке на SQL Academy](https://sql-academy.org/ru/guide/limit). diff --git a/course/module-3/multi-table-request-join/article.md b/course/module-3/multi-table-request-join/article.md index a1bf9e1..5419299 100644 --- a/course/module-3/multi-table-request-join/article.md +++ b/course/module-3/multi-table-request-join/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Многотабличные запросы, оператор JOIN' - description: 'Описание и синтаксис оператора SQL JOIN, примеры использования и задания для самопроверки' + title: "Многотабличные запросы, оператор JOIN" + description: "Описание и синтаксис оператора SQL JOIN, примеры использования и задания для самопроверки" --- # Многотабличные запросы, JOIN @@ -40,7 +40,7 @@ SELECT family_member, amount * unit_price AS price FROM Payments Вместо этих идентификаторов было бы гораздо нагляднее выводить имена тех, кто покупал (поле `member_name` из таблицы `FamilyMember`). Ровно для этого и существует объединение таблиц и оператор `JOIN`. - +ER-диаграмма базы данных Family: [открыть на SQL Academy](https://sql-academy.org/ru/guide/multi-table-request-join). ## Общая структура многотабличного запроса @@ -55,8 +55,8 @@ FROM таблица_1 Как можно увидеть по структуре, соединение бывает: -- внутренним `INNER` (по умолчанию) -- внешним `OUTER`, при этом внешнее соединение делится на левое `LEFT`, правое `RIGHT` и полное `FULL` +- внутренним `INNER` (по умолчанию) +- внешним `OUTER`, при этом внешнее соединение делится на левое `LEFT`, правое `RIGHT` и полное `FULL` С более подробными деталями, чем отличается внутреннее соединение от внешнего и как они работают, мы познакомимся в следующих статьях. @@ -180,5 +180,5 @@ INNER JOIN Pass_in_trip При использовании псевдонимов всегда руководствуйтесь следующими простыми правилами, и тогда ваши запросы будут лаконичными и понятными: -- Используйте логичные сокращения (например, первые буквы названия таблицы) -- Избегайте слишком коротких (однобуквенных) или неочевидных псевдонимов +- Используйте логичные сокращения (например, первые буквы названия таблицы) +- Избегайте слишком коротких (однобуквенных) или неочевидных псевдонимов diff --git a/course/module-3/nested-sql-queries/article.md b/course/module-3/nested-sql-queries/article.md index cec57d3..480a0dd 100644 --- a/course/module-3/nested-sql-queries/article.md +++ b/course/module-3/nested-sql-queries/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Подзапросы в SQL' - description: 'Подзапросы, вложенные запросы в SQL. Их виды и применение.' + title: "Подзапросы в SQL" + description: "Подзапросы, вложенные запросы в SQL. Их виды и применение." --- # Подзапросы @@ -15,9 +15,9 @@ meta: Как и любой другой SQL запрос, подзапрос возвращает результирующий набор, который может быть одним из следующих: -- одна строка и один столбец; -- несколько строк с одним столбцом; -- несколько строк с несколькими столбцами. +- одна строка и один столбец; +- несколько строк с одним столбцом; +- несколько строк с несколькими столбцами. В зависимости от типа результирующего набора подзапроса определяются операторы, которые могут использоваться в основном запросе. diff --git a/course/module-3/operator-with/article.md b/course/module-3/operator-with/article.md index bc44db5..fa1e28e 100644 --- a/course/module-3/operator-with/article.md +++ b/course/module-3/operator-with/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Обобщённое табличное выражение, оператор WITH" - description: "Обобщённое табличное выражение (Common Table Expression) в SQL. Синтаксис оператора WITH и примеры его использования." + title: "Обобщённое табличное выражение, оператор WITH" + description: "Обобщённое табличное выражение (Common Table Expression) в SQL. Синтаксис оператора WITH и примеры его использования." --- # Обобщённое табличное выражение, оператор WITH @@ -9,7 +9,7 @@ meta: Обобщённое табличное выражение или CTE (Common Table Expressions) - это временный результирующий набор данных, к которому можно обращаться в последующих запросах. Для написания обобщённого табличного выражения используется оператор `WITH`. -```sql-Trip-executable +```sql -- Пример использования конструкции WITH WITH Aeroflot_trips AS (SELECT TRIP.* FROM Company @@ -40,11 +40,11 @@ WITH название_cte [(столбец_1 [, столбец_2 ] …)] AS (п ## Примеры запросов - +ER-диаграмма базы данных Airo: [открыть на SQL Academy](https://sql-academy.org/ru/guide/operator-with). 1. Создаём табличное выражение `Aeroflot_trips`, содержащее все полёты, совершенные авиакомпанией «Aeroflot» -```sql-Trip-executable +```sql WITH Aeroflot_trips AS (SELECT plane, town_from, town_to FROM Company INNER JOIN Trip ON Trip.company = Company.id WHERE name = 'Aeroflot') @@ -52,9 +52,14 @@ WITH Aeroflot_trips AS SELECT * FROM Aeroflot_trips; ``` +| plane | town_from | town_to | +| ----- | --------- | ------- | +| IL-86 | Moscow | Rostov | +| IL-86 | Rostov | Moscow | + 2. Аналогично, создаём табличное выражение `Aeroflot_trips`, но с переименованными колонками -```sql-Trip-executable +```sql WITH Aeroflot_trips (aeroflot_plane, town_from, town_to) AS (SELECT plane, town_from, town_to FROM Company INNER JOIN Trip ON Trip.company = Company.id WHERE name = 'Aeroflot') @@ -62,9 +67,14 @@ WITH Aeroflot_trips (aeroflot_plane, town_from, town_to) AS SELECT * FROM Aeroflot_trips; ``` +| aeroflot_plane | town_from | town_to | +| -------------- | --------- | ------- | +| IL-86 | Moscow | Rostov | +| IL-86 | Rostov | Moscow | + 3. С помощью оператора `WITH` определяем несколько табличных выражений -```sql-Trip-executable +```sql WITH Aeroflot_trips AS (SELECT TRIP.* FROM Company INNER JOIN Trip ON Trip.company = Company.id WHERE name = 'Aeroflot'), @@ -75,6 +85,17 @@ WITH Aeroflot_trips AS SELECT * FROM Don_avia_trips UNION SELECT * FROM Aeroflot_trips; ``` +| id | company | plane | town_from | town_to | time_out | time_in | +| ---- | ------- | ------ | --------- | ------- | ------------------------ | ------------------------ | +| 1181 | 1 | TU-134 | Rostov | Moscow | 1900-01-01T06:12:00.000Z | 1900-01-01T08:01:00.000Z | +| 1182 | 1 | TU-134 | Moscow | Rostov | 1900-01-01T12:35:00.000Z | 1900-01-01T14:30:00.000Z | +| 1187 | 1 | TU-134 | Rostov | Moscow | 1900-01-01T15:42:00.000Z | 1900-01-01T17:39:00.000Z | +| 1188 | 1 | TU-134 | Moscow | Rostov | 1900-01-01T22:50:00.000Z | 1900-01-02T00:48:00.000Z | +| 1195 | 1 | TU-154 | Rostov | Moscow | 1900-01-01T23:30:00.000Z | 1900-01-02T01:11:00.000Z | +| 1196 | 1 | TU-154 | Moscow | Rostov | 1900-01-01T04:00:00.000Z | 1900-01-01T05:45:00.000Z | +| 1145 | 2 | IL-86 | Moscow | Rostov | 1900-01-01T09:35:00.000Z | 1900-01-01T11:23:00.000Z | +| 1146 | 2 | IL-86 | Rostov | Moscow | 1900-01-01T17:55:00.000Z | 1900-01-01T20:01:00.000Z | + ## Работа с рекурсией в CTE CTE также могут быть использованы для выполнения рекурсивных запросов, @@ -111,6 +132,15 @@ SELECT * FROM название_cte; Рассмотрим таблицу `Employees`, которая содержит идентификаторы сотрудников и их руководителей: +| id | name | managerId | +| --- | --------------- | --------- | +| 1 | John Smith | null | +| 2 | Michael Johnson | 1 | +| 3 | Robert Williams | 1 | +| 4 | James Brown | 2 | +| 5 | David Jones | 2 | +| 6 | Richard Davis | 3 | + Требуется найти всех подчинённых `John Smith` (`id=1`) на всех уровнях иерархии. ```sql @@ -131,68 +161,14 @@ WITH RECURSIVE Subordinates AS ( SELECT * FROM Subordinates; ``` -### Шаги выполнения рекурсивного CTE - -1. **Начальный набор данных:** выбираются все сотрудники, у которых `managerId=1` (непосредственные подчинённые `John Smith`). -2. **Рекурсивная часть:** для каждого сотрудника, выбранного в начальном наборе данных, выбираются их подчинённые (где `managerId` равен `id` выбранного сотрудника). -3. **Объединение:** результаты начального набора данных и рекурсивной частей объединяются с помощью `UNION ALL`. -4. **Рекурсия:** процесс повторяется для каждого нового набора подчинённых, пока не будут выбраны все уровни иерархии. - -## Работа с рекурсией в CTE - -CTE также могут быть использованы для выполнения рекурсивных запросов, -которые позволяют итеративно обрабатывать данные, например, -для работы с иерархическими структурами данных, такими как «руководитель — подчинённый». - -### Синтаксис рекурсивного CTE - -Рекурсивное CTE состоит из двух частей, разделенных оператором `UNION ALL`: - -- Начальный набор данных, который не содержит рекурсивных ссылок. -- Рекурсивная часть: запрос, который ссылается на CTE, чтобы продолжить рекурсию. - -```sql -WITH RECURSIVE название_cte (столбец_1, столбец_2, ...) AS ( - -- Начальный набор данных - SELECT столбец_1, столбец_2, ... - FROM таблица - WHERE условие - - UNION ALL +| id | name | managerId | +| --- | --------------- | --------- | +| 2 | Michael Johnson | 1 | +| 3 | Robert Williams | 1 | +| 4 | James Brown | 2 | +| 5 | David Jones | 2 | +| 6 | Richard Davis | 3 | - -- Рекурсивная часть - SELECT столбец_1, столбец_2, ... - FROM название_cte - INNER JOIN таблица ON название_cte.столбец = таблица.столбец - WHERE условие -) - -SELECT * FROM название_cte; -``` - -### Пример: иерархия руководителей и подчинённых - -Рассмотрим таблицу `Employees`, которая содержит идентификаторы сотрудников и их руководителей: - -Требуется найти всех подчинённых `John Smith` (`id=1`) на всех уровнях иерархии. - -```sql -WITH RECURSIVE Subordinates AS ( - -- Начальный набор данных - SELECT id, name, managerId - FROM Employees - WHERE managerId = 1 - - UNION ALL - - -- Рекурсивная часть: подчинённые подчинённых - SELECT e.id, e.name, e.managerId - FROM Employees e - INNER JOIN Subordinates s ON e.managerId = s.id -) - -SELECT * FROM Subordinates; -``` ### Шаги выполнения рекурсивного CTE 1. **Начальный набор данных:** выбираются все сотрудники, у которых `managerId=1` (непосредственные подчинённые `John Smith`). diff --git a/course/module-3/outer-join/article.md b/course/module-3/outer-join/article.md index b44cf37..825ddd4 100644 --- a/course/module-3/outer-join/article.md +++ b/course/module-3/outer-join/article.md @@ -1,243 +1,234 @@ --- meta: - title: "Внешнее соединение OUTER JOIN" - description: "Описание и синтаксис внешнего соединения OUTER JOIN" + title: "Внешнее соединение OUTER JOIN" + description: "Как работают LEFT, RIGHT и FULL OUTER JOIN: строки без пары, NULL в результате и почему строк становится больше" --- # Внешнее соединение OUTER JOIN -Внешнее соединение может быть трёх типов: левое (`LEFT`), правое (`RIGHT`) и полное (`FULL`). По умолчанию оно является полным. +Внутреннее соединение оставляет только те строки, для которых нашлась пара во второй таблице. Внешнее соединение работает иначе: оно обязательно возвращает все строки одной таблицы или обеих, а недостающую половину заполняет значениями `NULL`. -Главным отличием внешнего соединения от внутреннего является то, что оно обязательно возвращает все строки одной (`LEFT`, `RIGHT`) или двух таблиц (`FULL`). +Внешнее соединение бывает трёх типов: левое (`LEFT`), правое (`RIGHT`) и полное (`FULL`). Тип указывать обязательно — написать просто `OUTER JOIN` нельзя, это синтаксическая ошибка. А вот само слово `OUTER` необязательно: `LEFT JOIN` и `LEFT OUTER JOIN` означают одно и то же, и дальше используется короткая запись. + +> Не путайте с `JOIN` без уточнений — это внутреннее соединение, то же самое, что `INNER JOIN`. ## Внешнее левое соединение (LEFT OUTER JOIN) -Соединение, которое возвращает все значения из левой таблицы, соединённые с соответствующими значениями из правой таблицы, -если они удовлетворяют условию соединения, или заменяет их на `NULL` в обратном случае. +Возвращает все строки левой таблицы. Если для строки нашлась пара в правой таблице, строки склеиваются; если не нашлась — поля правой таблицы заполняются `NULL`. -Для примера получим из базы данных расписание звонков, объединённых с соответствующими занятиями в расписании занятий. +Для примера получим из базы данных расписание звонков, объединённое с соответствующими занятиями в расписании занятий. - +ER-диаграмма базы данных Schedule: [открыть на SQL Academy](https://sql-academy.org/ru/guide/outer-join). Данные в таблице `Timepair` (расписание звонков): +| id | start_pair | end_pair | +| --- | ---------- | -------- | +| 1 | 08:30:00 | 09:15:00 | +| 2 | 09:20:00 | 10:05:00 | +| 3 | 10:15:00 | 11:00:00 | +| 4 | 11:05:00 | 11:50:00 | +| 5 | 12:50:00 | 13:35:00 | +| 6 | 13:40:00 | 14:25:00 | +| 7 | 14:35:00 | 15:20:00 | +| 8 | 15:25:00 | 16:10:00 | + Данные в таблице `Schedule` (расписание занятий): -```sql-executable-Schedule -SELECT Timepair.id 'timepair.id', start_pair, end_pair, - Schedule.id 'schedule.id', date, class, number_pair, teacher, subject, classroom +| id | date | class | number_pair | teacher | subject | classroom | +| --- | ------------------------ | ----- | ----------- | ------- | ------- | --------- | +| 1 | 2019-09-01T00:00:00.000Z | 9 | 1 | 11 | 1 | 47 | +| 2 | 2019-09-01T00:00:00.000Z | 9 | 2 | 8 | 2 | 13 | +| 3 | 2019-09-01T00:00:00.000Z | 9 | 3 | 4 | 3 | 13 | +| 4 | 2019-09-02T00:00:00.000Z | 9 | 1 | 4 | 3 | 13 | +| 5 | 2019-09-02T00:00:00.000Z | 9 | 2 | 2 | 4 | 34 | +| 6 | 2019-09-02T00:00:00.000Z | 9 | 3 | 6 | 5 | 35 | +| 7 | 2019-09-03T00:00:00.000Z | 9 | 1 | 5 | 6 | 36 | +| 8 | 2019-09-03T00:00:00.000Z | 9 | 2 | 13 | 7 | 37 | +| 9 | 2019-09-03T00:00:00.000Z | 9 | 3 | 6 | 8 | 38 | +| 10 | 2019-09-04T00:00:00.000Z | 9 | 1 | 9 | 9 | 39 | +| 11 | 2019-09-04T00:00:00.000Z | 9 | 2 | 10 | 10 | 40 | +| 12 | 2019-09-04T00:00:00.000Z | 9 | 3 | 3 | 11 | 41 | +| 13 | 2019-09-05T00:00:00.000Z | 9 | 1 | 3 | 13 | 43 | +| 14 | 2019-09-05T00:00:00.000Z | 9 | 2 | 11 | 1 | 47 | +| 15 | 2019-09-05T00:00:00.000Z | 9 | 3 | 5 | 6 | 36 | +| 16 | 2019-08-30T00:00:00.000Z | 9 | 1 | 2 | 4 | 34 | +| 17 | 2019-08-30T00:00:00.000Z | 9 | 2 | 8 | 2 | 13 | +| 18 | 2019-08-30T00:00:00.000Z | 9 | 3 | 6 | 5 | 35 | +| 19 | 2019-08-30T00:00:00.000Z | 9 | 4 | 10 | 1 | 47 | +| 20 | 2019-09-03T00:00:00.000Z | 9 | 4 | 10 | 10 | 40 | +| 21 | 2019-08-30T00:00:00.000Z | 8 | 1 | 7 | 9 | 53 | +| 22 | 2019-08-30T00:00:00.000Z | 8 | 2 | 7 | 9 | 53 | +| 23 | 2019-08-30T00:00:00.000Z | 8 | 3 | 8 | 2 | 38 | +| 24 | 2019-08-30T00:00:00.000Z | 8 | 4 | 11 | 1 | 43 | +| 25 | 2019-08-30T00:00:00.000Z | 8 | 5 | 8 | 3 | 39 | +| 26 | 2019-09-01T00:00:00.000Z | 8 | 2 | 2 | 4 | 34 | +| 27 | 2019-09-01T00:00:00.000Z | 8 | 3 | 6 | 5 | 35 | +| 28 | 2019-09-01T00:00:00.000Z | 8 | 4 | 12 | 6 | 36 | +| 29 | 2019-09-01T00:00:00.000Z | 8 | 5 | 13 | 7 | 37 | +| 30 | 2019-09-02T00:00:00.000Z | 8 | 3 | 6 | 8 | 38 | +| 31 | 2019-09-02T00:00:00.000Z | 8 | 4 | 7 | 9 | 53 | +| 32 | 2019-09-03T00:00:00.000Z | 8 | 1 | 10 | 10 | 40 | +| 33 | 2019-09-03T00:00:00.000Z | 8 | 2 | 7 | 9 | 53 | +| 34 | 2019-09-03T00:00:00.000Z | 8 | 3 | 7 | 9 | 53 | +| 35 | 2019-09-04T00:00:00.000Z | 8 | 1 | 1 | 11 | 4 | +| 36 | 2019-09-04T00:00:00.000Z | 8 | 2 | 1 | 12 | 42 | +| 37 | 2019-09-04T00:00:00.000Z | 8 | 3 | 3 | 13 | 43 | +| 38 | 2019-09-04T00:00:00.000Z | 8 | 4 | 8 | 2 | 42 | +| 39 | 2019-09-04T00:00:00.000Z | 8 | 5 | 11 | 1 | 43 | +| 40 | 2019-09-05T00:00:00.000Z | 8 | 2 | 11 | 1 | 43 | + +```sql +SELECT Timepair.id "timepair.id", start_pair, end_pair, + Schedule.id "schedule.id", date, class, number_pair, teacher, subject, classroom FROM Timepair LEFT JOIN Schedule ON Schedule.number_pair = Timepair.id; ``` -В выборку попали все строки из левой таблицы, дополненные данными о занятиях. -Примечательно, что в конце таблицы есть строки с полями, заполненными `NULL`. -Это те строки, для которых не нашлось соответствующих занятий, однако они присутствуют в левой таблице, поэтому тоже были выведены. - -## Внешнее правое соединение (RIGHT OUTER JOIN) +| timepair.id | start_pair | end_pair | schedule.id | date | class | number_pair | teacher | subject | classroom | +| ----------- | ---------- | -------- | ----------- | ------------------------ | ----- | ----------- | ------- | ------- | --------- | +| 1 | 08:30:00 | 09:15:00 | 35 | 2019-09-04T00:00:00.000Z | 8 | 1 | 1 | 11 | 4 | +| 1 | 08:30:00 | 09:15:00 | 32 | 2019-09-03T00:00:00.000Z | 8 | 1 | 10 | 10 | 40 | +| 1 | 08:30:00 | 09:15:00 | 21 | 2019-08-30T00:00:00.000Z | 8 | 1 | 7 | 9 | 53 | +| 1 | 08:30:00 | 09:15:00 | 16 | 2019-08-30T00:00:00.000Z | 9 | 1 | 2 | 4 | 34 | +| 1 | 08:30:00 | 09:15:00 | 13 | 2019-09-05T00:00:00.000Z | 9 | 1 | 3 | 13 | 43 | +| 1 | 08:30:00 | 09:15:00 | 10 | 2019-09-04T00:00:00.000Z | 9 | 1 | 9 | 9 | 39 | +| 1 | 08:30:00 | 09:15:00 | 7 | 2019-09-03T00:00:00.000Z | 9 | 1 | 5 | 6 | 36 | +| 1 | 08:30:00 | 09:15:00 | 4 | 2019-09-02T00:00:00.000Z | 9 | 1 | 4 | 3 | 13 | +| 1 | 08:30:00 | 09:15:00 | 1 | 2019-09-01T00:00:00.000Z | 9 | 1 | 11 | 1 | 47 | +| 2 | 09:20:00 | 10:05:00 | 40 | 2019-09-05T00:00:00.000Z | 8 | 2 | 11 | 1 | 43 | +| 2 | 09:20:00 | 10:05:00 | 36 | 2019-09-04T00:00:00.000Z | 8 | 2 | 1 | 12 | 42 | +| 2 | 09:20:00 | 10:05:00 | 33 | 2019-09-03T00:00:00.000Z | 8 | 2 | 7 | 9 | 53 | +| 2 | 09:20:00 | 10:05:00 | 26 | 2019-09-01T00:00:00.000Z | 8 | 2 | 2 | 4 | 34 | +| 2 | 09:20:00 | 10:05:00 | 22 | 2019-08-30T00:00:00.000Z | 8 | 2 | 7 | 9 | 53 | +| 2 | 09:20:00 | 10:05:00 | 17 | 2019-08-30T00:00:00.000Z | 9 | 2 | 8 | 2 | 13 | +| 2 | 09:20:00 | 10:05:00 | 14 | 2019-09-05T00:00:00.000Z | 9 | 2 | 11 | 1 | 47 | +| 2 | 09:20:00 | 10:05:00 | 11 | 2019-09-04T00:00:00.000Z | 9 | 2 | 10 | 10 | 40 | +| 2 | 09:20:00 | 10:05:00 | 8 | 2019-09-03T00:00:00.000Z | 9 | 2 | 13 | 7 | 37 | +| 2 | 09:20:00 | 10:05:00 | 5 | 2019-09-02T00:00:00.000Z | 9 | 2 | 2 | 4 | 34 | +| 2 | 09:20:00 | 10:05:00 | 2 | 2019-09-01T00:00:00.000Z | 9 | 2 | 8 | 2 | 13 | +| 3 | 10:15:00 | 11:00:00 | 37 | 2019-09-04T00:00:00.000Z | 8 | 3 | 3 | 13 | 43 | +| 3 | 10:15:00 | 11:00:00 | 34 | 2019-09-03T00:00:00.000Z | 8 | 3 | 7 | 9 | 53 | +| 3 | 10:15:00 | 11:00:00 | 30 | 2019-09-02T00:00:00.000Z | 8 | 3 | 6 | 8 | 38 | +| 3 | 10:15:00 | 11:00:00 | 27 | 2019-09-01T00:00:00.000Z | 8 | 3 | 6 | 5 | 35 | +| 3 | 10:15:00 | 11:00:00 | 23 | 2019-08-30T00:00:00.000Z | 8 | 3 | 8 | 2 | 38 | +| 3 | 10:15:00 | 11:00:00 | 18 | 2019-08-30T00:00:00.000Z | 9 | 3 | 6 | 5 | 35 | +| 3 | 10:15:00 | 11:00:00 | 15 | 2019-09-05T00:00:00.000Z | 9 | 3 | 5 | 6 | 36 | +| 3 | 10:15:00 | 11:00:00 | 12 | 2019-09-04T00:00:00.000Z | 9 | 3 | 3 | 11 | 41 | +| 3 | 10:15:00 | 11:00:00 | 9 | 2019-09-03T00:00:00.000Z | 9 | 3 | 6 | 8 | 38 | +| 3 | 10:15:00 | 11:00:00 | 6 | 2019-09-02T00:00:00.000Z | 9 | 3 | 6 | 5 | 35 | +| 3 | 10:15:00 | 11:00:00 | 3 | 2019-09-01T00:00:00.000Z | 9 | 3 | 4 | 3 | 13 | +| 4 | 11:05:00 | 11:50:00 | 38 | 2019-09-04T00:00:00.000Z | 8 | 4 | 8 | 2 | 42 | +| 4 | 11:05:00 | 11:50:00 | 31 | 2019-09-02T00:00:00.000Z | 8 | 4 | 7 | 9 | 53 | +| 4 | 11:05:00 | 11:50:00 | 28 | 2019-09-01T00:00:00.000Z | 8 | 4 | 12 | 6 | 36 | +| 4 | 11:05:00 | 11:50:00 | 24 | 2019-08-30T00:00:00.000Z | 8 | 4 | 11 | 1 | 43 | +| 4 | 11:05:00 | 11:50:00 | 20 | 2019-09-03T00:00:00.000Z | 9 | 4 | 10 | 10 | 40 | +| 4 | 11:05:00 | 11:50:00 | 19 | 2019-08-30T00:00:00.000Z | 9 | 4 | 10 | 1 | 47 | +| 5 | 12:50:00 | 13:35:00 | 39 | 2019-09-04T00:00:00.000Z | 8 | 5 | 11 | 1 | 43 | +| 5 | 12:50:00 | 13:35:00 | 29 | 2019-09-01T00:00:00.000Z | 8 | 5 | 13 | 7 | 37 | +| 5 | 12:50:00 | 13:35:00 | 25 | 2019-08-30T00:00:00.000Z | 8 | 5 | 8 | 3 | 39 | +| 6 | 13:40:00 | 14:25:00 | null | null | null | null | null | null | null | +| 7 | 14:35:00 | 15:20:00 | null | null | null | null | null | null | null | +| 8 | 15:25:00 | 16:10:00 | null | null | null | null | null | null | null | + +В результат попали все восемь звонков — как и обещает левое соединение. Но строк получилось 43, а не 8. + +Соединение не дополняет левую таблицу, а перебирает все подходящие пары строк. Один и тот же номер пары встречается в расписании занятий много раз — в разные дни и у разных классов, — и каждое совпадение даёт отдельную строку. Если ключ в правой таблице неуникален, строк в результате будет больше, чем в левой таблице. + +В конце выборки есть строки, где все поля занятия заполнены `NULL`. Это звонки, для которых не нашлось ни одного занятия: пары нет, но строка левой таблицы обязана попасть в результат. + +### Строки без пары + +На этих `NULL` строится самый частый практический приём — найти записи, у которых пары нет. Достаточно оставить только строки с пустым ключом правой таблицы: -Соединение, которое возвращает все значения из правой таблицы, соединённые с соответствующими значениями из левой таблицы, если они удовлетворяют условию соединения, -или заменяет их на `NULL` в обратном случае. +```sql +SELECT Timepair.id, start_pair, end_pair +FROM Timepair + LEFT JOIN Schedule ON Schedule.number_pair = Timepair.id +WHERE Schedule.number_pair IS NULL; +``` - +| id | start_pair | end_pair | +| --- | ---------- | -------- | +| 6 | 13:40:00 | 14:25:00 | +| 7 | 14:35:00 | 15:20:00 | +| 8 | 15:25:00 | 16:10:00 | -## Внешнее полное соединение (FULL OUTER JOIN) +Остались три звонка, на которые не поставлено ни одного занятия. -Соединение, которое выполняет внутреннее соединение записей и дополняет их левым внешним соединением и правым внешним соединением. +Соединение, из которого оставляют только строки без пары, называют **анти-джойном** (`ANTI JOIN`). Собственного оператора у него нет: и в MySQL, и в PostgreSQL его записывают именно так — соединением и условием `IS NULL`. -Алгоритм работы полного соединения: +## Внешнее правое соединение (RIGHT OUTER JOIN) -- Формируется таблица на основе внутреннего соединения (`INNER JOIN`) -- В таблицу добавляются значения, не вошедшие в результат формирования из левой таблицы (`LEFT OUTER JOIN`) -- В таблицу добавляются значения, не вошедшие в результат формирования из правой таблицы (`RIGHT OUTER JOIN`) +Зеркальное отражение левого: в результат обязательно попадают все строки правой таблицы, а недостающие поля левой заполняются `NULL`. - +```sql +SELECT Timepair.id "timepair.id", start_pair, end_pair, + Schedule.id "schedule.id", date, class, number_pair, teacher, subject, classroom +FROM Timepair + RIGHT JOIN Schedule ON Schedule.number_pair = Timepair.id; +``` - +В результате 40 строк — ровно столько, сколько записей в `Schedule`, и ни одной строки с `NULL`. То есть он полностью совпал с внутренним соединением. -## Эмуляция полного соединения в MySQL +Так вышло потому, что каждое занятие ссылается на существующий звонок: непарных строк в правой таблице просто нет. Вид соединения задаёт правило, но что окажется в результате, решают данные. -Поскольку MySQL не поддерживает `FULL OUTER JOIN`, его можно эмулировать с помощью `UNION ALL`: +## Внешнее полное соединение (FULL OUTER JOIN) -```sql -SELECT * -FROM левая_таблица -LEFT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ +Возвращает все строки обеих таблиц. Строки с найденной парой склеиваются, а непарные строки левой и правой таблиц попадают в результат с `NULL` вместо второй половины. -UNION ALL +Результат полного соединения складывается из трёх частей: -SELECT * -FROM левая_таблица -RIGHT JOIN правая_таблица -ON правая_таблица.ключ = левая_таблица.ключ - WHERE левая_таблица.ключ IS NULL -``` +- строки, вошедшие во внутреннее соединение (`INNER JOIN`); +- строки левой таблицы, для которых не нашлось пары; +- строки правой таблицы, для которых не нашлось пары. - - -## Базовые запросы для разных вариантов объединения таблиц - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +2. Ровно восемь: левое соединение возвращает все строки левой таблицы — Все восемь строк действительно попадут в результат, но строка с несколькими парами размножится — строк станет больше восьми. -
СхемаЗапрос с JOIN
- - - Получение всех данных из левой таблицы, соединённых с соответствующими - данными из правой: - ```sql - SELECT поля_таблиц - FROM левая_таблица LEFT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ - ``` -
- - - Получение всех данных из правой таблицы, соединённых с соответствующими - данными из левой: - ```sql - SELECT поля_таблиц - FROM левая_таблица RIGHT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ - ``` -
- - - Получение данных, относящихся только к левой таблице: - ```sql - SELECT поля_таблиц - FROM левая_таблица LEFT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ - WHERE правая_таблица.ключ IS NULL - ``` -
- - - Получение данных, относящихся только к правой таблице: - ```sql - SELECT поля_таблиц - FROM левая_таблица RIGHT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ - WHERE левая_таблица.ключ IS NULL - ``` -
- - - Получение данных, относящихся как к левой, так и к правой таблице: - ```sql - SELECT поля_таблиц - FROM левая_таблица INNER JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ - ``` -
- - - Получение всех данных, относящихся к левой и правой таблицам, а также их - внутреннему соединению: - - +**PostgreSQL** ```sql -SELECT поля_таблиц -FROM левая_таблица - FULL OUTER JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ +SELECT Timepair.id "timepair.id", start_pair, end_pair, + Schedule.id "schedule.id", date, class, number_pair, teacher, subject, classroom +FROM Timepair + FULL OUTER JOIN Schedule ON Schedule.number_pair = Timepair.id; ``` - +На данных этой базы результат совпадёт с левым соединением — те же 43 строки: непарные строки здесь есть только слева. - +**MySQL** + +MySQL не поддерживает `FULL OUTER JOIN`, но тот же результат можно собрать вручную: взять левое соединение и добавить к нему строки правой таблицы, которым не нашлось пары. ```sql SELECT поля_таблиц FROM левая_таблица -LEFT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ + LEFT JOIN правая_таблица ON правая_таблица.ключ = левая_таблица.ключ UNION ALL SELECT поля_таблиц FROM левая_таблица -RIGHT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ -WHERE левая_таблица.ключ IS NULL -``` - - - -
- - - Получение данных, не относящихся к левой и правой таблицам одновременно - (обратное INNER JOIN): - - - -```sql -SELECT поля_таблиц -FROM левая_таблица - FULL OUTER JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ -WHERE левая_таблица.ключ IS NULL - OR правая_таблица.ключ IS NULL + RIGHT JOIN правая_таблица ON правая_таблица.ключ = левая_таблица.ключ +WHERE левая_таблица.ключ IS NULL; ``` - - - +Условие во второй части обязательно: без него совпавшие строки попали бы в результат дважды. -```sql -SELECT поля_таблиц -FROM левая_таблица -LEFT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ -WHERE правая_таблица.ключ IS NULL +## Все виды соединений таблиц -UNION ALL +| Вид соединения | Результат | Строк в примере | +| ----------------- | -------------------------- | --------------: | +| `LEFT JOIN` | Все строки левой таблицы | 4 | +| `INNER JOIN` | Только совпавшие строки | 3 | +| `RIGHT JOIN` | Все строки правой таблицы | 4 | +| `FULL JOIN` | Все строки обеих таблиц | 5 | +| `LEFT ANTI JOIN` | Левая таблица без пары | 1 | +| `RIGHT ANTI JOIN` | Правая таблица без пары | 1 | +| `FULL ANTI JOIN` | Всё, кроме совпавших строк | 2 | -SELECT поля_таблиц -FROM левая_таблица -RIGHT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ -WHERE левая_таблица.ключ IS NULL -``` +Давайте проверим себя. В левой таблице 8 строк. Сколько строк вернёт `LEFT JOIN` с правой таблицей? - +1. **Правильный ответ:** Восемь или больше — зависит от того, сколько пар нашлось — Каждая строка левой таблицы обязательно попадёт в результат, но строка, у которой в правой таблице несколько пар, даст несколько строк. -
+3. Не больше восьми: лишние строки правой таблицы отбрасываются — Отбрасываются только непарные строки правой таблицы. Совпадения не отбрасываются: каждое даёт отдельную строку результата. diff --git a/course/module-3/subquery-with-one-column-one-row/article.md b/course/module-3/subquery-with-one-column-one-row/article.md index ff9760b..b8823b5 100644 --- a/course/module-3/subquery-with-one-column-one-row/article.md +++ b/course/module-3/subquery-with-one-column-one-row/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Подзапрос с одной строкой и с одним столбцом" - description: "Скалярный подзапросы в SQL, примеры и синтаксис" + title: "Подзапрос с одной строкой и с одним столбцом" + description: "Скалярный подзапросы в SQL, примеры и синтаксис" --- # Подзапрос с одной строкой с одним столбцом @@ -17,17 +17,25 @@ meta: Следующий простейший запрос демонстрирует вывод единственного значения (названия компании). В таком виде он не имеет большого смысла, однако ваши запросы могут быть намного сложнее. -```sql-executable-Trip +```sql SELECT (SELECT name FROM company LIMIT 1) AS company_name; ``` +| company_name | +| ------------ | +| Don_avia | + Таким же образом можно использовать скалярные подзапросы для фильтрации строк с помощью `WHERE`, используя операторы сравнения. -```sql-executable-Family +```sql SELECT * FROM FamilyMembers WHERE birthday = (SELECT MAX(birthday) FROM FamilyMembers); ``` +| member_id | status | member_name | birthday | +| --------- | -------- | ---------------- | ------------------------ | +| 8 | daughter | Wednesday Addams | 2005-01-13T00:00:00.000Z | + С помощью данного запроса возможно получить самого младшего члена семьи. Подзапрос в данном случае необходим для получения максимальной даты рождения, которая затем используется в основном запросе для фильтрации строк. @@ -35,19 +43,15 @@ SELECT * FROM FamilyMembers При использовании результата подзапроса с операторами сравнения, как в нашем примере, важно, чтобы подзапрос возвращал именно скалярное значение (1 строка и 1 колонка). - +**MySQL** Если бы данный подзапрос вернул несколько значений, то СУБД бы вернула ошибку, сообщающую, что ожидалось, что подзапрос вернёт лишь 1 запись: «ER_SUBQUERY_NO_1_ROW: Subquery returns more than 1 row». - - - +**PostgreSQL** Если бы данный подзапрос вернул несколько значений, то СУБД бы вернула ошибку, сообщающую, что ожидалось, что подзапрос вернёт лишь 1 запись: «ERROR: more than one row returned by a subquery used as an expression». - - Поэтому стоит быть осторожным при написании подзапросов и представлять, какой результат вернёт подзапрос, и какие операторы мы можем использовать вместе с результирующим набором. diff --git a/course/module-3/subquery-with-one-column-several-row/article.md b/course/module-3/subquery-with-one-column-several-row/article.md index 36bb334..551fd76 100644 --- a/course/module-3/subquery-with-one-column-several-row/article.md +++ b/course/module-3/subquery-with-one-column-several-row/article.md @@ -1,12 +1,12 @@ --- meta: - title: 'Подзапросы с несколькими строками и одним столбцом' - description: 'Подзапросы с использованием операторов ANY, IN, ALL' + title: "Подзапросы с несколькими строками и одним столбцом" + description: "Подзапросы с использованием операторов ANY, IN, ALL" --- # Подзапросы с несколькими строками и одним столбцом -Если подзапрос возвращает более одной строки, его нельзя просто использовать с операторами сравнения, как это можно было делать со скалярными подзапросами. +Если подзапрос возвращает более одной строки, его нельзя просто использовать с операторами сравнения, как это можно было делать со скалярными подзапросами. Однако c подзапросами, возвращающими несколько строк и один столбец, можно использовать 3 дополнительных оператора. @@ -15,7 +15,7 @@ meta: С помощью оператора `ALL` мы можем сравнивать отдельное значение с каждым значением в наборе, полученным подзапросом. При этом данное условие вернёт `TRUE`, только если все сравнения отдельного значения со значениями в наборе вернут `TRUE`. -Например, нижеприведённый синтетический запрос проверяет, для всех ли жилых помещений выполняется условие, что оно дешевле, чем 200. +Например, нижеприведённый синтетический запрос проверяет, для всех ли жилых помещений выполняется условие, что оно дешевле чем 200. ```sql SELECT 200 > ALL(SELECT price FROM Rooms) @@ -24,28 +24,30 @@ SELECT 200 > ALL(SELECT price FROM Rooms) Или же, более практический пример: нам необходимо найти имена всех владельцев жилья, которые сами при этом никогда не снимали жилье. Чтобы получить данный список, мы можем действовать следующим образом: - +ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/subquery-with-one-column-several-row). - Получить список имён всех владельцев жилья - ```sql - SELECT DISTINCT name FROM Users INNER JOIN Rooms - ON Users.id = Rooms.owner_id - ``` + + ```sql + SELECT DISTINCT name FROM Users INNER JOIN Rooms + ON Users.id = Rooms.owner_id + ``` + - Получить список идентификаторов всех пользователей, снимавших жилье - ```sql - SELECT DISTINCT user_id FROM Reservations - ``` + ```sql + SELECT DISTINCT user_id FROM Reservations + ``` - Отфильтровать первый список всех владельцев по условию, что идентификатор владельца жилья не равен ни одному из идентификаторов пользователей, когда-либо снимавших жилье - ```sql - SELECT DISTINCT name FROM Users INNER JOIN Rooms - ON Users.id = Rooms.owner_id - WHERE Users.id <> ALL ( - SELECT DISTINCT user_id FROM Reservations - ) - ``` + ```sql + SELECT DISTINCT name FROM Users INNER JOIN Rooms + ON Users.id = Rooms.owner_id + WHERE Users.id <> ALL ( + SELECT DISTINCT user_id FROM Reservations + ) + ``` ## Подзапрос и оператор IN diff --git a/course/module-3/subquery-with-several-column/article.md b/course/module-3/subquery-with-several-column/article.md index c6b58dd..a648607 100644 --- a/course/module-3/subquery-with-several-column/article.md +++ b/course/module-3/subquery-with-several-column/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Многостолбцовые подзапросы' - description: 'Многостолбцовые подзапросы в SQL, подзапросы с произвольной таблицей и сравнение по нескольким столбцам в SQL.' + title: "Многостолбцовые подзапросы" + description: "Многостолбцовые подзапросы в SQL, подзапросы с произвольной таблицей и сравнение по нескольким столбцам в SQL." --- # Многостолбцовые подзапросы @@ -13,9 +13,10 @@ meta: SQL поддерживает сравнение не только по одной колонке, но позволяет попарно сравнивать значения в основном запросе со значениями в подзапросе. -Например, если мы хотим получить информацию о всех бронированиях, в которых цена жилья на момент брони (`Reservations.price`) соответствует текущей стоимости жилья (`Rooms.price`), то мы это можем сделать следующим образом: +Например, если мы хотим получить информацию о всех бронированиях, в которых цена жилья на момент брони (`Reservations.price`) соответствует текущей стоимости жилья (`Rooms.price`), +то мы это можем сделать следующим образом: - +ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/subquery-with-several-column). ```sql SELECT * FROM Reservations @@ -42,8 +43,8 @@ SELECT * FROM Reservations | 25 | 18 | 19 | 2019-11-01T10:00:00.000Z | 2019-11-16T10:00:00.000Z | 99 | 1485 | | 26 | 21 | 17 | 2019-11-03T09:00:00.000Z | 2019-11-05T09:00:00.000Z | 215 | 430 | | 27 | 31 | 25 | 2020-04-20T09:00:00.000Z | 2020-04-22T09:00:00.000Z | 120 | 240 | -| 28 | 21 | 14 | 2020-02-08T10:00:00Z | 2020-02-12T10:00:00Z | 85 | 340 | -| 29 | 21 | 39 | 2019-12-08T10:00:00Z | 2019-12-09T10:00:00Z | 150 | 150 | +| 28 | 21 | 14 | 2020-02-08T10:00:00.000Z | 2020-02-12T10:00:00.000Z | 85 | 340 | +| 29 | 21 | 39 | 2019-12-08T10:00:00.000Z | 2019-12-09T10:00:00.000Z | 150 | 150 | В данном примере подзапрос возвращает таблицу с идентификаторами жилых помещений и их текущей ценой: diff --git a/course/module-4/operator-delete/article.md b/course/module-4/operator-delete/article.md index 4356335..ce3d647 100644 --- a/course/module-4/operator-delete/article.md +++ b/course/module-4/operator-delete/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Удаление данных, оператор DELETE' - description: 'Удалить записи в sql. SQL операторы delete, truncate и их отличия. Delete запрос c join' + title: "Удаление данных, оператор DELETE" + description: "Удалить записи в sql. SQL операторы delete, truncate и их отличия. Delete запрос c join" --- # Удаление данных, оператор DELETE @@ -27,27 +27,29 @@ DELETE FROM имя_таблицы TRUNCATE TABLE имя_таблицы; ``` - +**MySQL** > Оптимизатор запросов СУБД MySQL автоматически использует оператор `TRUNCATE`, если оператор `DELETE` не содержит условия `WHERE` или конструкции `LIMIT`. - - Однако у оператора `TRUNCATE` есть ряд отличий: -- Не срабатывают триггеры, в частности, триггер удаления -- Удаляет все строки в таблице, не записывая при этом удаление отдельных строк данных в журнал транзакций -- В MySQL сбрасывает счётчик идентификаторов до начального значения -- Чтобы использовать, необходимы права на изменение таблицы +**MySQL** + +- Не срабатывают триггеры, в частности, триггер удаления +- Удаляет все строки в таблице, не записывая при этом удаление отдельных строк данных в журнал транзакций +- Сбрасывает счётчик идентификаторов до начального значения +- Чтобы использовать, необходимы права на изменение таблицы -### PostgreSQL +**PostgreSQL** -- В PostgreSQL счётчик идентификаторов сбрасывается только при использовании опции `RESTART IDENTITY` -- По умолчанию используется `CONTINUE IDENTITY`, поэтому после `TRUNCATE` счётчик не сбрасывается +- Не срабатывают триггеры, в частности, триггер удаления +- Удаляет все строки в таблице, не записывая при этом удаление отдельных строк данных в журнал транзакций +- Может сбрасывать счётчик идентификаторов при использовании опции `RESTART IDENTITY` (по умолчанию используется `CONTINUE IDENTITY`, и счётчик не сбрасывается) +- Чтобы использовать, необходимы права на изменение таблицы ## Удаление записей при многотабличных запросах - +**MySQL** Если в `DELETE` запросе используется `JOIN`, то необходимо указать, из каких именно таблиц требуется удалять записи. @@ -58,9 +60,7 @@ ON имя_таблицы_1.поле = имя_таблицы_2.поле [WHERE условие_отбора_записей]; ``` - - - +**PostgreSQL** Если в `DELETE` запросе используется `USING`, то после него необходимо указать дополнительные таблицы, по которым выбираются удаляемые записи. @@ -71,11 +71,9 @@ WHERE имя_таблицы_1.поле = имя_таблицы_2.поле [AND условие_отбора_записей]; ``` - - Например, нам необходимо удалить все бронирования жилья, в котором отсутствует кухня. Тогда запрос будет выглядеть следующим образом: - +**MySQL** ```sql DELETE Reservations FROM @@ -84,9 +82,7 @@ Reservations.room_id = Rooms.id WHERE Rooms.has_kitchen = false; ``` - - - +**PostgreSQL** ```sql DELETE FROM Reservations @@ -95,11 +91,9 @@ WHERE Reservations.room_id = Rooms.id AND Rooms.has_kitchen = false; ``` - - Если бы, помимо удаления бронирования, нам нужно было также удалить и жилье, то запрос приобрёл бы следующий вид: - +**MySQL** ```sql DELETE Reservations, Rooms FROM @@ -108,9 +102,7 @@ Reservations.room_id = Rooms.id WHERE Rooms.has_kitchen = false; ``` - - - +**PostgreSQL** В PostgreSQL для удаления из нескольких таблиц одновременно используются отдельные DELETE запросы или транзакции: @@ -125,5 +117,3 @@ DELETE FROM Rooms WHERE Rooms.has_kitchen = false; COMMIT; ``` - - diff --git a/course/module-4/operator-insert/article.md b/course/module-4/operator-insert/article.md index d347f4c..b897872 100644 --- a/course/module-4/operator-insert/article.md +++ b/course/module-4/operator-insert/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Добавление данных, оператор insert" - description: "Добавление новой записи в sql. Автоинкремент первичного ключа при создании строчки в таблице. SQL оператор insert into." + title: "INSERT INTO: как добавить данные в таблицу SQL — примеры" + description: "Как добавить запись в таблицу SQL оператором INSERT INTO: синтаксис, вставка нескольких строк сразу, автоинкремент первичного ключа. Примеры с упражнениями для MySQL и PostgreSQL." --- # Добавление данных, оператор INSERT @@ -18,24 +18,123 @@ VALUES (значение_поля_таблицы, ...) Значения можно вставлять перечислением с помощью слова `VALUES`, перечислив их в круглых скобках через запятую или c помощью оператора `SELECT`. +## Перечисление полей и соответствие значениям + +При использовании оператора `INSERT` можно явно указать, в какие поля таблицы будут вставлены данные. Это делается путём перечисления имён полей в круглых скобках после названия таблицы: + +```sql +INSERT INTO имя_таблицы (поле1, поле2, поле3) +VALUES (значение1, значение2, значение3); +``` + +**Важные правила:** + +- Порядок значений в `VALUES` должен строго соответствовать порядку полей в перечислении +- Количество значений должно совпадать с количеством указанных полей +- Если поле не указано в перечислении, оно получит значение по умолчанию (если оно задано) или `NULL` (если поле допускает `NULL`) + +Например, если таблица `Goods` имеет поля `good_id`, `good_name` и `type`, то следующие запросы эквивалентны: + +```sql +-- Явное указание полей +INSERT INTO Goods (good_id, good_name, type) +VALUES (20, 'Table', 2); + +-- Изменённый порядок полей - значения меняются соответственно +INSERT INTO Goods (good_name, type, good_id) +VALUES ('Table', 2, 20); +``` + +Если не указывать список полей, то значения должны быть перечислены для **всех** полей таблицы в том порядке, в котором они были определены при создании таблицы: + +```sql +INSERT INTO Goods +VALUES (20, 'Table', 2); +``` + +> Рекомендуется всегда явно указывать список полей. +> Это делает код более читаемым, защищает от ошибок при изменении структуры таблицы и позволяет вставлять значения только в нужные поля. + +## Различия между синтаксисами INSERT + +Оператор `INSERT` поддерживает два основных синтаксиса для указания данных: + +### INSERT INTO ... VALUES + +Используется для вставки **заранее известных** значений. Может вставлять одну или несколько строк за раз: + +```sql +-- Одна строка +INSERT INTO Goods (good_id, good_name, type) +VALUES (20, 'Table', 2); + +-- Несколько строк +INSERT INTO Goods (good_id, good_name, type) +VALUES + (20, 'Table', 2), + (21, 'Chair', 2), + (22, 'Lamp', 8); +``` + +**Когда использовать:** для вставки конкретных, статических данных, которые известны заранее. + +### INSERT INTO ... SELECT + +Используется для вставки данных, **полученных из запроса**. Позволяет копировать данные из одной таблицы в другую или вставлять результаты сложных вычислений: + +```sql +INSERT INTO Goods (good_id, good_name, type) +SELECT 20, 'Table', 2; + +-- Или копирование из другой таблицы +INSERT INTO Goods (good_id, good_name, type) +SELECT good_id + 100, good_name, type +FROM Goods +WHERE type = 2; +``` + +**Когда использовать:** для копирования данных между таблицами, вставки результатов вычислений или когда данные зависят от существующих записей в базе. + Таким образом, добавить новые записи можно следующими способами: +ER-диаграмма базы данных Family: [открыть на SQL Academy](https://sql-academy.org/ru/guide/operator-insert). + - Используя синтаксис `INSERT INTO ... SELECT` - ```sql-executable-Family-targetTable:Goods - INSERT INTO Goods (good_id, good_name, type) - SELECT 20, 'Table', 2; - ``` + ```sql + INSERT INTO Goods (good_id, good_name, type) + SELECT 20, 'Table', 2; + ``` - Используя синтаксис `INSERT INTO ... VALUES (...)` - ```sql-executable-Family-targetTable:Goods - INSERT INTO Goods (good_id, good_name, type) - VALUES (20, 'Table', 2); - ``` + ```sql + INSERT INTO Goods (good_id, good_name, type) + VALUES (20, 'Table', 2); + ``` Каждый из этих запросов даст одинаковый результат: +| good_id | good_name | type | +| ------- | ------------------ | ---- | +| 1 | apartment fee | 1 | +| 2 | phone fee | 1 | +| 3 | bread | 2 | +| 4 | milk | 2 | +| 5 | red caviar | 3 | +| 6 | cinema | 4 | +| 7 | black caviar | 3 | +| 8 | cough tablets | 5 | +| 9 | potato | 2 | +| 10 | pineapples | 3 | +| 11 | television | 8 | +| 12 | vacuum cleaner | 8 | +| 13 | jacket | 7 | +| 14 | fur coat | 7 | +| 15 | music school fee | 6 | +| 16 | english school fee | 6 | +| 20 | Table | 2 | + ## Первичный ключ при добавлении новой записи Следует помнить, что первичный ключ таблицы является уникальным значением и добавление уже существующего значения приведёт к ошибке. @@ -43,7 +142,7 @@ VALUES (значение_поля_таблицы, ...) При добавлении новой записи с уникальными индексами выбор такого уникального значения может оказаться непростой задачей. Решением может быть дополнительный запрос, направленный на выявление максимального значения первичного ключа для генерации нового уникального значения. -```sql-executable-Family-targetTable:Goods +```sql INSERT INTO Goods SELECT MAX(good_id) + 1, 'Table', 2 FROM Goods; ``` @@ -51,7 +150,7 @@ INSERT INTO Goods SELECT MAX(good_id) + 1, 'Table', 2 FROM Goods; ## Автоматическая генерация первичного ключа - +**MySQL** В MySQL введён механизм автоматической генерации первичного ключа. Для этого достаточно снабдить первичный ключ `good_id` атрибутом `AUTO_INCREMENT`. Тогда при создании новой записи в качестве значения `good_id` достаточно передать `NULL` или `0` — поле автоматически получит значение, большее предыдущего на единицу. @@ -68,9 +167,7 @@ CREATE TABLE Goods ( INSERT INTO Goods VALUES (NULL, 'Table', 2); ``` - - - +**PostgreSQL** В PostgreSQL есть механизм для автоматической генерации уникального идентификатора. Для этого он имеет типы `SMALLSERIAL`, `SERIAL`, `BIGSERIAL`, которые не являются настоящими типами, а скорее просто удобством записи столбцов с уникальным идентификатором. @@ -87,5 +184,3 @@ CREATE TABLE Goods ( ```sql INSERT INTO Goods (good_name, type) VALUES ('Table', 2); ``` - - diff --git a/course/module-4/operator-update/article.md b/course/module-4/operator-update/article.md index 1351f54..c049a66 100644 --- a/course/module-4/operator-update/article.md +++ b/course/module-4/operator-update/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Обновление данных, оператор UPDATE' - description: 'Редактирование (обновление) записей в sql. Изменение данных в реляционных базах данных.' + title: "UPDATE в SQL: как изменить данные в таблице — примеры" + description: "Как обновить данные в таблице SQL оператором UPDATE: синтаксис SET и WHERE, обновление нескольких столбцов одним запросом, типичные ошибки. Примеры с упражнениями." --- # Обновление данных, оператор UPDATE @@ -19,24 +19,24 @@ SET поле_таблицы1 = значение_поля_таблицы1, Так, например, если нужно изменить имя, то запрос будет иметь следующий вид: - +ER-диаграмма базы данных Family: [открыть на SQL Academy](https://sql-academy.org/ru/guide/operator-update). ```sql UPDATE FamilyMembers -SET member_name = "Andie Anthony" -WHERE member_name = "Andie Quincey"; +SET member_name = 'Andie Anthony' +WHERE member_name = 'Andie Quincey'; ``` -| member_id | status | member_name | birthday | -| --------- | ----------- | ----------------- | -------------------- | -| 1 | father | Headley Quincey | 1960-05-13T00:00:00Z | -| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00Z | -| 3 | varchar(50) | Andie Anthony | 1983-06-05T00:00:00Z | -| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00Z | -| 5 | daughter | Annie Quincey | 1988-04-10T00:00:00Z | -| 6 | father | Ernest Forrest | 1961-09-11T00:00:00Z | -| 7 | mother | Constance Forrest | 1968-09-06T00:00:00Z | -| 8 | daughter | Wednesday Addams | 2005-01-13T00:00:00Z | +| member_id | status | member_name | birthday | +| --------- | ----------- | ----------------- | ------------------------ | +| 1 | father | Headley Quincey | 1960-05-13T00:00:00.000Z | +| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00.000Z | +| 3 | varchar(50) | Andie Anthony | 1983-06-05T00:00:00.000Z | +| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00.000Z | +| 5 | daughter | Annie Quincey | 1988-04-10T00:00:00.000Z | +| 6 | father | Ernest Forrest | 1961-09-11T00:00:00.000Z | +| 7 | mother | Constance Forrest | 1968-09-06T00:00:00.000Z | +| 8 | daughter | Wednesday Addams | 2005-01-13T00:00:00.000Z | > Будьте внимательны, когда обновляете данные. Если вы пропустите оператор `WHERE`, то будут обновлены все записи в таблице. diff --git a/course/module-5/creating-transactions/article.md b/course/module-5/creating-transactions/article.md index 0b81374..1f13745 100644 --- a/course/module-5/creating-transactions/article.md +++ b/course/module-5/creating-transactions/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Создание транзакций: MySQL и PostgreSQL" - description: "Изучите, как создавать безопасные транзакции в базах данных MySQL и PostgreSQL для защиты ваших средств и данных. Узнайте о важности команд COMMIT и ROLLBACK для управления изменениями и обеспечения стабильности данных. Откройте для себя применение точек сохранения для гибкого контроля над транзакциями, минимизируя риски и повышая эффективность обработки данных." + title: "Создание транзакций: MySQL и PostgreSQL" + description: "Изучите, как создавать безопасные транзакции в базах данных MySQL и PostgreSQL для защиты ваших средств и данных. Узнайте о важности команд COMMIT и ROLLBACK для управления изменениями и обеспечения стабильности данных. Откройте для себя применение точек сохранения для гибкого контроля над транзакциями, минимизируя риски и повышая эффективность обработки данных." --- # Создание транзакций @@ -43,18 +43,14 @@ ROLLBACK; ## Запуск и завершение транзакций - +**MySQL** Каждая явная транзакция в MySQL начинается с использования оператора `START TRANSACTION` или `BEGIN`. - - - +**PostgreSQL** Каждая явная транзакция в PostgreSQL начинается с использования оператора `BEGIN` или `START TRANSACTION`. - - Завершение же транзакции возможно: - с помощью команды `COMMIT`, которая даёт указание серверу пометить изменения как постоянные и освободить все ресурсы (т.е. блокировки строк), использовавшиеся во время транзакции @@ -82,7 +78,7 @@ SAVEPOINT my_savepoint; `ROLLBACK`, за которой следуют ключевые слова `TO SAVEPOINT` и имя точки сохранения, например: - +**MySQL** ```sql START TRANSACTION; @@ -104,9 +100,7 @@ UPDATE accounts SET balance = balance + 200 WHERE user_id = 2; COMMIT; ``` - - - +**PostgreSQL** ```sql BEGIN; @@ -128,8 +122,6 @@ UPDATE accounts SET balance = balance + 200 WHERE user_id = 2; COMMIT; ``` - - В результате этой транзакции баланс первого пользователя останется без изменений из-за отката к точке сохранения, а баланс второго пользователя увеличится на 200. Это показывает, как можно управлять изменениями в базе данных с высоким уровнем контроля при помощи транзакций и точек сохранения. diff --git a/course/module-5/locking/article.md b/course/module-5/locking/article.md index 797c873..f90c0b0 100644 --- a/course/module-5/locking/article.md +++ b/course/module-5/locking/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Блокировки в СУБД: MySQL и PostgreSQL" - description: "Понимание блокировок в MySQL и PostgreSQL: откройте для себя, как разные типы блокировок помогают управлять одновременным доступом к данным и обеспечивают корректную обработку транзакций. Изучите различные уровни гранулярности блокировок — от таблиц до строк — и их влияние на производительность и согласованность данных в вашей базе данных." + title: "Блокировки в СУБД: MySQL и PostgreSQL" + description: "Понимание блокировок в MySQL и PostgreSQL: откройте для себя, как разные типы блокировок помогают управлять одновременным доступом к данным и обеспечивают корректную обработку транзакций. Изучите различные уровни гранулярности блокировок — от таблиц до строк — и их влияние на производительность и согласованность данных в вашей базе данных." --- # Блокировки в СУБД @@ -40,15 +40,9 @@ meta: Существует ряд различных стратегий, которые могут использоваться, как именно блокировать ресурс. Сервер может применять блокировку на одном из трёх разных уровней, или гранулярностей. -- Блокировка таблиц - Не позволяет нескольким пользователям одновременно изменять данные в одной таблице. -- Блокировка страниц - Не позволяет нескольким пользователям изменять данные в одной и той - же странице (страница — это сегмент памяти, обычно в диапазоне от 2 - до 16 Кбайт) таблицы одновременно. -- Блокировка строк - Не позволяет нескольким пользователям одновременно изменять одну - и ту же строку в таблице. +- **Блокировка таблицы.** Пока идёт изменение, вся таблица недоступна остальным +- **Блокировка страницы.** Ждут только те, кто попал в тот же сегмент памяти — 2–16 Кбайт +- **Блокировка строки.** Ждёт только тот, кто меняет ту же самую строку Эти подходы имеют свои преимущества и недостатки. Блокировка всей таблицы требует небольшого времени, но при увеличении числа пользователей может привести к долгим ожиданиям. @@ -56,17 +50,21 @@ meta: но зато позволяет нескольким пользователям изменять одну и ту же таблицу, если они работают с разными строками. - +**MySQL** MySQL может использовать блокировку таблиц, страниц или строк в зависимости от вашего выбора механизма хранения. По умолчанию в MySQL используется механизм хранения InnoDB, который обеспечивает блокировку строк. - - - +**PostgreSQL** PostgreSQL использует многоверсионное управление конкурентностью (MVCC) и поддерживает блокировку строк по умолчанию. - - Перед тем как перейти к следующей статье о создании транзакций, давайте проверим, как вы поняли этот урок. + +**Для чего нужна блокировка в СУБД ?** + +1. **Правильный ответ:** Блокировка в СУБД нужна для управления одновременным доступом к ресурсам данных. — Основная цель блокировки в базах данных — предотвращение конфликтов доступа и обеспечение целостности данных путем временного блокирования доступа к ним. + +2. Блокировка в СУБД нужна для ускорения работы сервера базы данных — Этот ответ неправильный, потому что блокировка добавляет некоторую задержку в доступе к данным, а не ускоряет его. Она необходима для предотвращения конфликтов и поддержания целостности данных, что иногда может приводить к задержкам в обработке запросов. + +3. Блокировка в СУБД нужна для выполнения множества SQL-инструкций как одной логической операции. — Этот ответ неправильный, потому что блокировка не обязательно связана с выполнением нескольких SQL-инструкций как одной операции. Она скорее обеспечивает согласованный доступ к данным при одновременном их изменении несколькими пользователями. diff --git a/course/module-5/operators-if-case-while-in-stored-procedures/article.md b/course/module-5/operators-if-case-while-in-stored-procedures/article.md index 314b906..c77c769 100644 --- a/course/module-5/operators-if-case-while-in-stored-procedures/article.md +++ b/course/module-5/operators-if-case-while-in-stored-procedures/article.md @@ -1,10 +1,16 @@ --- meta: - title: 'Операторы IF, CASE, WHILE в хранимых процедурах и функциях' - description: 'Изучите операторы ветвления и циклы в хранимых процедурах и функциях SQL. Синтаксис и примеры IF, CASE, WHILE для MySQL и PostgreSQL.' + title: "Операторы IF, CASE, WHILE в хранимых процедурах и функциях" + description: "Изучите операторы ветвления и циклы в хранимых процедурах и функциях SQL. Синтаксис и примеры IF, CASE, WHILE для MySQL и PostgreSQL." --- -# Операторы IF, CASE, WHILE в хранимых процедурах и функциях +**MySQL** + +# Операторы IF, CASE, WHILE в хранимых процедурах + +**PostgreSQL** + +# Операторы IF, CASE, WHILE в хранимых функциях Хранимые процедуры и функции — это не просто удобные контейнеры для группы запросов. Они позволяют реализовать достаточно сложную логику, используя операторы ветвления и циклы. @@ -16,7 +22,7 @@ meta: ### Синтаксис IF - +**MySQL** ```sql IF условие THEN @@ -28,9 +34,7 @@ ELSE END IF; ``` - - - +**PostgreSQL** ```sql IF условие THEN @@ -42,15 +46,13 @@ ELSE END IF; ``` - - ### Пример использования IF - +**MySQL** Создадим процедуру, которая определяет категорию студента по возрасту: -```sql-executable-Schedule +```sql CREATE PROCEDURE categorize_student_by_age( IN student_id INT, OUT category VARCHAR(20) @@ -79,13 +81,11 @@ CALL categorize_student_by_age(1, @category); SELECT @category AS age_category; ``` - - - +**PostgreSQL** Создадим функцию, которая определяет категорию студента по возрасту: -```sql-executable-Schedule +```sql CREATE OR REPLACE FUNCTION categorize_student_by_age(student_id INT) RETURNS VARCHAR(20) LANGUAGE plpgsql @@ -117,7 +117,11 @@ $$; SELECT categorize_student_by_age(1) AS age_category; ``` - +**MySQL** + +| age_category | +| ------------ | +| Молодой | ## Оператор выбора CASE @@ -125,7 +129,7 @@ SELECT categorize_student_by_age(1) AS age_category; ### Синтаксис CASE - +**MySQL** ```sql CASE @@ -135,9 +139,7 @@ CASE END CASE; ``` - - - +**PostgreSQL** ```sql CASE @@ -147,15 +149,13 @@ CASE END CASE; ``` - - ### Пример использования CASE - +**MySQL** Создадим ту же процедуру категоризации студентов, но используя оператор CASE: -```sql-executable-Schedule +```sql CREATE PROCEDURE categorize_student_with_case( IN student_id INT, OUT category VARCHAR(20) @@ -182,13 +182,11 @@ CALL categorize_student_with_case(1, @category); SELECT @category AS age_category; ``` - - - +**PostgreSQL** Создадим ту же функцию категоризации студентов, но используя оператор CASE: -```sql-executable-Schedule +```sql CREATE OR REPLACE FUNCTION categorize_student_with_case(student_id INT) RETURNS VARCHAR(20) LANGUAGE plpgsql @@ -218,7 +216,11 @@ $$; SELECT categorize_student_with_case(1) AS age_category; ``` - +**MySQL** + +| age_category | +| ------------ | +| Молодой | ## Цикл WHILE @@ -226,7 +228,7 @@ SELECT categorize_student_with_case(1) AS age_category; ### Синтаксис WHILE - +**MySQL** ```sql WHILE условие DO @@ -234,9 +236,7 @@ WHILE условие DO END WHILE; ``` - - - +**PostgreSQL** ```sql WHILE условие LOOP @@ -244,15 +244,13 @@ WHILE условие LOOP END LOOP; ``` - - ### Пример использования WHILE Рассмотрим пример хранимой процедуры для создания нескольких тестовых предметов: - +**MySQL** -```sql-executable-Schedule +```sql CREATE PROCEDURE create_test_subjects(IN count_subjects INT) BEGIN DECLARE i INT DEFAULT 1; @@ -277,11 +275,9 @@ CALL create_test_subjects(3); SELECT * FROM Subject WHERE name LIKE 'Test Subject%'; ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql CREATE OR REPLACE PROCEDURE create_test_subjects(count_subjects INT) LANGUAGE plpgsql AS $$ @@ -311,7 +307,10 @@ CALL create_test_subjects(3); SELECT * FROM Subject WHERE name LIKE 'Test Subject%'; ``` - - +| id | name | +| --- | -------------- | +| 21 | Test Subject 1 | +| 22 | Test Subject 2 | +| 23 | Test Subject 3 | Операторы управления потоком делают хранимые процедуры и функции мощным инструментом для реализации сложной бизнес-логики прямо в базе данных! 🚀 diff --git a/course/module-5/partitions/article.md b/course/module-5/partitions/article.md index f7daba1..cef86fb 100644 --- a/course/module-5/partitions/article.md +++ b/course/module-5/partitions/article.md @@ -1,13 +1,13 @@ --- meta: - title: 'Партиции в оконных функциях' - description: 'Партиции в оконных функциях SQL. Использование партиций по нескольким колонкам. Синтаксис партиций.' + title: "Партиции в оконных функциях" + description: "Партиции в оконных функциях SQL. Использование партиций по нескольким колонкам. Синтаксис партиций." --- # Партиции в оконных функциях -В прошлой статье мы кратко уже упоминали, что -такое партиции и как их использовать в оконных функциях, пришло время разобраться в них поподробнее. +В прошлой статье мы кратко уже упоминали, что +такое партиции и как их использовать в оконных функциях, пришло время разобраться в них поподробнее 🤓. ## Понятие партиции @@ -16,14 +16,14 @@ meta: Они служат для сегментации данных, позволяя выполнить более детальный анализ и расчёты вроде агрегации или ранжирования внутри каждой такой группы. -Применяя партиционирование, например, по типу жилья в таблице с данными о стоимости жилья, +Применяя партиционирование, например, по типу жилья в таблице с данными о цене жилья, мы можем рассчитать в отдельной колонке, скажем, среднюю цену для каждого типа жилья. ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/3.png "Схема разбиения на партиции") ## Применение партиций в SQL -Для того, чтобы использовать партицию вместе с оконной функцией, необходимо придерживаться следующего +Для того чтобы использовать партицию вместе с оконной функцией, необходимо придерживаться следующего синтаксиса: ```sql @@ -37,32 +37,138 @@ OVER ( А теперь давайте на простом примере рассмотрим использование партиции вместе с оконной функцией. - +ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/partitions). Для этого рассмотрим таблицу `Rooms`, а именно поля `home_type` и `price`: -```sql-Airbnb-executable +```sql SELECT home_type, price FROM Rooms; ``` +| home_type | price | +| --------------- | ----- | +| Private room | 149 | +| Entire home/apt | 225 | +| Private room | 150 | +| Entire home/apt | 89 | +| Entire home/apt | 80 | +| Entire home/apt | 200 | +| Private room | 60 | +| Private room | 79 | +| Private room | 79 | +| Entire home/apt | 150 | +| Entire home/apt | 135 | +| Private room | 85 | +| Private room | 89 | +| Private room | 85 | +| Entire home/apt | 120 | +| Entire home/apt | 140 | +| Entire home/apt | 215 | +| Private room | 140 | +| Entire home/apt | 99 | +| Entire home/apt | 190 | +| Entire home/apt | 299 | +| Private room | 130 | +| Private room | 80 | +| Private room | 110 | +| Entire home/apt | 120 | +| Private room | 60 | +| Private room | 80 | +| Entire home/apt | 150 | +| Private room | 44 | +| Entire home/apt | 180 | +| Private room | 50 | +| Private room | 52 | +| Private room | 55 | +| Private room | 50 | +| Private room | 70 | +| Private room | 89 | +| Private room | 35 | +| Entire home/apt | 85 | +| Private room | 150 | +| Shared room | 40 | +| Private room | 68 | +| Entire home/apt | 120 | +| Private room | 120 | +| Private room | 135 | +| Entire home/apt | 150 | +| Entire home/apt | 150 | +| Private room | 130 | +| Entire home/apt | 110 | +| Entire home/apt | 115 | +| Private room | 80 | + Мы можем увидеть, что все жильё для аренды разделено на 3 категории: «Private room», «Entire home/apt» и «Shared room». Каждая категория жилья имеет свои ценовые рамки. Чтобы узнать среднюю стоимость в конкретной категории и сравнить её с текущей, как раз можно использовать оконные функции. -Для этого добавим к нашей результирующей таблице ещё одно поле `avg_price`, которое будет высчитывать среднюю стоимость по категориям. Это будет выглядеть следующим образом: +Для этого добавим к нашей результирующей таблице ещё одно поле `avg_price`, которое будет высчитывать среднюю цену по категориям. Это будет выглядеть следующим образом: -```sql-Airbnb-executable +```sql SELECT home_type, price, AVG(price) OVER (PARTITION BY home_type) AS avg_price - FROM Rooms +FROM Rooms ``` +| home_type | price | avg_price | +| --------------- | ----- | --------- | +| Entire home/apt | 225 | 148.6667 | +| Entire home/apt | 180 | 148.6667 | +| Entire home/apt | 150 | 148.6667 | +| Entire home/apt | 85 | 148.6667 | +| Entire home/apt | 120 | 148.6667 | +| Entire home/apt | 120 | 148.6667 | +| Entire home/apt | 299 | 148.6667 | +| Entire home/apt | 190 | 148.6667 | +| Entire home/apt | 99 | 148.6667 | +| Entire home/apt | 215 | 148.6667 | +| Entire home/apt | 140 | 148.6667 | +| Entire home/apt | 120 | 148.6667 | +| Entire home/apt | 150 | 148.6667 | +| Entire home/apt | 135 | 148.6667 | +| Entire home/apt | 150 | 148.6667 | +| Entire home/apt | 110 | 148.6667 | +| Entire home/apt | 115 | 148.6667 | +| Entire home/apt | 200 | 148.6667 | +| Entire home/apt | 150 | 148.6667 | +| Entire home/apt | 80 | 148.6667 | +| Entire home/apt | 89 | 148.6667 | +| Private room | 68 | 89.4286 | +| Private room | 50 | 89.4286 | +| Private room | 70 | 89.4286 | +| Private room | 80 | 89.4286 | +| Private room | 89 | 89.4286 | +| Private room | 149 | 89.4286 | +| Private room | 35 | 89.4286 | +| Private room | 150 | 89.4286 | +| Private room | 130 | 89.4286 | +| Private room | 120 | 89.4286 | +| Private room | 135 | 89.4286 | +| Private room | 130 | 89.4286 | +| Private room | 150 | 89.4286 | +| Private room | 60 | 89.4286 | +| Private room | 79 | 89.4286 | +| Private room | 79 | 89.4286 | +| Private room | 85 | 89.4286 | +| Private room | 89 | 89.4286 | +| Private room | 85 | 89.4286 | +| Private room | 140 | 89.4286 | +| Private room | 55 | 89.4286 | +| Private room | 80 | 89.4286 | +| Private room | 110 | 89.4286 | +| Private room | 60 | 89.4286 | +| Private room | 80 | 89.4286 | +| Private room | 44 | 89.4286 | +| Private room | 50 | 89.4286 | +| Private room | 52 | 89.4286 | +| Shared room | 40 | 40 | + Что именно происходит в добавленной строке? - `PARTITION BY home_type` делит все записи на разные партиции на основе уникальных значений столбца `home_type` -- затем, для каждой записи, `AVG(price)` вычисляет среднюю цену (`price`) в рамках её партиции (`home_type`) +- затем для каждой записи `AVG(price)` вычисляет среднюю цену (`price`) в рамках её партиции (`home_type`) Результатом выполнения этой части запроса будет столбец `avg_price`, в котором для каждой записи будет указано среднее значение цены для её категории жилья (`home_type`). @@ -76,14 +182,67 @@ SELECT Пример запроса с партиционированием по двум столбцам: -```sql-Airbnb-executable +```sql SELECT home_type, has_tv, price, AVG(price) OVER (PARTITION BY home_type, has_tv) AS avg_price FROM Rooms ``` +| home_type | has_tv | price | avg_price | +| --------------- | ------ | ----- | --------- | +| Entire home/apt | 0 | 225 | 170 | +| Entire home/apt | 0 | 180 | 170 | +| Entire home/apt | 0 | 80 | 170 | +| Entire home/apt | 0 | 200 | 170 | +| Entire home/apt | 0 | 150 | 170 | +| Entire home/apt | 0 | 150 | 170 | +| Entire home/apt | 0 | 190 | 170 | +| Entire home/apt | 0 | 215 | 170 | +| Entire home/apt | 0 | 140 | 170 | +| Entire home/apt | 1 | 99 | 132.6667 | +| Entire home/apt | 1 | 85 | 132.6667 | +| Entire home/apt | 1 | 150 | 132.6667 | +| Entire home/apt | 1 | 120 | 132.6667 | +| Entire home/apt | 1 | 120 | 132.6667 | +| Entire home/apt | 1 | 299 | 132.6667 | +| Entire home/apt | 1 | 120 | 132.6667 | +| Entire home/apt | 1 | 135 | 132.6667 | +| Entire home/apt | 1 | 150 | 132.6667 | +| Entire home/apt | 1 | 110 | 132.6667 | +| Entire home/apt | 1 | 89 | 132.6667 | +| Entire home/apt | 1 | 115 | 132.6667 | +| Private room | 0 | 85 | 78.5455 | +| Private room | 0 | 35 | 78.5455 | +| Private room | 0 | 150 | 78.5455 | +| Private room | 0 | 55 | 78.5455 | +| Private room | 0 | 52 | 78.5455 | +| Private room | 0 | 50 | 78.5455 | +| Private room | 0 | 68 | 78.5455 | +| Private room | 0 | 60 | 78.5455 | +| Private room | 0 | 135 | 78.5455 | +| Private room | 0 | 85 | 78.5455 | +| Private room | 0 | 89 | 78.5455 | +| Private room | 1 | 120 | 96.4706 | +| Private room | 1 | 80 | 96.4706 | +| Private room | 1 | 149 | 96.4706 | +| Private room | 1 | 130 | 96.4706 | +| Private room | 1 | 89 | 96.4706 | +| Private room | 1 | 70 | 96.4706 | +| Private room | 1 | 50 | 96.4706 | +| Private room | 1 | 44 | 96.4706 | +| Private room | 1 | 80 | 96.4706 | +| Private room | 1 | 60 | 96.4706 | +| Private room | 1 | 110 | 96.4706 | +| Private room | 1 | 80 | 96.4706 | +| Private room | 1 | 130 | 96.4706 | +| Private room | 1 | 140 | 96.4706 | +| Private room | 1 | 79 | 96.4706 | +| Private room | 1 | 79 | 96.4706 | +| Private room | 1 | 150 | 96.4706 | +| Shared room | 1 | 40 | 40 | + Здесь `PARTITION BY home_type, has_tv` создаёт уникальные партиции для каждой комбинации `home_type` и `has_tv`, -позволяя вычислить среднюю стоимости жилья для текущей категории жилья с наличием или без наличия телевизора. +позволяя вычислить среднюю цену жилья для текущей категории жилья с наличием или без наличия телевизора. ![Партиции по 2 колонками](https://sql-academy.org/static/guidePage/partitions/2-columns-partition.png "Партиции по 2 колонками") diff --git "a/course/module-5/sched\342\200\216uled-events\342\200\216/article.md" b/course/module-5/scheduled-events/article.md similarity index 72% rename from "course/module-5/sched\342\200\216uled-events\342\200\216/article.md" rename to course/module-5/scheduled-events/article.md index 1886099..7b1d978 100644 --- "a/course/module-5/sched\342\200\216uled-events\342\200\216/article.md" +++ b/course/module-5/scheduled-events/article.md @@ -1,41 +1,35 @@ --- meta: - title: 'Планировщик событий в SQL: MySQL EVENT и PostgreSQL pg_cron' - description: 'Полное руководство по созданию автоматических задач в MySQL и PostgreSQL. Научитесь использовать EVENT scheduler и pg_cron для очистки данных, обновления статистики и генерации отчётов по расписанию. Примеры кода и практические советы.' + title: "Планировщик событий в SQL: MySQL EVENT и PostgreSQL pg_cron" + description: "Полное руководство по созданию автоматических задач в MySQL и PostgreSQL. Научитесь использовать EVENT scheduler и pg_cron для очистки данных, обновления статистики и генерации отчётов по расписанию. Примеры кода и практические советы." --- - - # Запланированные события (Events) В реальных приложениях часто возникает необходимость выполнять определённые действия автоматически и по расписанию: очищать старые записи, обновлять статистику, формировать отчёты. Для таких задач SQL предоставляет механизм **запланированных событий**. > **Событие** — это задача, которую база данных запускает сама по расписанию. Вы настраиваете — оно работает автоматически. - +**MySQL** События в MySQL похожи на планировщик задач в операционной системе: вы создаёте задачу один раз, а база данных выполняет её автоматически по расписанию. - - - +**PostgreSQL** В PostgreSQL для автоматического выполнения задач используется расширение **pg_cron**. Это расширение позволяет планировать SQL-команды с использованием синтаксиса cron (как в Unix-системах). - - ## Когда он пригодится Запланированные события помогают автоматизировать следующие задачи: -- **Очистка данных**: удаление устаревших записей логов или временных данных -- **Обновление статистики**: пересчёт агрегированных данных для аналитики -- **Генерация отчётов**: автоматическое формирование периодических отчётов -- **Резервное копирование**: создание копий важных данных +- **Очистка данных**: удаление устаревших записей логов или временных данных +- **Обновление статистики**: пересчёт агрегированных данных для аналитики +- **Генерация отчётов**: автоматическое формирование периодических отчётов +- **Резервное копирование**: создание копий важных данных ## Как включить планировщик - +**MySQL** Прежде чем создавать события, необходимо убедиться, что планировщик событий включён: @@ -49,9 +43,7 @@ SHOW VARIABLES LIKE 'event_scheduler'; SET GLOBAL event_scheduler = ON; ``` - - - +**PostgreSQL** Для использования запланированных задач в PostgreSQL нужно установить расширение pg_cron: @@ -61,15 +53,13 @@ CREATE EXTENSION IF NOT EXISTS pg_cron; > **Важно:** Расширение pg_cron может требовать прав суперпользователя и дополнительной настройки PostgreSQL. В облачных сервисах (AWS RDS, Azure) оно может быть уже предустановлено. - - ## Создание одноразового события Начнём с самого простого — события, которое выполнится один раз в определённое время: - +**MySQL** -```sql-executable +```sql CREATE EVENT cleanup_old_logs ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY DO @@ -80,14 +70,12 @@ DO **Разберём синтаксис:** -- `CREATE EVENT cleanup_old_logs` — создаём событие с именем `cleanup_old_logs` -- `ON SCHEDULE AT` — указываем, когда событие должно выполниться -- `CURRENT_TIMESTAMP + INTERVAL 1 DAY` — время выполнения (через 1 день) -- `DO` — код, который нужно выполнить (любой SQL-оператор) +- `CREATE EVENT cleanup_old_logs` — создаём событие с именем `cleanup_old_logs` +- `ON SCHEDULE AT` — указываем, когда событие должно выполниться +- `CURRENT_TIMESTAMP + INTERVAL 1 DAY` — время выполнения (через 1 день) +- `DO` — код, который нужно выполнить (любой SQL-оператор) - - - +**PostgreSQL** ```sql SELECT cron.schedule( @@ -101,24 +89,22 @@ SELECT cron.schedule( **Разберём синтаксис:** -- `cron.schedule()` — функция для создания запланированной задачи -- `'cleanup_old_logs'` — имя задачи -- `'0 3 * * *'` — расписание в формате cron (минута час день месяц день_недели) -- Последний параметр — SQL-команда для выполнения +- `cron.schedule()` — функция для создания запланированной задачи +- `'cleanup_old_logs'` — имя задачи +- `'0 3 * * *'` — расписание в формате cron (минута час день месяц день_недели) +- Последний параметр — SQL-команда для выполнения **Формат cron расписания:** -![Формат cron расписания](https://sql-academy.org/static/guidePage/scheduled-events/cron_schedule_ru.png 'Формат cron расписания') - - +![Формат cron расписания](https://sql-academy.org/static/guidePage/scheduled-events/cron_schedule_ru.png "Формат cron расписания") ## Создание повторяющегося события Чаще всего события нужно запускать периодически — каждый день, час или минуту: - +**MySQL** -```sql-executable +```sql CREATE EVENT update_statistics ON SCHEDULE EVERY 1 HOUR DO @@ -133,21 +119,19 @@ END; **Разберём синтаксис:** -- `ON SCHEDULE EVERY 1 HOUR` — выполнять каждый час -- `BEGIN ... END` — блок из нескольких SQL-операторов +- `ON SCHEDULE EVERY 1 HOUR` — выполнять каждый час +- `BEGIN ... END` — блок из нескольких SQL-операторов **Варианты интервалов:** -- `EVERY 1 MINUTE` — каждую минуту -- `EVERY 1 HOUR` — каждый час -- `EVERY 1 DAY` — каждый день -- `EVERY 1 WEEK` — каждую неделю -- `EVERY 1 MONTH` — каждый месяц -- `EVERY 30 SECOND` — каждые 30 секунд +- `EVERY 1 MINUTE` — каждую минуту +- `EVERY 1 HOUR` — каждый час +- `EVERY 1 DAY` — каждый день +- `EVERY 1 WEEK` — каждую неделю +- `EVERY 1 MONTH` — каждый месяц +- `EVERY 30 SECOND` — каждые 30 секунд - - - +**PostgreSQL** ```sql SELECT cron.schedule( @@ -165,21 +149,19 @@ SELECT cron.schedule( **Примеры расписаний:** -- `'*/5 * * * *'` — каждые 5 минут -- `'0 * * * *'` — каждый час (в начале часа) -- `'0 0 * * *'` — каждый день в полночь -- `'0 0 * * 0'` — каждое воскресенье в полночь -- `'0 9 1 * *'` — первого числа каждого месяца в 9:00 - - +- `'*/5 * * * *'` — каждые 5 минут +- `'0 * * * *'` — каждый час (в начале часа) +- `'0 0 * * *'` — каждый день в полночь +- `'0 0 * * 0'` — каждое воскресенье в полночь +- `'0 9 1 * *'` — первого числа каждого месяца в 9:00 ## Событие с ограниченным сроком действия Иногда нужно, чтобы событие работало только в определённый период: - +**MySQL** -```sql-executable +```sql CREATE EVENT seasonal_discount ON SCHEDULE EVERY 1 DAY STARTS '2025-12-01 00:00:00' @@ -192,14 +174,12 @@ DO **Новые элементы:** -- `STARTS` — начало периода действия события -- `ENDS` — конец периода действия события +- `STARTS` — начало периода действия события +- `ENDS` — конец периода действия события После указанной даты событие автоматически прекратит выполняться. - - - +**PostgreSQL** В pg_cron нет встроенной поддержки автоматического завершения задач, но можно включить проверку даты в саму команду: @@ -226,11 +206,9 @@ SELECT cron.schedule( ); ``` - - ## Просмотр существующих событий - +**MySQL** Чтобы увидеть все созданные события: @@ -244,9 +222,7 @@ SHOW EVENTS; SHOW EVENTS FROM your_database_name; ``` - - - +**PostgreSQL** Чтобы увидеть все запланированные задачи: @@ -264,11 +240,9 @@ ORDER BY start_time DESC LIMIT 10; ``` - - ## Управление событиями - +**MySQL** **Временное отключение события:** @@ -295,9 +269,7 @@ ON SCHEDULE EVERY 2 HOUR; DROP EVENT IF EXISTS cleanup_old_logs; ``` - - - +**PostgreSQL** **Удаление запланированной задачи:** @@ -327,11 +299,9 @@ SELECT cron.schedule( ); ``` - - ## Важные моменты при работе с событиями - +**MySQL** 1. **Права доступа**: Для создания событий нужна привилегия `EVENT`. @@ -339,9 +309,7 @@ SELECT cron.schedule( 3. **Производительность**: Избегайте создания событий со слишком коротким интервалом (каждую минуту), это может повлиять на производительность. - - - +**PostgreSQL** 1. **Права доступа**: Для использования pg_cron обычно требуются права суперпользователя или специальная настройка. @@ -351,9 +319,14 @@ SELECT cron.schedule( 4. **Логирование**: Все выполнения задач сохраняются в таблице `cron.job_run_details`, что полезно для отладки. - - ## Самопроверка Какой минимальный интервал можно использовать для повторяющихся событий? + +1. События можно запускать каждую секунду — Минимальный практичный интервал для событий — минута. Слишком частое выполнение может негативно влиять на производительность базы данных. + +2. **Правильный ответ:** Минимальный интервал — 1 минута, но лучше использовать интервалы от часа и больше — Хотя технически можно создать событие с интервалом в 1 минуту, для большинства задач рекомендуются более длительные интервалы (часы, дни), чтобы не создавать лишнюю нагрузку на базу данных. + +3. Минимальный интервал — 1 час — Технически можно создавать события с интервалом от 1 минуты, но час — действительно хороший практичный минимум для большинства задач. + Запланированные события — это мощный инструмент для автоматизации рутинных задач в базе данных. Они помогают поддерживать чистоту данных, обновлять статистику и выполнять регламентные операции без участия разработчиков! 🚀 diff --git a/course/module-5/sorting-in-windows-functions/article.md b/course/module-5/sorting-in-windows-functions/article.md index 7e7660b..d626231 100644 --- a/course/module-5/sorting-in-windows-functions/article.md +++ b/course/module-5/sorting-in-windows-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Сортировка внутри окна' - description: 'Сортировка внутри окна — важная особенность оконных функций SQL. Узнайте, как использовать сортировку внутри окна для упорядочивания данных и получения более точных агрегатных вычислений. Пример использования и объяснение особенностей сортировки без указания рамок окна.' + title: "Сортировка внутри окна" + description: "Сортировка внутри окна — важная особенность оконных функций SQL. Узнайте, как использовать сортировку внутри окна для упорядочивания данных и получения более точных агрегатных вычислений. Пример использования и объяснение особенностей сортировки без указания рамок окна." --- # Сортировка внутри окна @@ -25,12 +25,12 @@ meta: Изначально мы имеем следующую выборку о бронированиях: -![Использование оконной функции без сортировки](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/initial-data.png 'Использование оконной функции без сортировки') +![Использование оконной функции без сортировки](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/initial-data.png "Использование оконной функции без сортировки") А как результат мы хотим увидеть изменение затраченных средств по каждому пользователю со временем, то есть таблицу следующего вида: -![Использование оконной функции с сортировкой](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/final-result.png 'Использование оконной функции с сортировкой') +![Использование оконной функции с сортировкой](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/final-result.png "Использование оконной функции с сортировкой") #### Разделение данных на партиции @@ -38,7 +38,7 @@ meta: пользователю, чтоб оконная функция работала для каждого пользователя независимо. Для получения же суммы мы можем использовать оконную функцию `SUM`. -```sql-Airbnb-executable +```sql SELECT user_id, start_date, total AS reservation_price, @@ -48,7 +48,7 @@ SELECT user_id, FROM Reservations; ``` -![Промежуточный результат](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/result-1.png 'Промежуточный результат') +![Промежуточный результат](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/result-1.png "Промежуточный результат") В результате выполненного запроса в колонке `total_expenses` вывелась общая сумма затраченных средств с разбивкой по пользователям. Но это не совсем то, что мы хотим: данные в таблице не упорядочены по дате, и @@ -56,7 +56,7 @@ FROM Reservations; Чтобы получить желаемый результат, нам как раз понадобится добавить в запрос сортировку по дате начала бронирования: -```sql-Airbnb-executable +```sql SELECT user_id, start_date, total AS reservation_price, @@ -67,7 +67,7 @@ SELECT user_id, FROM Reservations; ``` -![Финальные данные](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/final-result.png 'Финальные данные') +![Финальные данные](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/final-result.png "Финальные данные") Теперь мы получили то, что и хотели. Но что изменилось после добавления `ORDER BY start_date`? @@ -93,7 +93,7 @@ OVER ( мы остановимся детально в следующей статье, но сейчас важнее, то для чего он нужен. Он позволяет указать рамки окна относительно текущей строки, которые будут использоваться для вычисления в оконной функции. -Так, можно указать, чтобы при расчёте значений +Так, можно указать, чтобы при подсчёте значений для текущей строки в оконную функцию отправились не все записи в рамках текущей партиции, а только `N` записей до текущей строки и `N` после. @@ -104,6 +104,6 @@ OVER ( То есть значения для колонки `cumulative_total` будут высчитываться следующим образом: -![Объяснение как сработала сортировка](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/explanation.png 'Объяснение как сработала сортировка') +![Объяснение как сработала сортировка](https://sql-academy.org/static/guidePage/sorting-in-windows-functions/explanation.png "Объяснение как сработала сортировка") -Подробнее об окнах и их определении в следующей статье. +Подробнее об рамках окон и их определении в следующей статье. diff --git a/course/module-5/stored-functions/article.md b/course/module-5/stored-functions/article.md index 17bfdfd..0731b4a 100644 --- a/course/module-5/stored-functions/article.md +++ b/course/module-5/stored-functions/article.md @@ -1,10 +1,9 @@ --- meta: - title: 'Хранимые функции в SQL' - description: 'Создание и использование хранимых функций в SQL. Синтаксис, параметры, типы возвращаемых значений и практические примеры.' + title: "Хранимые функции в SQL" + description: "Создание и использование хранимых функций в SQL. Синтаксис, параметры, типы возвращаемых значений и практические примеры." --- - # Хранимые функции в SQL Хранимые функции — это мощный инструмент SQL, который позволяет создавать переиспользуемые блоки кода для выполнения вычислений и преобразования данных. @@ -14,7 +13,7 @@ meta: ## Общая структура хранимой функции - +**MySQL** ```sql CREATE FUNCTION имя_функции(параметр1 ТИП, параметр2 ТИП, ...) @@ -25,9 +24,7 @@ BEGIN END; ``` - - - +**PostgreSQL** ```sql CREATE OR REPLACE FUNCTION имя_функции(параметр1 ТИП, параметр2 ТИП, ...) @@ -45,15 +42,13 @@ $$; `AS $$ ... $$` — **долларовое квотирование**, специальный способ обрамления тела функции. Позволяет избежать экранирования символов внутри функции. - - ## Простой пример функции Создадим функцию для определения, является ли человек совершеннолетним по дате рождения: - +**MySQL** -```sql-executable +```sql CREATE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN BEGIN @@ -61,11 +56,9 @@ BEGIN END; ``` - +**PostgreSQL** - - -```sql-executable +```sql CREATE OR REPLACE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN LANGUAGE plpgsql @@ -76,13 +69,11 @@ END; $$; ``` - - Теперь эту функцию можно использовать в любом запросе: - +**MySQL** -```sql-executable +```sql -- Создаём функцию CREATE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN @@ -96,11 +87,9 @@ SELECT is_adult('2000-03-20') AS adult_status; ``` - +**PostgreSQL** - - -```sql-executable +```sql -- Создаём функцию CREATE OR REPLACE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN @@ -117,16 +106,25 @@ SELECT is_adult('2000-03-20') AS adult_status; ``` - +**MySQL** + +| child_status | adult_status | +| ------------ | ------------ | +| 0 | 1 | + +**PostgreSQL** +| child_status | adult_status | +| ------------ | ------------ | +| false | true | ## Использование функций в запросах к таблицам Хранимые функции особенно полезны при работе с реальными данными. Например, мы можем использовать нашу функцию для фильтрации студентов по возрасту: - +**MySQL** -```sql-executable-Schedule +```sql -- Создаём функцию CREATE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN @@ -145,11 +143,9 @@ WHERE is_adult(birthday) = TRUE LIMIT 5; ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql -- Создаём функцию CREATE OR REPLACE FUNCTION is_adult(birth_date DATE) RETURNS BOOLEAN @@ -171,15 +167,33 @@ WHERE is_adult(birthday) = TRUE LIMIT 5; ``` - +**MySQL** + +| first_name | last_name | birthday | is_adult | +| ---------- | --------- | ------------------------ | -------- | +| Nikolaj | Sokolov | 2000-10-01T00:00:00.000Z | 1 | +| Vyacheslav | Eliseev | 2000-11-21T00:00:00.000Z | 1 | +| Ivan | Efremov | 2000-09-19T00:00:00.000Z | 1 | +| Anatolij | ZHdanov | 2007-07-15T00:00:00.000Z | 1 | +| Georgij | Noskov | 2000-03-03T00:00:00.000Z | 1 | + +**PostgreSQL** + +| first_name | last_name | birthday | is_adult | +| ---------- | --------- | ------------------------ | -------- | +| Nikolaj | Sokolov | 2000-10-01T00:00:00.000Z | true | +| Vyacheslav | Eliseev | 2000-11-21T00:00:00.000Z | true | +| Ivan | Efremov | 2000-09-19T00:00:00.000Z | true | +| Anatolij | ZHdanov | 2007-07-15T00:00:00.000Z | true | +| Georgij | Noskov | 2000-03-03T00:00:00.000Z | true | ## Функции с запросами к базе данных Хранимые функции могут выполнять SQL-запросы внутри себя для получения необходимых данных: - +**MySQL** -```sql-executable-Schedule +```sql CREATE FUNCTION get_student_lessons_count(student_id INT, target_date DATE) RETURNS INT BEGIN @@ -195,11 +209,9 @@ BEGIN END; ``` - - - +**PostgreSQL** -```sql-executable-Schedule +```sql CREATE OR REPLACE FUNCTION get_student_lessons_count(student_id INT, target_date DATE) RETURNS INT LANGUAGE plpgsql @@ -218,26 +230,23 @@ END; $$; ``` - - Эта функция подсчитывает количество уроков у конкретного студента в определённый день: - +**MySQL** ```sql SELECT get_student_lessons_count(1, '2019-09-01') AS lessons_today; ``` - - - +**PostgreSQL** ```sql SELECT get_student_lessons_count(1, '2019-09-01') AS lessons_today; ``` - - +| lessons_today | +| ------------- | +| 3 | ## Разбор примера с переменными @@ -250,12 +259,10 @@ DECLARE lessons_count INT; Эта строка **объявляет переменную** `lessons_count` типа `INT`. Переменная будет хранить результат нашего запроса. - +**PostgreSQL** > **Важно для PostgreSQL:** Все переменные должны быть объявлены в блоке `DECLARE` до начала тела функции (до `BEGIN`). Объявлять переменные внутри тела функции нельзя. - - ```sql SELECT COUNT(*) INTO lessons_count FROM Schedule s @@ -266,9 +273,9 @@ WHERE sic.student = student_id Здесь происходит **сохранение результата запроса в переменную**: -- `SELECT COUNT(*)` — подсчитывает количество записей -- `INTO lessons_count` — сохраняет результат в переменную `lessons_count` -- Остальная часть — обычный SQL-запрос с JOIN и условиями +- `SELECT COUNT(*)` — подсчитывает количество записей +- `INTO lessons_count` — сохраняет результат в переменную `lessons_count` +- Остальная часть — обычный SQL-запрос с JOIN и условиями ```sql RETURN lessons_count; @@ -280,17 +287,15 @@ RETURN lessons_count; ## Управление хранимыми функциями -- **Просмотр существующих функций** +- **Просмотр существующих функций** - + **MySQL** ```sql SHOW FUNCTION STATUS WHERE Db = 'your_database_name'; ``` - - - + **PostgreSQL** ```sql SELECT routine_name, routine_type @@ -298,29 +303,23 @@ RETURN lessons_count; WHERE routine_type = 'FUNCTION' AND routine_schema = 'public'; ``` - +- **Удаление функции** -- **Удаление функции** - - + **MySQL** ```sql DROP FUNCTION IF EXISTS is_adult; ``` - - - + **PostgreSQL** ```sql DROP FUNCTION IF EXISTS is_adult(DATE); ``` - +- **Изменение функции** -- **Изменение функции** - - + **MySQL** Для изменения функции в MySQL нужно сначала удалить старую версию, а затем создать новую: @@ -330,9 +329,7 @@ RETURN lessons_count; CREATE FUNCTION is_adult(birth_date DATE) ... ``` - - - + **PostgreSQL** В PostgreSQL можно использовать `CREATE OR REPLACE FUNCTION`: @@ -342,6 +339,4 @@ RETURN lessons_count; -- новая реализация ``` - - Хранимые функции — это мощный инструмент для создания переиспользуемой бизнес-логики прямо в базе данных. Они помогают централизовать вычисления и обеспечить консистентность данных во всём приложении! 🚀 diff --git a/course/module-5/stored-procedures-and-functions/article.md b/course/module-5/stored-procedures-and-functions/article.md index 1633b39..ba5d08a 100644 --- a/course/module-5/stored-procedures-and-functions/article.md +++ b/course/module-5/stored-procedures-and-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Хранимые процедуры и функции в SQL' - description: 'Введение в хранимые процедуры и функции SQL. Их назначение, основные различия и когда использовать каждый тип.' + title: "Хранимые процедуры и функции в SQL" + description: "Введение в хранимые процедуры и функции SQL. Их назначение, основные различия и когда использовать каждый тип." --- # Хранимые процедуры и функции @@ -12,22 +12,22 @@ meta: > **Хранимые процедуры и функции** — это заранее написанные и сохранённые в базе данных SQL-скрипты, которые можно вызывать по имени. Представьте, что у вас есть сложный запрос для расчёта статистики продаж, который вы используете каждый день. -Вместо того чтобы каждый раз переписывать его, можно создать процедуру или функцию и просто вызывать её! +Вместо того, чтобы каждый раз переписывать его, можно создать процедуру или функцию и просто вызывать её! ## Зачем они нужны? Хранимые процедуры и функции решают несколько важных задач: -- **🚀 Повторное использование кода** — написали один раз, используете везде. Никаких копий одного и того же кода в разных местах. -- **⚡ Производительность** — код выполняется прямо на сервере базы данных, что часто быстрее обычных запросов. -- **🔒 Безопасность** — можно предоставить доступ к процедуре, не давая прямого доступа к таблицам. -- **🛡️ Централизованная логика** — вся бизнес-логика находится в одном месте, в базе данных. +- **🚀 Повторное использование кода** — написали один раз, используете везде. Никаких копий одного и того же кода в разных местах. +- **⚡ Производительность** — код выполняется прямо на сервере базы данных, что часто быстрее обычных запросов. +- **🔒 Безопасность** — можно предоставить доступ к процедуре, не давая прямого доступа к таблицам. +- **🛡️ Централизованная логика** — вся бизнес-логика находится в одном месте, в базе данных. ## Основные различия Хотя процедуры и функции похожи, между ними есть важные различия: - +**MySQL** | Характеристика | Хранимые процедуры | Хранимые функции | | ---------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- | @@ -36,9 +36,7 @@ meta: | **Изменение данных** | Может изменять данные в таблицах | Предназначены только для чтения данных | | **Вызов** | `CALL procedure_name()` | `SELECT function_name()` | - - - +**PostgreSQL** | Характеристика | Хранимые процедуры | Хранимые функции | | ---------------------------- | -------------------------------- | ---------------------------------------------------------- | @@ -47,16 +45,14 @@ meta: | **Изменение данных** | Может изменять данные в таблицах | Может изменять данные в таблицах | | **Вызов** | `CALL procedure_name()` | `SELECT function_name()` | - - ## Когда использовать процедуры? **Хранимые процедуры** лучше всего подходят, когда нужно: -- Выполнить последовательность операций (например, создать заказ, списать товар со склада, отправить уведомление) -- Изменить данные в нескольких таблицах одновременно -- Реализовать сложную бизнес-логику -- Вернуть несколько результирующих наборов +- Выполнить последовательность операций (например, создать заказ, списать товар со склада, отправить уведомление) +- Изменить данные в нескольких таблицах одновременно +- Реализовать сложную бизнес-логику +- Вернуть несколько результирующих наборов ### Пример использования процедуры @@ -78,10 +74,10 @@ CALL create_order(customer_id = 123, product_id = 456, quantity = 2); **Хранимые функции** идеальны, когда нужно: -- Выполнить вычисления и вернуть результат -- Создать переиспользуемую формулу -- Преобразовать данные определённым образом -- Использовать результат в других SQL-запросах +- Выполнить вычисления и вернуть результат +- Создать переиспользуемую формулу +- Преобразовать данные определённым образом +- Использовать результат в других SQL-запросах ### Пример использования функции @@ -102,14 +98,16 @@ FROM Products; Если сомневаетесь, что выбрать, используйте это простое правило: -- **Нужно получить одно значение для использования в запросе?** → Функция -- **Нужно выполнить набор действий или изменить данные?** → Процедура +- **Нужно получить одно значение для использования в запросе?** → Функция +- **Нужно выполнить набор действий или изменить данные?** → Процедура ## Закрепим знания Теперь, когда вы знаете основные различия между процедурами и функциями, попробуйте классифицировать задачи в интерактивной игре: +Интерактивная демонстрация доступна [в уроке на SQL Academy](https://sql-academy.org/ru/guide/stored-procedures-and-functions). + ## Что дальше? -Это была вводная статья, чтобы понять общую концепцию. В следующих материалах мы детально разберём +Это была вводная статья, чтобы понять общую концепцию. В следующих материалах мы детально разберём, как создавать и работать с хранимыми процедурами и функциями. diff --git a/course/module-5/stored-procedures/article.md b/course/module-5/stored-procedures/article.md index adc42be..89a041f 100644 --- a/course/module-5/stored-procedures/article.md +++ b/course/module-5/stored-procedures/article.md @@ -1,28 +1,24 @@ --- meta: - title: 'Хранимые процедуры в SQL' - description: 'Создание и использование хранимых процедур в SQL. Синтаксис, параметры, условная логика, циклы и практические примеры.' + title: "Хранимые процедуры в SQL" + description: "Создание и использование хранимых процедур в SQL. Синтаксис, параметры, условная логика, циклы и практические примеры." --- # Хранимые процедуры в SQL Хранимые процедуры — это программные блоки, которые выполняют определённую последовательность действий в базе данных. - +**MySQL** В отличие от функций, процедуры могут изменять данные, выполнять сложную бизнес-логику и не обязательно возвращают значение. - - - +**PostgreSQL** В отличие от функций, процедуры могут изменять данные, выполнять сложную бизнес-логику, но не могут возвращать значения. - - ## Общая структура хранимой процедуры - +**MySQL** ```sql CREATE PROCEDURE имя_процедуры(параметр1 ТИП, параметр2 ТИП, ...) @@ -31,9 +27,7 @@ BEGIN END; ``` - - - +**PostgreSQL** ```sql CREATE OR REPLACE PROCEDURE имя_процедуры(параметр1 ТИП, параметр2 ТИП, ...) @@ -49,15 +43,13 @@ $$; `AS $$ ... $$` — **долларовое квотирование**, специальный способ обрамления тела процедуры. Позволяет избежать экранирования символов внутри процедуры. - - ## Простой пример процедуры Создадим процедуру для обновления информации о студенте: - +**MySQL** -```sql-executable-Schedule +```sql -- Создаём процедуру CREATE PROCEDURE update_student_info( IN student_id INT, @@ -78,11 +70,9 @@ CALL update_student_info(1, 'Alexander', 'Smirnov'); SELECT * FROM Student WHERE id = 1; ``` - +**PostgreSQL** - - -```sql-executable-Schedule +```sql -- Создаём процедуру CREATE OR REPLACE PROCEDURE update_student_info( student_id INT, @@ -106,24 +96,27 @@ CALL update_student_info(1, 'Alexander', 'Smirnov'); SELECT * FROM Student WHERE id = 1; ``` - +| id | first_name | middle_name | last_name | birthday | address | +| --- | ---------- | ----------- | --------- | ------------------------ | -------------------------- | +| 1 | Alexander | Fedorovich | Smirnov | 2000-10-01T00:00:00.000Z | ul. Pushkina, d. 36, kv. 5 | Эта процедура принимает ID студента и новые данные, затем обновляет соответствующую запись в таблице `Student`. - +**MySQL** + ## Типы параметров процедур В MySQL процедуры поддерживают три типа параметров, которые можно передавать в хранимую процедуру: -- **IN** — входные параметры (по умолчанию) -- **OUT** — выходные параметры для возврата значений -- **INOUT** — параметры, которые могут быть как входными, так и выходными +- **IN** — входные параметры (по умолчанию) +- **OUT** — выходные параметры для возврата значений +- **INOUT** — параметры, которые могут быть как входными, так и выходными ### Входные параметры (IN) Входные параметры передают данные в процедуру. Это самый распространённый тип параметров: -```sql-executable-Schedule +```sql CREATE PROCEDURE add_subject( IN subject_id INT, IN subject_name VARCHAR(100) @@ -141,7 +134,7 @@ CALL add_subject(15, 'Mathematics'); Выходные параметры позволяют процедуре возвращать значения: -```sql-executable-Schedule +```sql CREATE PROCEDURE get_student_info( IN student_id INT, OUT student_name VARCHAR(100), @@ -161,12 +154,15 @@ CALL get_student_info(1, @name, @age); SELECT @name AS student_name, @age AS student_age; ``` +| student_name | student_age | +| --------------- | ----------- | +| Nikolaj Sokolov | 24 | ### Входные и выходные параметры (INOUT) INOUT параметры могут принимать значение и возвращать изменённое значение: -```sql-executable-Schedule +```sql CREATE PROCEDURE calculate_discount( INOUT price DECIMAL(10,2), IN discount_percent INT @@ -181,14 +177,15 @@ CALL calculate_discount(@original_price, 15); SELECT @original_price AS discounted_price; ``` - - +**MySQL** - +| discounted_price | +| ---------------- | +| 850 | ### Пример работы трёх типов параметров -![Примеры работы параметров в хранимой процедуре](https://sql-academy.org/static/guidePage/stored-procedures/params-description.jpg 'Примеры работы параметров в хранимой процедуре') +![Примеры работы параметров в хранимой процедуре](https://sql-academy.org/static/guidePage/stored-procedures/params-description.jpg "Примеры работы параметров в хранимой процедуре") ### Ключевые различия типов параметров @@ -200,21 +197,17 @@ SELECT @original_price AS discounted_price; > **Важно:** OUT и INOUT параметры в MySQL требуют использования переменных сессии (например, `@variable_name`) при вызове процедуры. - - ## Управление хранимыми процедурами -- **Просмотр существующих процедур** +- **Просмотр существующих процедур** - + **MySQL** ```sql SHOW PROCEDURE STATUS WHERE Db = 'your_database_name'; ``` - - - + **PostgreSQL** ```sql SELECT routine_name, routine_type @@ -222,29 +215,23 @@ SELECT @original_price AS discounted_price; WHERE routine_type = 'PROCEDURE' AND routine_schema = 'public'; ``` - - -- **Удаление процедуры** +- **Удаление процедуры** - + **MySQL** ```sql DROP PROCEDURE IF EXISTS add_student; ``` - - - + **PostgreSQL** ```sql DROP PROCEDURE IF EXISTS add_student(VARCHAR, VARCHAR, DATE); ``` - - -- **Изменение процедуры** +- **Изменение процедуры** - + **MySQL** Для изменения процедуры в MySQL нужно сначала удалить старую версию, а затем создать новую: @@ -254,9 +241,7 @@ SELECT @original_price AS discounted_price; CREATE PROCEDURE add_student(...) ... ``` - - - + **PostgreSQL** В PostgreSQL можно использовать `CREATE OR REPLACE PROCEDURE`: @@ -269,6 +254,4 @@ SELECT @original_price AS discounted_price; -- новая реализация ``` - - Хранимые процедуры — это мощный инструмент для реализации сложной бизнес-логики прямо в базе данных. Они обеспечивают централизацию логики, повышают производительность и гарантируют целостность данных! 🚀 diff --git a/course/module-5/transactions/article.md b/course/module-5/transactions/article.md index f268fe1..5ac0233 100644 --- a/course/module-5/transactions/article.md +++ b/course/module-5/transactions/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Транзакции" - description: "Изучите важность транзакций в управлении базами данных и как они обеспечивают надёжность работы приложений. Узнайте, почему транзакции необходимы для поддержания целостности данных и как они помогают предотвращать ошибки при одновременном доступе множества пользователей." + title: "Транзакции: MySQL и PostgreSQL" + description: "Изучите важность транзакций в управлении базами данных MySQL и PostgreSQL и как они обеспечивают надёжность работы приложений. Узнайте, почему транзакции необходимы для поддержания целостности данных и как они помогают предотвращать ошибки при одновременном доступе множества пользователей." --- # Транзакции diff --git a/course/module-5/type-conversion-functions/article.md b/course/module-5/type-conversion-functions/article.md index 4e82f00..ef79448 100644 --- a/course/module-5/type-conversion-functions/article.md +++ b/course/module-5/type-conversion-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Функции преобразования типов, CAST: MySQL и PostgreSQL" - description: "SQL преобразование типов: функция CAST в MySQL и PostgreSQL, CONVERT в MySQL. Типы данных для конвертации, синтаксис и примеры." + title: "Функции преобразования типов, CAST: MySQL и PostgreSQL" + description: "SQL преобразование типов: функция CAST в MySQL и PostgreSQL, CONVERT в MySQL. Типы данных для конвертации, синтаксис и примеры." --- # Функции преобразования типов, CAST @@ -10,39 +10,39 @@ meta: Например, в примере ниже мы сравниваем значения с типами `STRING` и `INT`. Чтобы выполнить это сравнение СУБД автоматически сконвертирует строковое значение в числовое. - +**MySQL** -```sql-executable +```sql SELECT '50' > 49 AS comparison_1, '50' > 51 AS comparison_2; ``` - +| comparison_1 | comparison_2 | +| ------------ | ------------ | +| 1 | 0 | - +**PostgreSQL** -```sql-executable +```sql SELECT '50' > 49 AS comparison_1, '50' > 51 AS comparison_2; ``` - +| comparison_1 | comparison_2 | +| ------------ | ------------ | +| true | false | Но не все преобразования СУБД может сделать автоматически, и тогда необходимо делать явное преобразование типов. - +**MySQL** Для этого в MySQL есть две очень схожие функции `CAST` и `CONVERT`. - - - +**PostgreSQL** Для этого в PostgreSQL есть функция `CAST` и оператор `::`. - - ## Синтаксис - +**MySQL** ```sql CAST(значение AS тип_для_конвертации); @@ -51,13 +51,15 @@ CONVERT(значение, тип_для_конвертации); Например, -```sql-executable +```sql SELECT CAST(12005.6 AS DECIMAL) AS cast_example, CONVERT(12005.4, DECIMAL) AS convert_example; ``` - +| cast_example | convert_example | +| ------------ | --------------- | +| 12006 | 12005 | - +**PostgreSQL** ```sql CAST(значение AS тип_для_конвертации); @@ -66,13 +68,15 @@ CAST(значение AS тип_для_конвертации); Например, -```sql-executable +```sql SELECT CAST(12005.6 AS INTEGER) AS cast_example, 12005.4::INTEGER AS operator_example; ``` - +| cast_example | operator_example | +| ------------ | ---------------- | +| 12006 | 12005 | - +**MySQL** Функция CAST умеет конвертировать переданное значение в любой из следующих типов: @@ -88,9 +92,7 @@ SELECT CAST(12005.6 AS INTEGER) AS cast_example, 12005.4::INTEGER AS operator_ex | `BINARY` | Конвертирует значение в `BINARY`. | | `YEAR` | Конвертирует значение в год. | - - - +**PostgreSQL** Функция CAST умеет конвертировать переданное значение в любой из следующих типов: @@ -106,34 +108,38 @@ SELECT CAST(12005.6 AS INTEGER) AS cast_example, 12005.4::INTEGER AS operator_ex | `BOOLEAN` | Конвертирует значение в логический тип. | | `TEXT` | Конвертирует значение в текстовый тип. | - - ## Невозможность любой конвертации Использование функции `CAST` накладывает требования к формату исходного значения. И сразу же напрашивается вопрос, что произойдёт, если данный формат не будет соответствовать необходимому? Например, если попробовать сконвертировать случайный текст во временной тип данных: - +**MySQL** -```sql-executable +```sql SELECT CAST('SQL Academy' AS DATETIME) AS invalid_cast; ``` -В этом случае MySQL вернёт `NULL` вместо сконвертированного значения. +| invalid_cast | +| ------------ | +| \ | - +В этом случае MySQL вернёт `NULL` вместо сконвертированного значения. - +**PostgreSQL** -```sql-executable +```sql SELECT CAST('SQL Academy' AS TIMESTAMP) AS invalid_cast; ``` В этом случае PostgreSQL вернёт ошибку, так как строка не может быть сконвертирована в дату. - - ## Самопроверка Итак, за что отвечает функция `CAST` в SQL 🧐? + +1. Функция используется, когда необходимо определить тип данных у переданного значения — Функция CAST отвечает за конвертацию значения, а не за определение его типа данных. + +2. **Правильный ответ:** Функция отвечает за конвертацию значения из одного типа данных в другой — Функция действительно отвечает за явное преобразование типов. + +3. Функция необходима для выполнения математических вычислений — Возможно, вам стоит ещё раз перепройти данный урок. Функция CAST отвечает за конвертацию типов, а не за математические вычисления. diff --git a/course/module-5/types-of-windows-functions/article.md b/course/module-5/types-of-windows-functions/article.md index 392e3d1..4bfc78f 100644 --- a/course/module-5/types-of-windows-functions/article.md +++ b/course/module-5/types-of-windows-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Основные оконные функции' - description: 'Основные оконные функции в SQL — агрегатные, ранжирующие и функции смещения. Узнайте, как использовать агрегатные функции, такие как SUM, COUNT, AVG, MAX и MIN, для вычисления итоговых значений. Ранжирующие функции, такие как ROW_NUMBER, RANK и DENSE_RANK, позволяют ранжировать значения в окне. Функции смещения, такие как LAG, LEAD, FIRST_VALUE и LAST_VALUE, позволяют обращаться к данным из предыдущих и следующих строк окна.' + title: "Основные оконные функции" + description: "Основные оконные функции в SQL — агрегатные, ранжирующие и функции смещения. Узнайте, как использовать агрегатные функции, такие как SUM, COUNT, AVG, MAX и MIN, для вычисления итоговых значений. Ранжирующие функции, такие как ROW_NUMBER, RANK и DENSE_RANK, позволяют ранжировать значения в окне. Функции смещения, такие как LAG, LEAD, FIRST_VALUE и LAST_VALUE, позволяют обращаться к данным из предыдущих и следующих строк окна." --- # Основные оконные функции @@ -11,7 +11,7 @@ meta: ## Виды оконных функций -![Категории оконных функций](https://sql-academy.org/static/guidePage/types-of-windows-functions/categories_of_windows_functions.png 'Категории оконных функций') +![Категории оконных функций](https://sql-academy.org/static/guidePage/types-of-windows-functions/categories_of_windows_functions.png "Категории оконных функций") Оконные функции можно разделить на 3 группы: @@ -24,12 +24,12 @@ meta: Агрегатные функции — это функции, которые выполняют на наборе данных арифметические вычисления и возвращают итоговое значение. - `SUM` — подсчитывает общую сумму значений; -- `COUNT` — читает общее количество записей в колонке (значения `NULL` не учитываются); +- `COUNT` — считает общее количество записей в колонке; - `AVG` — рассчитывает среднее арифметическое; - `MAX` — находит наибольшее значение; - `MIN` — определяет наименьшее значение. -```sql-Airbnb-executable +```sql SELECT id, home_type, price, @@ -41,6 +41,60 @@ SELECT id, FROM Rooms; ``` +| id | home_type | price | Sum | Count | Avg | Max | Min | +| --- | --------------- | ----- | ---- | ----- | -------- | --- | --- | +| 2 | Entire home/apt | 225 | 3122 | 21 | 148.6667 | 299 | 80 | +| 30 | Entire home/apt | 180 | 3122 | 21 | 148.6667 | 299 | 80 | +| 28 | Entire home/apt | 150 | 3122 | 21 | 148.6667 | 299 | 80 | +| 38 | Entire home/apt | 85 | 3122 | 21 | 148.6667 | 299 | 80 | +| 25 | Entire home/apt | 120 | 3122 | 21 | 148.6667 | 299 | 80 | +| 42 | Entire home/apt | 120 | 3122 | 21 | 148.6667 | 299 | 80 | +| 21 | Entire home/apt | 299 | 3122 | 21 | 148.6667 | 299 | 80 | +| 20 | Entire home/apt | 190 | 3122 | 21 | 148.6667 | 299 | 80 | +| 19 | Entire home/apt | 99 | 3122 | 21 | 148.6667 | 299 | 80 | +| 17 | Entire home/apt | 215 | 3122 | 21 | 148.6667 | 299 | 80 | +| 16 | Entire home/apt | 140 | 3122 | 21 | 148.6667 | 299 | 80 | +| 15 | Entire home/apt | 120 | 3122 | 21 | 148.6667 | 299 | 80 | +| 46 | Entire home/apt | 150 | 3122 | 21 | 148.6667 | 299 | 80 | +| 11 | Entire home/apt | 135 | 3122 | 21 | 148.6667 | 299 | 80 | +| 10 | Entire home/apt | 150 | 3122 | 21 | 148.6667 | 299 | 80 | +| 48 | Entire home/apt | 110 | 3122 | 21 | 148.6667 | 299 | 80 | +| 49 | Entire home/apt | 115 | 3122 | 21 | 148.6667 | 299 | 80 | +| 6 | Entire home/apt | 200 | 3122 | 21 | 148.6667 | 299 | 80 | +| 45 | Entire home/apt | 150 | 3122 | 21 | 148.6667 | 299 | 80 | +| 5 | Entire home/apt | 80 | 3122 | 21 | 148.6667 | 299 | 80 | +| 4 | Entire home/apt | 89 | 3122 | 21 | 148.6667 | 299 | 80 | +| 41 | Private room | 68 | 2504 | 28 | 89.4286 | 150 | 35 | +| 34 | Private room | 50 | 2504 | 28 | 89.4286 | 150 | 35 | +| 35 | Private room | 70 | 2504 | 28 | 89.4286 | 150 | 35 | +| 50 | Private room | 80 | 2504 | 28 | 89.4286 | 150 | 35 | +| 36 | Private room | 89 | 2504 | 28 | 89.4286 | 150 | 35 | +| 1 | Private room | 149 | 2504 | 28 | 89.4286 | 150 | 35 | +| 37 | Private room | 35 | 2504 | 28 | 89.4286 | 150 | 35 | +| 39 | Private room | 150 | 2504 | 28 | 89.4286 | 150 | 35 | +| 47 | Private room | 130 | 2504 | 28 | 89.4286 | 150 | 35 | +| 43 | Private room | 120 | 2504 | 28 | 89.4286 | 150 | 35 | +| 44 | Private room | 135 | 2504 | 28 | 89.4286 | 150 | 35 | +| 22 | Private room | 130 | 2504 | 28 | 89.4286 | 150 | 35 | +| 3 | Private room | 150 | 2504 | 28 | 89.4286 | 150 | 35 | +| 7 | Private room | 60 | 2504 | 28 | 89.4286 | 150 | 35 | +| 8 | Private room | 79 | 2504 | 28 | 89.4286 | 150 | 35 | +| 9 | Private room | 79 | 2504 | 28 | 89.4286 | 150 | 35 | +| 12 | Private room | 85 | 2504 | 28 | 89.4286 | 150 | 35 | +| 13 | Private room | 89 | 2504 | 28 | 89.4286 | 150 | 35 | +| 14 | Private room | 85 | 2504 | 28 | 89.4286 | 150 | 35 | +| 18 | Private room | 140 | 2504 | 28 | 89.4286 | 150 | 35 | +| 18 | Private room | 140 | 2504 | 28 | 89.4286 | 150 | 35 | +| 33 | Private room | 55 | 2504 | 28 | 89.4286 | 150 | 35 | +| 23 | Private room | 80 | 2504 | 28 | 89.4286 | 150 | 35 | +| 24 | Private room | 110 | 2504 | 28 | 89.4286 | 150 | 35 | +| 26 | Private room | 60 | 2504 | 28 | 89.4286 | 150 | 35 | +| 27 | Private room | 80 | 2504 | 28 | 89.4286 | 150 | 35 | +| 29 | Private room | 44 | 2504 | 28 | 89.4286 | 150 | 35 | +| 31 | Private room | 50 | 2504 | 28 | 89.4286 | 150 | 35 | +| 32 | Private room | 52 | 2504 | 28 | 89.4286 | 150 | 35 | +| 40 | Shared room | 40 | 40 | 1 | 40 | 40 | 40 | + ### Ранжирующие оконные функции Ранжирующие оконные функции — это функции, которые ранжируют значение для каждой строки в окне. @@ -49,14 +103,14 @@ FROM Rooms; - `ROW_NUMBER` — возвращает номер строки, используется для нумерации; - `RANK` — возвращает ранг каждой строки. Вот как это работает: -- Сортировка: во-первых, строки сортируются по одному или нескольким столбцам. Эти столбцы указываются в `ORDER BY` в конструкции `OVER`. -- Присвоение рангов: каждой уникальной строке или группе строк, имеющих одинаковые значения в столбцах сортировки, присваивается ранг. Ранг начинается с 1. -- Одинаковые значения: если у нескольких строк одинаковые значения в столбцах сортировки, они получают одинаковый ранг. Например, если две строки занимают второе место, обе получают ранг 2. -- Пропуск рангов: после группы строк с одинаковым рангом, следующий ранг увеличивается на количество строк в этой группе. Например, если две строки имеют ранг 2, следующая строка получит ранг 4, а не 3. -- Продолжение сортировки: этот процесс продолжается до тех пор, пока не будут присвоены ранги всем строкам в наборе результатов. + - Сортировка: во-первых, строки сортируются по одному или нескольким столбцам. Эти столбцы указываются в `ORDER BY` в конструкции `OVER`. + - Присвоение рангов: каждой уникальной строке или группе строк, имеющих одинаковые значения в столбцах сортировки, присваивается ранг. Ранг начинается с 1. + - Одинаковые значения: если у нескольких строк одинаковые значения в столбцах сортировки, они получают одинаковый ранг. Например, если две строки занимают второе место, обе получают ранг 2. + - Пропуск рангов: после группы строк с одинаковым рангом, следующий ранг увеличивается на количество строк в этой группе. Например, если две строки имеют ранг 2, следующая строка получит ранг 4, а не 3. + - Продолжение сортировки: этот процесс продолжается до тех пор, пока не будут присвоены ранги всем строкам в наборе результатов. - `DENSE_RANK` — возвращает ранг каждой строки. Но в отличие от функции `RANK`, она не пропускает ранги и после группы одинаковых значений ранг увеличивается на единицу, а не на количество строк. Например, если две строки имеют ранг 2, следующая строка получит ранг 3, а не 4. -```sql-Airbnb-executable +```sql SELECT id, home_type, price, @@ -66,21 +120,76 @@ SELECT id, FROM Rooms; ``` +| id | home_type | price | row_number | rank | dense_rank | +| --- | --------------- | ----- | ---------- | ---- | ---------- | +| 5 | Entire home/apt | 80 | 1 | 1 | 1 | +| 38 | Entire home/apt | 85 | 2 | 2 | 2 | +| 4 | Entire home/apt | 89 | 3 | 3 | 3 | +| 19 | Entire home/apt | 99 | 4 | 4 | 4 | +| 48 | Entire home/apt | 110 | 5 | 5 | 5 | +| 49 | Entire home/apt | 115 | 6 | 6 | 6 | +| 25 | Entire home/apt | 120 | 7 | 7 | 7 | +| 15 | Entire home/apt | 120 | 8 | 7 | 7 | +| 42 | Entire home/apt | 120 | 9 | 7 | 7 | +| 11 | Entire home/apt | 135 | 10 | 10 | 8 | +| 16 | Entire home/apt | 140 | 11 | 11 | 9 | +| 28 | Entire home/apt | 150 | 12 | 12 | 10 | +| 10 | Entire home/apt | 150 | 13 | 12 | 10 | +| 45 | Entire home/apt | 150 | 14 | 12 | 10 | +| 46 | Entire home/apt | 150 | 15 | 12 | 10 | +| 30 | Entire home/apt | 180 | 16 | 16 | 11 | +| 20 | Entire home/apt | 190 | 17 | 17 | 12 | +| 6 | Entire home/apt | 200 | 18 | 18 | 13 | +| 17 | Entire home/apt | 215 | 19 | 19 | 14 | +| 2 | Entire home/apt | 225 | 20 | 20 | 15 | +| 21 | Entire home/apt | 299 | 21 | 21 | 16 | +| 37 | Private room | 35 | 1 | 1 | 1 | +| 29 | Private room | 44 | 2 | 2 | 2 | +| 34 | Private room | 50 | 3 | 3 | 3 | +| 31 | Private room | 50 | 4 | 3 | 3 | +| 32 | Private room | 52 | 5 | 5 | 4 | +| 33 | Private room | 55 | 6 | 6 | 5 | +| 26 | Private room | 60 | 7 | 7 | 6 | +| 7 | Private room | 60 | 8 | 7 | 6 | +| 41 | Private room | 68 | 9 | 9 | 7 | +| 35 | Private room | 70 | 10 | 10 | 8 | +| 8 | Private room | 79 | 11 | 11 | 9 | +| 9 | Private room | 79 | 12 | 11 | 9 | +| 27 | Private room | 80 | 13 | 13 | 10 | +| 23 | Private room | 80 | 14 | 13 | 10 | +| 50 | Private room | 80 | 15 | 13 | 10 | +| 12 | Private room | 85 | 16 | 16 | 11 | +| 14 | Private room | 85 | 17 | 16 | 11 | +| 13 | Private room | 89 | 18 | 18 | 12 | +| 36 | Private room | 89 | 19 | 18 | 12 | +| 24 | Private room | 110 | 20 | 20 | 13 | +| 43 | Private room | 120 | 21 | 21 | 14 | +| 22 | Private room | 130 | 22 | 22 | 15 | +| 47 | Private room | 130 | 23 | 22 | 15 | +| 44 | Private room | 135 | 24 | 24 | 16 | +| 18 | Private room | 140 | 25 | 25 | 17 | +| 1 | Private room | 149 | 26 | 26 | 18 | +| 3 | Private room | 150 | 27 | 27 | 19 | +| 39 | Private room | 150 | 28 | 27 | 19 | +| 40 | Shared room | 40 | 1 | 1 | 1 | + ### Оконные функции смещения Оконные функции смещения — это функции, которые позволяют перемещаться и обращаться к разным строкам в окне, относительно текущей строки, а также обращаться к значениям в начале или в конце окна. - `LAG` — обращается к данным из предыдущих строк окна. - Имеет три аргумента: столбец, значение которого необходимо вернуть, количество строк для смещения (по-умолчанию 1), значение, которое необходимо вернуть, если после смещения возвращается значение `NULL`. + Имеет три аргумента: столбец, значение которого необходимо вернуть, количество строк для смещения (по умолчанию 1), значение, которое необходимо вернуть, если после смещения возвращается значение `NULL`. - `LEAD` — обращается к данным из следующих строк. Аналогично `LAG` имеет 3 аргумента. + - `FIRST_VALUE` — возвращает первое значение в окне. В качестве аргумента принимает столбец, значение которого необходимо вернуть. + - `LAST_VALUE` — возвращает последнее значение в окне. В качестве аргумента принимает столбец, значение которого необходимо вернуть > При использовании `ORDER BY` рамки окна по умолчанию устанавливаются от начала партиции до текущей строки (`RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`). Из-за этого `LAST_VALUE` будет возвращать значение текущей строки, а не последней строки всей партиции. Чтобы получить действительно последнее значение партиции, необходимо явно расширить границы окна: `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING`. -```sql-Airbnb-executable +```sql SELECT id, home_type, price, @@ -91,3 +200,56 @@ SELECT id, LAST_VALUE(price) OVER(PARTITION BY home_type ORDER BY price ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS "last_value" FROM Rooms; ``` + +| id | home_type | price | lag | lag_2 | lead | first_value | last_value | +| --- | --------------- | ----- | ---- | ----- | ---- | ----------- | ---------- | +| 5 | Entire home/apt | 80 | null | null | 85 | 80 | 299 | +| 38 | Entire home/apt | 85 | 80 | null | 89 | 80 | 299 | +| 4 | Entire home/apt | 89 | 85 | 80 | 99 | 80 | 299 | +| 19 | Entire home/apt | 99 | 89 | 85 | 110 | 80 | 299 | +| 48 | Entire home/apt | 110 | 99 | 89 | 115 | 80 | 299 | +| 49 | Entire home/apt | 115 | 110 | 99 | 120 | 80 | 299 | +| 25 | Entire home/apt | 120 | 115 | 110 | 120 | 80 | 299 | +| 15 | Entire home/apt | 120 | 120 | 115 | 120 | 80 | 299 | +| 42 | Entire home/apt | 120 | 120 | 120 | 135 | 80 | 299 | +| 11 | Entire home/apt | 135 | 120 | 120 | 140 | 80 | 299 | +| 16 | Entire home/apt | 140 | 135 | 120 | 150 | 80 | 299 | +| 28 | Entire home/apt | 150 | 140 | 135 | 150 | 80 | 299 | +| 10 | Entire home/apt | 150 | 150 | 140 | 150 | 80 | 299 | +| 45 | Entire home/apt | 150 | 150 | 150 | 150 | 80 | 299 | +| 46 | Entire home/apt | 150 | 150 | 150 | 180 | 80 | 299 | +| 30 | Entire home/apt | 180 | 150 | 150 | 190 | 80 | 299 | +| 20 | Entire home/apt | 190 | 180 | 150 | 200 | 80 | 299 | +| 6 | Entire home/apt | 200 | 190 | 180 | 215 | 80 | 299 | +| 17 | Entire home/apt | 215 | 200 | 190 | 225 | 80 | 299 | +| 2 | Entire home/apt | 225 | 215 | 200 | 299 | 80 | 299 | +| 21 | Entire home/apt | 299 | 225 | 215 | null | 80 | 299 | +| 37 | Private room | 35 | null | null | 44 | 35 | 150 | +| 29 | Private room | 44 | 35 | null | 50 | 35 | 150 | +| 34 | Private room | 50 | 44 | 35 | 50 | 35 | 150 | +| 31 | Private room | 50 | 50 | 44 | 52 | 35 | 150 | +| 32 | Private room | 52 | 50 | 50 | 55 | 35 | 150 | +| 33 | Private room | 55 | 52 | 50 | 60 | 35 | 150 | +| 26 | Private room | 60 | 55 | 52 | 60 | 35 | 150 | +| 7 | Private room | 60 | 60 | 55 | 68 | 35 | 150 | +| 41 | Private room | 68 | 60 | 60 | 70 | 35 | 150 | +| 35 | Private room | 70 | 68 | 60 | 79 | 35 | 150 | +| 8 | Private room | 79 | 70 | 68 | 79 | 35 | 150 | +| 9 | Private room | 79 | 79 | 70 | 80 | 35 | 150 | +| 27 | Private room | 80 | 79 | 79 | 80 | 35 | 150 | +| 23 | Private room | 80 | 80 | 79 | 80 | 35 | 150 | +| 50 | Private room | 80 | 80 | 80 | 85 | 35 | 150 | +| 12 | Private room | 85 | 80 | 80 | 85 | 35 | 150 | +| 14 | Private room | 85 | 85 | 80 | 89 | 35 | 150 | +| 13 | Private room | 89 | 85 | 85 | 89 | 35 | 150 | +| 36 | Private room | 89 | 89 | 85 | 110 | 35 | 150 | +| 24 | Private room | 110 | 89 | 89 | 120 | 35 | 150 | +| 43 | Private room | 120 | 110 | 89 | 130 | 35 | 150 | +| 22 | Private room | 130 | 120 | 110 | 130 | 35 | 150 | +| 47 | Private room | 130 | 130 | 120 | 135 | 35 | 150 | +| 44 | Private room | 135 | 130 | 130 | 140 | 35 | 150 | +| 18 | Private room | 140 | 135 | 130 | 149 | 35 | 150 | +| 1 | Private room | 149 | 140 | 135 | 150 | 35 | 150 | +| 3 | Private room | 150 | 149 | 140 | 150 | 35 | 150 | +| 39 | Private room | 150 | 150 | 149 | null | 35 | 150 | +| 40 | Shared room | 40 | null | null | null | 40 | 40 | diff --git a/course/module-5/windows-functions-frames/article.md b/course/module-5/windows-functions-frames/article.md index c13ba2b..b3816b6 100644 --- a/course/module-5/windows-functions-frames/article.md +++ b/course/module-5/windows-functions-frames/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Рамки окон, RANGE и ROWS' - description: 'Рамки окон в SQL — понятие, которое определяет подмножество строк, рассматриваемых в оконных функциях. Узнайте разницу между окном и партицией, а также как определить границы окна с помощью ROWS и RANGE. Понимание различий между ROWS и RANGE в контексте оконных функций SQL.' + title: "Рамки окон, RANGE и ROWS" + description: "Рамки окон в SQL — понятие, которое определяет подмножество строк, рассматриваемых в оконных функциях. Узнайте разницу между окном и партицией, а также как определить границы окна с помощью ROWS и RANGE. Понимание различий между ROWS и RANGE в контексте оконных функций SQL." --- # Рамки окон @@ -20,25 +20,25 @@ meta: где каждое подмножество содержит строки с одинаковыми значениями в одном или нескольких столбцах. Оконные функции применяются отдельно к каждой партиции, как если бы каждая из них была отдельным набором данных. - ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions-frames/partitions_visualisation.png "Схема разбиения на партиции") + ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions-frames/partitions_visualisation.png "Схема разбиения на партиции") - Окно. Определяет, какие конкретные строки в каждой партиции будут использоваться для вычисления оконной функции для каждой строки. Окно может изменяться от строки к строке. - Например, если используется правило `ROWS BETWEEN 1 PRECEDING AND CURRENT ROW`, то - для каждой строки окно будет состоять из неё самой и одной предшествующей строки. - Это как "подпартиция" внутри уже существующей партиции. + Например, если используется правило `ROWS BETWEEN 1 PRECEDING AND CURRENT ROW`, то + для каждой строки окно будет состоять из неё самой и одной предшествующей строки. + Это как "подпартиция" внутри уже существующей партиции. - ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions-frames/windows_visualisation.png "Схема разбиения на партиции") + ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions-frames/windows_visualisation.png "Схема разбиения на партиции") - То есть: + То есть: - - Первое окно у нас состоит только из 1-ой записи, потому что предыдущей записи нет. Одна единственная запись подаётся - в агрегатную функцию `AVG(price)` и результат добавляется в поле `avg_price`. - - Второе окно у нас уже содержит 1 и 2 запись, которые и отправляются в `AVG(price)` и возвращают `(170 + 220) / 2 = 195`. - - Третье окно у нас содержит 2 и 3 запись, результат `(220 + 150) / 2 = 185`. - - и т.д. + - Первое окно у нас состоит только из 1-ой записи, потому что предыдущей записи нет. Одна единственная запись подаётся + в агрегатную функцию `AVG(price)` и результат добавляется в поле `avg_price`. + - Второе окно у нас уже содержит 1 и 2 запись, которые и отправляются в `AVG(price)` и возвращают `(170 + 220) / 2 = 195`. + - Третье окно у нас содержит 2 и 3 запись, результат `(220 + 150) / 2 = 185`. + - и т.д. ### Примечание об окне без ROWS/RANGE @@ -49,7 +49,7 @@ meta: ## Определение границ окон -Используя синтаксис `ROWS` или `RANGE` мы можем определить какое именно окно с данными будет передаваться в оконную функцию +Используя синтаксис `ROWS` или `RANGE`, мы можем определить какое именно окно с данными будет передаваться в оконную функцию для вычисления значения для текущей строки. Синтаксис определения границ окна выглядит как указание диапазона относительно текущей строки. @@ -96,13 +96,13 @@ OVER ( - Основан на физических строках: - При использовании `ROWS`, определение окна основывается на физическом положении строк относительно текущей строки. - Например, `1 PRECEDING` означает одну строку до текущей. + При использовании `ROWS` определение окна основывается на физическом положении строк относительно текущей строки. + Например, `1 PRECEDING` означает одну строку до текущей. - Точная граница: - Определение окна с помощью `ROWS` чётко ограничивает количество строк, которые включаются в окно, - делая его предсказуемым и конкретным. + Определение окна с помощью `ROWS` чётко ограничивает количество строк, которые включаются в окно, + делая его предсказуемым и конкретным. ![Определение границ окна c rows](https://sql-academy.org/static/guidePage/windows-functions-frames/rows_example.png "Определение границ окна c rows") @@ -110,12 +110,24 @@ OVER ( - Основан на значениях: - `RANGE`, в отличие от `ROWS`, определяет границы окна на основе значений столбцов, - упорядоченных в соответствии с `ORDER BY` в оконной функции. + `RANGE`, в отличие от `ROWS`, определяет границы окна на основе значений столбцов, + упорядоченных в соответствии с `ORDER BY` в оконной функции. - Динамичность границ: - Границы, определённые с помощью `RANGE`, могут варьироваться - в зависимости от данных, что делает окно гибким, но потенциально менее предсказуемым. + Границы, определённые с помощью `RANGE`, могут варьироваться + в зависимости от данных, что делает окно гибким, но потенциально менее предсказуемым. ![Определение границ окна c range](https://sql-academy.org/static/guidePage/windows-functions-frames/range_example.png "Определение границ окна c range") + +Давайте проверим, правильно ли вы поняли разницу между `ROWS` и `RANGE`: + +**Какое из следующих утверждений наилучшим образом описывает разницу между использованием `ROWS` и `RANGE` в контексте оконных функций SQL?** + +1. ROWS и RANGE являются взаимозаменяемыми, поскольку оба определяют физические строки в окне — Это неверно, так как ROWS основан на физическом положении строк, в то время как RANGE ориентирован на значения столбцов. + +2. **Правильный ответ:** ROWS определяет границы окна на основе физического положения строк, а RANGE — на основе значений столбцов. — ROWS фокусируется на физическом положении строк, в то время как RANGE использует значения столбцов для определения границ окна. + +3. RANGE использует физическое расположение строк, а ROWS — значения столбцов. — Это неправильно, так как ROWS базируется на физическом положении строк, в отличие от RANGE, который ориентируется на значения столбцов. + +4. И ROWS, и RANGE определяют границы окна исключительно на основе значений столбцов. — Это неверно, потому что только RANGE использует значения столбцов, в то время как ROWS ориентируется на физическое расположение строк. diff --git a/course/module-5/windows-functions/article.md b/course/module-5/windows-functions/article.md index 918bcea..b5fed52 100644 --- a/course/module-5/windows-functions/article.md +++ b/course/module-5/windows-functions/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Оконные функции SQL' - description: 'Оконные функции SQL, синтаксис OVER окна данных, оконной функции, пример использования оконной функции, очередь выполнения оконных функций в SELECT запросе' + title: "Оконные функции SQL: MySQL и PostgreSQL" + description: "Оконные функции SQL в MySQL и PostgreSQL, синтаксис OVER окна данных, оконной функции, пример использования оконной функции, очередь выполнения оконных функций в SELECT запросе" --- # Оконные функции SQL @@ -24,39 +24,39 @@ meta: - всей таблицей - отдельными партициями таблицы, то есть группой строк на основе одного или нескольких полей - или даже конкретным диапазоном строк в пределах таблицы или партиции. - Например, мы может определить окно, которое будет передаваться в оконную функцию, + Например, мы можем определить окно, которое будет передаваться в оконную функцию, как предыдущая + текущая строка таблицы. И тогда для каждой строки значение агрегатной функции будет подсчитываться по-своему, так как данные, которые поступают в функцию, будут динамически меняться от строки к строке. Окно будет как бы «скользить» по таблице. ### Визуализация -Оконные функции всегда принимают на вход окно данных, которое указывает пользователь, и возвращает результат в отдельный столбец. +Оконные функции всегда принимают на вход окно данных, которое указывает пользователь, и возвращают результат в отдельный столбец. -Давайте рассмотрим, как это может выглядеть. Для этого возьмём оконную функцию `AVG` для вычисления среднего значения и вот +Давайте рассмотрим как это может выглядеть. Для этого возьмём оконную функцию `AVG` для вычисления среднего значения и вот такую небольшую таблицу: -![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/1.png "Схема разбиения на партиции") +![Изначальная таблица](https://sql-academy.org/static/guidePage/windows-functions/schema_table.png "Изначальная таблица") А теперь давайте посмотрим, как оконная функция будет работать для разных переданных окон: -- Если в качестве окна указать всю таблицу, то для всех строк окно будет совпадать и на вход функции `AVG` будет +- Если в качестве окна указать всю таблицу, то для всех строк окно будет совпадать, и на вход функции `AVG` будет поступать один и тот же набор данных, и, соответственно, результат будет одинаковый. - ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/2.png "Схема разбиения на партиции") + ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/2.png "Схема разбиения на партиции") - Если в качестве окна указать партицию по полю `home_type`, то на вход функции `AVG` будет поступать набор жилых помещений с одинаковым типом, и, соответственно, в результате в новой колонке будет отображаться средняя стоимость по жилью, чей тип совпадает с типом у текущей строки таблицы. - ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/3.png "Схема разбиения на партиции") + ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/3.png "Схема разбиения на партиции") - В качестве окна можно указать и более специфический набор строк. Например, окно можно определить как "предыдущая + текущая строка" таблицы. Тогда это будет выглядеть следующим образом: - ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/4.png "Схема разбиения на партиции") + ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/4.png "Схема разбиения на партиции") - Стоит отметить, что для первой строки окно будет состоять только из 1-ой записи, так как предыдущей строки нет. + Стоит отметить, что для первой строки окно будет состоять только из 1-ой записи, так как предыдущей строки нет. ## Синтаксис оконной функции @@ -80,7 +80,7 @@ OVER ( - с помощью `PARTITION BY <столбцы_для_разделения>` выборка делится на непересекающиеся подмножества, где каждое подмножество содержит строки с одинаковыми значениями в одном или нескольких столбцах, образуются партиции. - с помощью `ORDER BY <столбцы_для_сортировки>` устанавливается порядок строк внутри окна, особо важную роль играет в оконных функциях ранжирования. -- с помощью `ROWS|RANGE <определение_диапазона_строк>` формируется диапазоны строк. С помощью этого параметра можно указать сколько строк брать до и после +- с помощью `ROWS|RANGE <определение_диапазона_строк>` формируются диапазоны строк. С помощью этого параметра можно указать, сколько строк брать до и после текущей в окно. На каждом из этих параметров мы подробнее остановимся в следующих статьях. @@ -89,11 +89,11 @@ OVER ( Давайте с помощью оконных функций попробуем получить список имён студентов и то, сколько человек у них в классе. - +ER-диаграмма базы данных Schedule: [открыть на SQL Academy](https://sql-academy.org/ru/guide/windows-functions). Для начала давайте получим список студентов и идентификатор класса, в котором они учатся: -```sql-Schedule-executable +```sql SELECT Student.first_name, Student.last_name, @@ -104,10 +104,97 @@ JOIN Student ON Student_in_class.student = Student.id; ``` -А теперь, чтобы вычислить сколько учащихся учится в каждом из классов и вывести эту информацию в новую колонку, +| first_name | last_name | class | +| ---------- | ------------ | ----- | +| Nikolaj | Sokolov | 9 | +| Vyacheslav | Eliseev | 9 | +| Ivan | Efremov | 9 | +| Anatolij | ZHdanov | 9 | +| Georgij | Noskov | 9 | +| Artyom | Sergeev | 9 | +| Arina | Evseeva | 9 | +| Angelina | Voroncova | 9 | +| Ekaterina | Ustinova | 9 | +| Raisa | Lapina | 9 | +| Leonid | Ignatov | 9 | +| Snezhana | Seliverstova | 9 | +| Semyon | Biryukov | 9 | +| Georgij | Baranov | 8 | +| YUliya | Vishnyakova | 8 | +| Valentina | Bolshakova | 8 | +| Leonid | Kryukov | 8 | +| Vladislav | Cvetkov | 8 | +| Snezhana | Morozova | 8 | +| Lyubov | Borisova | 8 | +| Anfisa | Kalashnikova | 8 | +| Anna | Osipova | 8 | +| Kristina | Myasnikova | 8 | +| Kristina | Smirnova | 8 | +| Boris | Simonov | 7 | +| Dmitrij | Trofimov | 7 | +| YAkov | Rozhkov | 7 | +| Fyodor | Drozdov | 7 | +| Gleb | Strelkov | 7 | +| Angelina | Lukina | 7 | +| Nina | Odincova | 7 | +| Valeriya | Novikova | 7 | +| Grigorij | Kapustin | 7 | +| Vitalij | Panfilov | 7 | +| Svyatoslav | Tarasov | 6 | +| Matvej | YAkushev | 6 | +| Ilya | Alekseev | 6 | +| Lyubov | Zaharova | 6 | +| Polina | Sidorova | 6 | +| Elizaveta | Samojlova | 6 | +| YUliya | Avdeeva | 6 | +| Matvej | Bogdanov | 6 | +| Ilya | Filippov | 6 | +| Denis | Mel | 6 | +| Svyatoslav | Muravyov | 6 | +| Anna | Kulagina | 5 | +| ZHanna | Fokina | 5 | +| Valeriya | Lapina | 5 | +| Valentina | Sazonova | 5 | +| Nataliya | Myasnikova | 5 | +| Viktoriya | Makarova | 5 | +| Stanislav | Lazarev | 5 | +| Gennadij | Ovchinnikov | 5 | +| Roman | SHilov | 4 | +| Timur | Subbotin | 4 | +| Danila | Osipov | 4 | +| Arina | Silina | 4 | +| Nadezhda | Zaharova | 4 | +| Larisa | SHCHerbakova | 4 | +| Aleksandra | Belozyorova | 4 | +| Natalya | Davydova | 4 | +| Mariya | Fadeeva | 4 | +| YUrij | Markov | 3 | +| Kirill | SHubin | 3 | +| Grigorij | Kolobov | 3 | +| Semyon | Trofimov | 3 | +| Vasilij | Ustinov | 3 | +| Valentina | SHarova | 3 | +| Larisa | Savina | 3 | +| Galina | Orekhova | 3 | +| Arina | SHarapova | 2 | +| Viktoriya | Sergeeva | 2 | +| Vasilij | Krasilnikov | 2 | +| Timur | Rusakov | 2 | +| Gleb | Nesterov | 2 | +| Denis | Makarov | 2 | +| Elizaveta | SHilova | 2 | +| Vera | Evseeva | 1 | +| Margarita | Kabanova | 1 | +| Angelina | Lazareva | 1 | +| Semyon | Voronov | 1 | +| Innokentij | Nekrasov | 1 | +| Artyom | Nikitin | 1 | +| Egor | Belyakov | 1 | + +А теперь, чтобы вычислить, сколько учащихся учится в каждом из классов и вывести эту информацию в новую колонку, мы можем применить оконную функцию: -```sql-Schedule-executable +```sql SELECT Student.first_name, Student.last_name, @@ -119,7 +206,94 @@ JOIN Student ON Student_in_class.student = Student.id; ``` -### Что делает наша оконная функция ? +| first_name | last_name | class | student_count_in_class | +| ---------- | ------------ | ----- | ---------------------- | +| Egor | Belyakov | 1 | 7 | +| Artyom | Nikitin | 1 | 7 | +| Innokentij | Nekrasov | 1 | 7 | +| Semyon | Voronov | 1 | 7 | +| Angelina | Lazareva | 1 | 7 | +| Margarita | Kabanova | 1 | 7 | +| Vera | Evseeva | 1 | 7 | +| Denis | Makarov | 2 | 7 | +| Arina | SHarapova | 2 | 7 | +| Viktoriya | Sergeeva | 2 | 7 | +| Vasilij | Krasilnikov | 2 | 7 | +| Timur | Rusakov | 2 | 7 | +| Gleb | Nesterov | 2 | 7 | +| Elizaveta | SHilova | 2 | 7 | +| Kirill | SHubin | 3 | 8 | +| YUrij | Markov | 3 | 8 | +| Grigorij | Kolobov | 3 | 8 | +| Semyon | Trofimov | 3 | 8 | +| Valentina | SHarova | 3 | 8 | +| Larisa | Savina | 3 | 8 | +| Galina | Orekhova | 3 | 8 | +| Vasilij | Ustinov | 3 | 8 | +| Timur | Subbotin | 4 | 9 | +| Roman | SHilov | 4 | 9 | +| Danila | Osipov | 4 | 9 | +| Arina | Silina | 4 | 9 | +| Nadezhda | Zaharova | 4 | 9 | +| Larisa | SHCHerbakova | 4 | 9 | +| Aleksandra | Belozyorova | 4 | 9 | +| Natalya | Davydova | 4 | 9 | +| Mariya | Fadeeva | 4 | 9 | +| Gennadij | Ovchinnikov | 5 | 8 | +| Stanislav | Lazarev | 5 | 8 | +| Viktoriya | Makarova | 5 | 8 | +| Nataliya | Myasnikova | 5 | 8 | +| Valentina | Sazonova | 5 | 8 | +| Valeriya | Lapina | 5 | 8 | +| ZHanna | Fokina | 5 | 8 | +| Anna | Kulagina | 5 | 8 | +| Ilya | Filippov | 6 | 11 | +| Svyatoslav | Muravyov | 6 | 11 | +| Denis | Mel | 6 | 11 | +| Matvej | Bogdanov | 6 | 11 | +| YUliya | Avdeeva | 6 | 11 | +| Elizaveta | Samojlova | 6 | 11 | +| Polina | Sidorova | 6 | 11 | +| Lyubov | Zaharova | 6 | 11 | +| Ilya | Alekseev | 6 | 11 | +| Matvej | YAkushev | 6 | 11 | +| Svyatoslav | Tarasov | 6 | 11 | +| Nina | Odincova | 7 | 10 | +| Boris | Simonov | 7 | 10 | +| Dmitrij | Trofimov | 7 | 10 | +| YAkov | Rozhkov | 7 | 10 | +| Fyodor | Drozdov | 7 | 10 | +| Gleb | Strelkov | 7 | 10 | +| Angelina | Lukina | 7 | 10 | +| Valeriya | Novikova | 7 | 10 | +| Grigorij | Kapustin | 7 | 10 | +| Vitalij | Panfilov | 7 | 10 | +| Anna | Osipova | 8 | 11 | +| Georgij | Baranov | 8 | 11 | +| YUliya | Vishnyakova | 8 | 11 | +| Valentina | Bolshakova | 8 | 11 | +| Leonid | Kryukov | 8 | 11 | +| Vladislav | Cvetkov | 8 | 11 | +| Lyubov | Borisova | 8 | 11 | +| Anfisa | Kalashnikova | 8 | 11 | +| Snezhana | Morozova | 8 | 11 | +| Kristina | Myasnikova | 8 | 11 | +| Kristina | Smirnova | 8 | 11 | +| Vyacheslav | Eliseev | 9 | 13 | +| Ivan | Efremov | 9 | 13 | +| Anatolij | ZHdanov | 9 | 13 | +| Georgij | Noskov | 9 | 13 | +| Artyom | Sergeev | 9 | 13 | +| Arina | Evseeva | 9 | 13 | +| Angelina | Voroncova | 9 | 13 | +| Ekaterina | Ustinova | 9 | 13 | +| Raisa | Lapina | 9 | 13 | +| Leonid | Ignatov | 9 | 13 | +| Snezhana | Seliverstova | 9 | 13 | +| Semyon | Biryukov | 9 | 13 | +| Nikolaj | Sokolov | 9 | 13 | + +### Что делает наша оконная функция Выражение `PARTITION BY Student_in_class.class` разделяет все строки таблицы на партиции по полю `class`. Так, для каждой из строк в оконную функцию будут подаваться только те строки таблицы, где поле `class` @@ -130,7 +304,7 @@ JOIN ## Порядок выполнения оконных функций в SELECT -При использовании оконный функций важно понимать, в какой последовательности они будут исполняться. Так, как мы +При использовании оконных функций важно понимать, в какой последовательности они будут исполняться. Так, как мы можем увидеть на схеме ниже, окна отрабатывают предпоследним шагом, уже после фильтрации и группировки, но перед финальной сортировкой результатов выборки. @@ -140,3 +314,13 @@ JOIN В этой статье мы кратко рассмотрели понятие оконных функций, их возможности и практическую пользу. В следующих статьях мы более подробно рассмотрим каждый аспект оконных функций. + +И напоследок давайте проверим, все ли мы поняли: + +**Какое ключевое отличие между оконными функциями и агрегатными функциями с группировкой в SQL?** + +1. Оконные функции и агрегатные функции с группировкой выполняют одни и те же вычисления, но с использованием разного синтаксиса. — Оконные функции и агрегатные функции с группировкой имеют разную функциональность и не могут использоваться взаимозаменяемо. + +2. **Правильный ответ:** Оконные функции вычисляются для каждой строки независимо, возвращая результат в отдельный столбец. Агрегатные функции с группировкой в свою очередь группируют строки и применяются к сформированным группам. — Оконные функции предоставляют расчёты для каждой строки, учитывая набор строк (окно), связанный с текущей строкой, в то время как агрегатные функции с группировкой предоставляют один результат для каждой группы, созданной по критерию группировки. + +3. В оконных функциях используется PARTITION BY, а в агрегатных функциях с группировкой — нет. — Хотя PARTITION BY действительно является особенностью оконных функций, ключевое отличие заключается в том, как функции применяются к данным (по строкам против групп). diff --git a/course/module-5/work-with-datatypes/article.md b/course/module-5/work-with-datatypes/article.md index 75ca9da..75b6d31 100644 --- a/course/module-5/work-with-datatypes/article.md +++ b/course/module-5/work-with-datatypes/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Работа с типами данных' - description: 'Продвинутое изучение работы с типами данных в SQL' + title: "Работа с типами данных" + description: "Продвинутое изучение работы с типами данных в SQL" --- # Работа с типами данных diff --git a/course/module-5/work-with-datetime-data-type/article.md b/course/module-5/work-with-datetime-data-type/article.md index a2ba479..83ee2dc 100644 --- a/course/module-5/work-with-datetime-data-type/article.md +++ b/course/module-5/work-with-datetime-data-type/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Дата и время в SQL: функции YEAR, MONTH, TIMESTAMPDIFF, STR_TO_DATE" - description: "Работа с датой и временем в SQL: функции YEAR, MONTH, DAY, TIMESTAMPDIFF, STR_TO_DATE, EXTRACT. Типы данных DATE, TIME, DATETIME, TIMESTAMP в MySQL и PostgreSQL." + title: "Дата и время в SQL: функции YEAR, MONTH, TIMESTAMPDIFF, STR_TO_DATE" + description: "Работа с датой и временем в SQL: функции YEAR, MONTH, DAY, TIMESTAMPDIFF, STR_TO_DATE, EXTRACT. Типы данных DATE, TIME, DATETIME, TIMESTAMP в MySQL и PostgreSQL." --- # Дата и время в SQL @@ -26,7 +26,7 @@ meta: Для задания даты и времени используются следующие форматы: - +**MySQL** | Тип | Формат по умолчанию | | :---------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -36,9 +36,7 @@ meta: | `TIME` | `hhh:mm:sss` | | `YEAR` | `YYYY` - полный формат
`YY` или `Y` - сокращённый формат, который возвращает год в пределах 2000-2069 для значений 0-69 и год в пределах 1970-1999 для значений 70-99 | -
- - +**PostgreSQL** | Тип | Формат по умолчанию | | :---------- | :-------------------- | @@ -46,16 +44,14 @@ meta: | `TIMESTAMP` | `YYYY-MM-DD hh:mm:ss` | | `TIME` | `hh:mm:ss` | - - Причём, при указании даты допускается использовать любой знак пунктуации в качестве разделительного между частями разделов даты или времени. Также возможно задавать дату вообще без разделительного знака, слитно. Примеры валидного задания временных значений через строковое представление: - +**MySQL** -```sql-executable +```sql SELECT CAST("2022-06-16 16:37:23" AS DATETIME) AS datetime_1, CAST("2014/02/22 16*37*22" AS DATETIME) AS datetime_2, CAST("20220616163723" AS DATETIME) AS datetime_3, @@ -64,11 +60,13 @@ SELECT CAST("2022-06-16 16:37:23" AS DATETIME) AS datetime_1, CAST("89" AS YEAR) AS year ``` - +| datetime_1 | datetime_2 | datetime_3 | date_1 | time_1 | year | +| ------------------------ | ------------------------ | ------------------------ | ------------------------ | --------- | ---- | +| 2022-06-16T16:37:23.000Z | 2014-02-22T16:37:22.000Z | 2022-06-16T16:37:23.000Z | 2021-02-12T00:00:00.000Z | 160:23:13 | 1989 | - +**PostgreSQL** -```sql-executable +```sql SELECT CAST('2022-06-16 16:37:23' AS TIMESTAMP) AS timestamp_1, CAST('2014/02/22 16:37:22' AS TIMESTAMP) AS timestamp_2, CAST('20220616163723' AS TIMESTAMP) AS timestamp_3, @@ -76,123 +74,117 @@ SELECT CAST('2022-06-16 16:37:23' AS TIMESTAMP) AS timestamp_1, CAST('16:23:13' AS TIME) AS time_1 ``` - +| timestamp_1 | timestamp_2 | timestamp_3 | date_1 | time_1 | +| ------------------------ | ------------------------ | ------------------------ | ------------------------ | -------- | +| 2022-06-16T16:37:23.000Z | 2014-02-22T16:37:22.000Z | 2022-06-16T16:37:23.000Z | 2021-02-12T00:00:00.000Z | 16:23:13 | В запросе выше для принудительного преобразования строки в дату и время была использована функция `CAST`. Она необходима, если сервер не ожидает временного значения и, соответственно, автоматически не преобразует строку -к нужному типу. С преобразованием типов мы более подробно познакомимся в статье «Функции преобразования типов, CAST». +к нужному типу. С преобразованием типов мы более подробно познакомимся в статье «Функции преобразования типов, CAST». ### Функции генерации дат Если необходимо получить временные данные из строки, которая не соответствует ни одному формату, который принимает функция `CAST`, то можно использовать специальные функции для парсинга дат. - +**MySQL** В MySQL есть встроенная функция `STR_TO_DATE`, которая принимает произвольную строку, содержащую дату, и формат, описывающий её. -```sql-executable +```sql SELECT STR_TO_DATE('November 13, 1998', '%M %d, %Y') AS date; ``` -Более подробное описание функции `STR_TO_DATE` и её аргументов можно посмотреть в справочнике. +| date | +| ------------------------ | +| 1998-11-13T00:00:00.000Z | - +Более подробное описание функции `STR_TO_DATE` и её аргументов можно посмотреть в справочнике. - +**PostgreSQL** В PostgreSQL есть встроенная функция `TO_DATE`, которая принимает произвольную строку, содержащую дату, и формат, описывающий её. -```sql-executable +```sql SELECT TO_DATE('November 13, 1998', 'Month DD, YYYY') AS date; ``` -Более подробное описание функции `TO_DATE` и её аргументов можно посмотреть в справочнике. +| date | +| ------------------------ | +| 1998-11-13T00:00:00.000Z | - +Более подробное описание функции `TO_DATE` и её аргументов можно посмотреть в справочнике. Для генерации же текущей даты или времени нет необходимости создавать строку для последующего её преобразования в дату, потому что есть встроенные функции для получения данных значений. - +**MySQL** В MySQL это функции `CURDATE`, `CURTIME` и `NOW`. -```sql-executable +```sql SELECT CURDATE(), CURTIME(), NOW(); ``` - - - +**PostgreSQL** В PostgreSQL это функции `CURRENT_DATE`, `CURRENT_TIME` и `NOW`. -```sql-executable +```sql SELECT CURRENT_DATE, CURRENT_TIME, NOW(); ``` - - ## Функции извлечения временных данных Иногда необходимо получить не всю дату, а только её конкретную часть, например, месяц или год. - +**MySQL** Для этого в SQL есть следующие функции: -| Функция | Описание | -| :------------------------------------------------------------ | :--------------------------------------------------------- | -| `YEAR` | Возвращает год для указанной даты | -| `MONTH` | Возвращает числовое значение месяца года (от 1 до 12) даты | -| `DAY` | Возвращает порядковый номер дня в месяце (от 1 до 31) | -| `HOUR` | Возвращает значение часа (от 0 до 23) для времени | -| `MINUTE` | Возвращает значение минут (от 0 до 59) для времени | - - +| Функция | Описание | +| :-------------------------------------------------------------------------------------- | :--------------------------------------------------------- | +| `YEAR` | Возвращает год для указанной даты | +| `MONTH` | Возвращает числовое значение месяца года (от 1 до 12) даты | +| `DAY` | Возвращает порядковый номер дня в месяце (от 1 до 31) | +| `HOUR` | Возвращает значение часа (от 0 до 23) для времени | +| `MINUTE` | Возвращает значение минут (от 0 до 59) для времени | - +**PostgreSQL** Для этого в PostgreSQL используется функция `EXTRACT`: -| Функция | Описание | -| :------------------------------------------------------------------------------------- | :--------------------------------------------------------- | -| `EXTRACT(YEAR FROM date)` | Возвращает год для указанной даты | -| `EXTRACT(MONTH FROM date)` | Возвращает числовое значение месяца года (от 1 до 12) даты | -| `EXTRACT(DAY FROM date)` | Возвращает порядковый номер дня в месяце (от 1 до 31) | -| `EXTRACT(HOUR FROM time)` | Возвращает значение часа (от 0 до 23) для времени | -| `EXTRACT(MINUTE FROM time)` | Возвращает значение минут (от 0 до 59) для времени | +| Функция | Описание | +| :--------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------- | +| `EXTRACT(YEAR FROM date)` | Возвращает год для указанной даты | +| `EXTRACT(MONTH FROM date)` | Возвращает числовое значение месяца года (от 1 до 12) даты | +| `EXTRACT(DAY FROM date)` | Возвращает порядковый номер дня в месяце (от 1 до 31) | +| `EXTRACT(HOUR FROM time)` | Возвращает значение часа (от 0 до 23) для времени | +| `EXTRACT(MINUTE FROM time)` | Возвращает значение минут (от 0 до 59) для времени | - +**MySQL** - +## Отличие DATETIME от TIMESTAMP -## MySQL: отличие DATETIME от TIMESTAMP - -В MySQL есть очень похожие друг на друга типы данных: `DATETIME` и `TIMESTAMP`. Они оба направлены на хранение даты и времени, но имеют ряд отличий, определяющих их целевое использование. +Есть очень похожие друг на друга типы данных: `DATETIME` и `TIMESTAMP`. Они оба направлены на хранение даты и времени, но имеют ряд отличий, определяющих их целевое использование. | Критерий | `DATETIME` | `TIMESTAMP` | | :----------- | :------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------- | | Диапазон | от `1000-01-01 00:00:00`
до `9999-12-31 23:59:59` | от `1970-01-01 00:00:00`
до `2038-01-19 03:14:07` | | Часовой пояс | Не учитывается
Отображается в таком виде, в котором дата была установлена | Учитывается
При выборках отображается с учётом текущего часового пояса сервера БД | -
- - +**PostgreSQL** -## PostgreSQL: отличие TIMESTAMP и TIMESTAMPTZ +## Отличие TIMESTAMP и TIMESTAMPTZ -В PostgreSQL основными типами для хранения даты и времени являются `TIMESTAMP` (без часового пояса) и `TIMESTAMPTZ` (с часовым поясом). +Основными типами для хранения даты и времени являются `TIMESTAMP` (без часового пояса) и `TIMESTAMPTZ` (с часовым поясом). | Критерий | `TIMESTAMP` | `TIMESTAMPTZ` | | :----------- | :------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------- | | Диапазон | от `4713 BC` до `294276 AD` | от `4713 BC` до `294276 AD` | | Часовой пояс | Не учитывается
Отображается в таком виде, в котором дата была установлена | Учитывается
При выборках отображается с учётом текущего часового пояса сервера БД | -
- ## Часовые пояса Так как люди во всем мире хотят, чтобы полдень примерно соответствовал максимальному подъёму Солнца, то никогда не было задачи @@ -207,7 +199,7 @@ SELECT CURRENT_DATE, CURRENT_TIME, NOW(); - для текущего пользователя - для текущей пользовательской сессии - +**MySQL** ```sql SET GLOBAL time_zone = '+03:00'; // глобально @@ -217,9 +209,7 @@ SET @@session.time_zone = '+03:00'; // для текущей пользоват Соответственно, при изменении временной зоны все значения с типом `TIMESTAMP` будут выводиться с учётом текущей активной временной зоны. - - - +**PostgreSQL** ```sql ALTER DATABASE mydb SET timezone = 'Europe/Moscow'; // глобально для базы данных @@ -230,8 +220,6 @@ SET TIME ZONE '+03:00'; // для текущей с Соответственно, при изменении временной зоны все значения с типом `TIMESTAMPTZ` будут выводиться с учётом текущей активной временной зоны. - - ## Примеры задач на дату и время Хочется отдельно остановиться на наиболее популярных задачах, связанных с временным типом данных, @@ -242,22 +230,18 @@ SET TIME ZONE '+03:00'; // для текущей с При постановке задачи найти возраст человека по дате его рождения часто возникает соблазн 😈 вычислить разницу текущего года и года рождения человека: - +**MySQL** -```sql-executable +```sql SELECT YEAR(NOW()) - YEAR('2003-07-03 14:10:26'); ``` - - - +**PostgreSQL** -```sql-executable +```sql SELECT EXTRACT(YEAR FROM NOW()) - EXTRACT(YEAR FROM TIMESTAMP '2003-07-03 14:10:26'); ``` - - Проблема такого подхода в том, что он не учитывает, был ли день рождения у данного человека в этом году или ещё нет. То есть, если на момент запроса уже наступило 3-е июля (07-03), то человек отпраздновал свой день рождения и ему уже 20 лет, иначе ему по-прежнему 19 лет. @@ -266,46 +250,38 @@ SELECT EXTRACT(YEAR FROM NOW()) - EXTRACT(YEAR FROM TIMESTAMP '2003-07-03 14:10: Если определить возраст через разницу годов — неработающий вариант, то может возникнуть желание найти возраст через разницу дней между двумя датами, затем поделить эту разницу на количество дней в году и округлить вниз: - +**MySQL** -```sql-executable +```sql SELECT FLOOR(DATEDIFF(NOW(), '2003-07-03 14:10:26') / 365); ``` - +**PostgreSQL** - - -```sql-executable +```sql SELECT FLOOR(EXTRACT(DAY FROM NOW() - TIMESTAMP '2003-07-03 14:10:26') / 365); ``` - - И это решение будет гораздо точнее предыдущего. Но оно не будет абсолютно точным из-за наличия високосных годов, когда в году 366 дней. Хотя погрешность в вычислении возраста для 1 человека из-за наличия високосного года достаточно низкая, в вычислениях на определение, скажем, среднего возраста среди определённого списка людей, погрешность может накапливаться и исказить реальные значения. И как же тогда корректно определять возраст? - +**MySQL** -Для этого есть готовая встроенная функция — `TIMESTAMPDIFF`, +Для этого есть готовая встроенная функция — `TIMESTAMPDIFF`, которая первым аргументом принимает единицу измерения, в которой нужно вернуть разницу между двумя временными значениями. -```sql-executable +```sql SELECT TIMESTAMPDIFF(YEAR, '2003-07-03 14:10:26', NOW()); ``` - +**PostgreSQL** - - -Для этого используется функция `EXTRACT` совместно с функцией `AGE`, +Для этого используется функция `EXTRACT` совместно с функцией `AGE`, которая вычисляет точный интервал между двумя датами. -```sql-executable +```sql SELECT EXTRACT(YEAR FROM AGE(NOW(), TIMESTAMP '2003-07-03 14:10:26')); ``` - - diff --git a/course/module-5/work-with-number-data-type/article.md b/course/module-5/work-with-number-data-type/article.md index 3c6b8cb..f644b99 100644 --- a/course/module-5/work-with-number-data-type/article.md +++ b/course/module-5/work-with-number-data-type/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Числовой тип данных в SQL: математические функции, округление, ROUND, TRUNCATE" - description: "Работа с числами в SQL: математические функции ROUND, TRUNCATE, CEILING, FLOOR, ABS, SIGN. Округление чисел, управление точностью в MySQL и PostgreSQL." + title: "Числовой тип данных в SQL: математические функции, округление, ROUND, TRUNCATE" + description: "Работа с числами в SQL: математические функции ROUND, TRUNCATE, CEILING, FLOOR, ABS, SIGN. Округление чисел, управление точностью в MySQL и PostgreSQL." --- # Числовой тип данных в SQL @@ -11,145 +11,175 @@ meta: При вычислениях можно использовать все стандартные арифметические операции (`+`, `-`, `*`, `/` и прочие) и изменять приоритеты вычислений с помощью скобок. -```sql-executable +```sql SELECT 2 * ((22 - 16) / (2 + 1)) AS calc_example; ``` +| calc_example | +| ------------ | +| 4 | + ## Математические функции Для большинства математических вычислений, таких как получение степени числа или получение квадратного корня, в SQL есть встроенные числовые функции. Вот некоторые примеры данных функций: - - -| Имя функции | Описание | -| :------------------------------------------------------------------ | ------------------------------------------------ | -| `POW(num, power)` | Вычисляет число в указанной степени | -| `SQRT(num)` | Вычисляет квадратный корень числа | -| `LOG(base, num)` | Вычисляет логарифм числа по указанному основанию | -| `EXP(num)` | Вычисляет enum | -| `SIN(num)` | Вычисляет синус числа | -| `COS(num)` | Вычисляет косинус числа | -| `TAN(num)` | Вычисляет тангенс числа | +**MySQL** -Список всех числовых функций, их описание и примеры можно посмотреть в справочнике. +| Имя функции | Описание | +| :-------------------------------------------------------------------------------------------- | ------------------------------------------------ | +| `POW(num, power)` | Вычисляет число в указанной степени | +| `SQRT(num)` | Вычисляет квадратный корень числа | +| `LOG(base, num)` | Вычисляет логарифм числа по указанному основанию | +| `EXP(num)` | Вычисляет enum | +| `SIN(num)` | Вычисляет синус числа | +| `COS(num)` | Вычисляет косинус числа | +| `TAN(num)` | Вычисляет тангенс числа | - +Список всех числовых функций, их описание и примеры можно посмотреть в справочнике. - +**PostgreSQL** -| Имя функции | Описание | -| :--------------------------------------------------------------------------- | ------------------------------------------------ | -| `POWER(num, power)` | Вычисляет число в указанной степени | -| `SQRT(num)` | Вычисляет квадратный корень числа | -| `LOG(base, num)` | Вычисляет логарифм числа по указанному основанию | -| `EXP(num)` | Вычисляет enum | -| `SIN(num)` | Вычисляет синус числа | -| `COS(num)` | Вычисляет косинус числа | -| `TAN(num)` | Вычисляет тангенс числа | +| Имя функции | Описание | +| :----------------------------------------------------------------------------------------------------- | ------------------------------------------------ | +| `POWER(num, power)` | Вычисляет число в указанной степени | +| `SQRT(num)` | Вычисляет квадратный корень числа | +| `LOG(base, num)` | Вычисляет логарифм числа по указанному основанию | +| `EXP(num)` | Вычисляет enum | +| `SIN(num)` | Вычисляет синус числа | +| `COS(num)` | Вычисляет косинус числа | +| `TAN(num)` | Вычисляет тангенс числа | -Список всех числовых функций, их описание и примеры можно посмотреть в справочнике. - - +Список всех числовых функций, их описание и примеры можно посмотреть в справочнике. ## Округление чисел При работе с числами с плавающей точкой не всегда требуется сохранение или отображение чисел с полной точностью. Так, денежные транзакции можно хранить с точностью до 6 знаков после запятой, а отображать до 2, с точностью до копеек. - +**MySQL** Для округления числовых данных в SQL предусмотрены следующие 4 функции: `CEILING`, `FLOOR`, `ROUND`, `TRUNCATE`. Функции `CEILING`, `FLOOR` направлены на то, чтобы округлять число к ближайшему целому числу в большую и в меньшую сторону соответственно. -```sql-executable +```sql SELECT CEILING(69.69) AS ceiling, FLOOR(69.69) AS floor; ``` - - - +**PostgreSQL** -Для округления числовых данных в SQL предусмотрены следующие 4 функции: `CEILING`, `FLOOR`, `ROUND`, +Для округления числовых данных в SQL предусмотрены следующие 4 функции: `CEIL`, `FLOOR`, `ROUND`, `TRUNC`. -Функции `CEILING`, `FLOOR` направлены на то, чтобы округлять число к ближайшему целому числу в большую и в меньшую сторону соответственно. +Функции `CEIL`, `FLOOR` направлены на то, чтобы округлять число к ближайшему целому числу в большую и в меньшую сторону соответственно. -```sql-executable +```sql SELECT CEIL(69.69) AS ceiling, FLOOR(69.69) AS floor; ``` - +| ceiling | floor | +| ------- | ----- | +| 70 | 69 | Для округления к ближайшему целому числу есть функция `ROUND`, которая любое число, десятичная часть которого больше или равна 0.5, округляет в большую сторону, иначе в меньшую. -```sql-executable +```sql SELECT ROUND(69.499), ROUND(69.5), ROUND(69.501); ``` +| ROUND(69.499) | ROUND(69.5) | ROUND(69.501) | +| ------------- | ----------- | ------------- | +| 69 | 70 | 70 | + Функция `ROUND` также позволяет округлять число до некоторой части десятичных знаков после запятой. Для этого функция принимает второй необязательный аргумент с указанием количества знаков после запятой, которые требуется оставить. -```sql-executable +```sql SELECT ROUND(69.7171,1), ROUND(69.7171,2), ROUND(69.7171,3); ``` +| ROUND(69.7171,1) | ROUND(69.7171,2) | ROUND(69.7171,3) | +| ---------------- | ---------------- | ---------------- | +| 69.7 | 69.72 | 69.717 | + Второй аргумент функции `ROUND` может принимать также и отрицательные значения. -В этом случае, цифры слева от десятичной точки числа становятся равными нулю на указанное в аргументе количество, а дробная часть обрезается. +В этом случае цифры слева от десятичной точки числа становятся равными нулю на указанное в аргументе количество, а дробная часть обрезается. -```sql-executable +```sql SELECT ROUND(1691.7,-1), ROUND(1691.7,-2), ROUND(1691.7,-3); ``` - +| ROUND(1691.7,-1) | ROUND(1691.7,-2) | ROUND(1691.7,-3) | +| ---------------- | ---------------- | ---------------- | +| 1690 | 1700 | 2000 | + +**MySQL** Функция `TRUNCATE` аналогична функции `ROUND`, она также способна принимать 2-й необязательный параметр, только вместо округления она просто отбрасывает ненужные цифры. -```sql-executable +```sql SELECT TRUNCATE(69.7979,1), TRUNCATE(69.7979,2), TRUNCATE(69.7979,3); ``` +| TRUNCATE(69.7979,1) | TRUNCATE(69.7979,2) | TRUNCATE(69.7979,3) | +| ------------------- | ------------------- | ------------------- | +| 69.7 | 69.79 | 69.797 | + А что вернёт следующее выражение? -```sql-executable +```sql SELECT TRUNCATE(69.7979, -1); ``` - - - +**PostgreSQL** Функция `TRUNC` аналогична функции `ROUND`, она также способна принимать 2-й необязательный параметр, только вместо округления она просто отбрасывает ненужные цифры. -```sql-executable +```sql SELECT TRUNC(69.7979,1), TRUNC(69.7979,2), TRUNC(69.7979,3); ``` +| TRUNC(69.7979,1) | TRUNC(69.7979,2) | TRUNC(69.7979,3) | +| ---------------- | ---------------- | ---------------- | +| 69.7 | 69.79 | 69.797 | + А что вернёт следующее выражение? -```sql-executable +```sql SELECT TRUNC(69.7979, -1); ``` - +1. 69.7 — Если функция принимает отрицательное значение в качестве второго аргумента, то цифры слева от десятичной точки числа становятся равными нулю на указанное в аргументе количество, а дробная часть обрезается. + +2. 69 — Если функция принимает отрицательное значение в качестве второго аргумента, то цифры слева от десятичной точки числа становятся равными нулю на указанное в аргументе количество, а дробная часть обрезается. + +3. **Правильный ответ:** 60 — Хорошая работа 🤩, вы абсолютно правы! ## Работа со знаковыми числами При работе с числовыми данными, в которых возможно наличие отрицательных значений, могут быть полезными функции `SIGN` и `ABS`. -Функция `SIGN` возвращает значение `-1`, если число отрицательно, `0`, если число нулевое и `1`, если число положительное. +Функция `SIGN` возвращает значение `-1`, если число отрицательное, `0`, если число нулевое и `1`, если число положительное. -```sql-executable +```sql SELECT SIGN(-69), SIGN(0), SIGN(69); ``` +| SIGN(-69) | SIGN(0) | SIGN(69) | +| --------- | ------- | -------- | +| -1 | 0 | 1 | + Функция `ABS` возвращает абсолютное значение числа. -```sql-executable +```sql SELECT ABS(-69), ABS(0), ABS(69); ``` + +| ABS(-69) | ABS(0) | ABS(69) | +| -------- | ------ | ------- | +| 69 | 0 | 69 | diff --git a/course/module-6/constraints/article.md b/course/module-6/constraints/article.md index 3506b93..454ff27 100644 --- a/course/module-6/constraints/article.md +++ b/course/module-6/constraints/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Ограничения столбцов (Constraints) в SQL: MySQL и PostgreSQL" - description: "Полное руководство по ограничениям (constraints) в MySQL и PostgreSQL, объясняющее, как они обеспечивают корректность и целостность данных в таблицах баз данных. Узнайте о различных типах ограничений, включая PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, CHECK и DEFAULT." + title: "Ограничения в SQL: первичный и внешний ключ, UNIQUE, NOT NULL, CHECK" + description: "Что такое первичный и внешний ключ и как ограничения (constraints) защищают данные: PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, CHECK и DEFAULT с примерами для MySQL и PostgreSQL." --- # Ограничения столбцов (Constraints) в SQL @@ -35,7 +35,7 @@ meta: Он не может содержать NULL-значения и должен быть уникальным. Таблица может иметь только один первичный ключ. - +**MySQL** ```sql CREATE TABLE Users ( @@ -56,15 +56,13 @@ CREATE TABLE Users ( ); ``` -При попытке добавить запись с уже существующим первичным ключом или с NULL-значением вместо ключа, СУБД выдаст ошибку: +При попытке добавить запись с уже существующим первичным ключом или с NULL-значением вместо ключа СУБД выдаст ошибку: ```sql Error(1062) 23000: "Duplicate entry '1' for key 'users.PRIMARY'" ``` - - - +**PostgreSQL** ```sql CREATE TABLE Users ( @@ -92,8 +90,6 @@ ERROR: duplicate key value violates unique constraint "users_pkey" DETAIL: Key (id)=(1) already exists. ``` - - ## FOREIGN KEY (Внешний ключ) Внешний ключ — это столбец или группа столбцов в одной таблице, которые ссылаются на первичный ключ другой таблицы. @@ -166,11 +162,11 @@ CREATE TABLE Users ( ## CHECK (Проверка условия) - +**MySQL** Ограничение CHECK позволяет определить условие, которому должны соответствовать значения в столбце. Это помогает обеспечить бизнес-правила и предотвратить ввод некорректных данных. -**Примечание:** CHECK ограничения полностью поддерживаются в MySQL начиная с версии 8.0.16. В более ранних версиях они принимались синтаксически, но не проверялись. +**Примечание:** CHECK ограничения полностью поддерживаются в MySQL, начиная с версии 8.0.16. В более ранних версиях они принимались синтаксически, но не проверялись. ```sql CREATE TABLE Products ( @@ -194,9 +190,7 @@ CREATE TABLE Employees ( ); ``` - - - +**PostgreSQL** Ограничение CHECK позволяет определить условие, которому должны соответствовать значения в столбце. Это помогает обеспечить бизнес-правила и предотвратить ввод некорректных данных. @@ -234,13 +228,11 @@ CREATE TABLE Users ( ); ``` - - ## DEFAULT (Значение по умолчанию) Ограничение DEFAULT устанавливает значение, которое будет использовано, если при добавлении новой записи не указано значение для этого столбца. - +**MySQL** ```sql CREATE TABLE Orders ( @@ -254,9 +246,7 @@ CREATE TABLE Orders ( В этом примере, если не указана дата заказа, будет использована текущая дата, а статус по умолчанию будет установлен как "Pending". - - - +**PostgreSQL** ```sql CREATE TABLE Orders ( @@ -282,11 +272,9 @@ CREATE TABLE Users ( ); ``` - - ## Добавление и удаление ограничений - +**MySQL** Ограничения можно добавлять не только при создании таблицы, но и при её изменении: @@ -344,9 +332,7 @@ ALTER TABLE Orders ALTER COLUMN status DROP DEFAULT; ``` - - - +**PostgreSQL** Ограничения можно добавлять не только при создании таблицы, но и при её изменении: @@ -404,8 +390,6 @@ ALTER TABLE Orders ALTER COLUMN status DROP DEFAULT; ``` - - ## Лучшие практики использования ограничений 🚀 При проектировании базы данных следует придерживаться следующих рекомендаций: @@ -427,3 +411,11 @@ ALTER COLUMN status DROP DEFAULT; ## Проверка знаний об ограничениях в SQL: Какое из следующих ограничений в SQL НЕ может содержать NULL-значения? + +1. UNIQUE — Ограничение UNIQUE допускает NULL-значения, хотя обычно только одно NULL-значение в столбце. + +2. CHECK — Ограничение CHECK проверяет условие только для непустых значений, NULL-значения обычно пропускаются проверкой. + +3. **Правильный ответ:** PRIMARY KEY — Первичный ключ не может содержать NULL-значения, так как он должен уникально идентифицировать каждую строку в таблице. + +4. FOREIGN KEY — Внешний ключ может содержать NULL-значения, если не указано иное, это означает отсутствие связи с другой таблицей. diff --git a/course/module-6/create-database/article.md b/course/module-6/create-database/article.md index 1f98716..613c3f9 100644 --- a/course/module-6/create-database/article.md +++ b/course/module-6/create-database/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Создание и удаление баз данных: MySQL и PostgreSQL" - description: "SQL синтаксис создания и удаления баз данных в MySQL и PostgreSQL: CREATE DATABASE, DROP DATABASE, IF EXISTS и IF NOT EXISTS." + title: "Создание и удаление баз данных: MySQL и PostgreSQL" + description: "SQL синтаксис создания и удаления баз данных в MySQL и PostgreSQL: CREATE DATABASE, DROP DATABASE, IF EXISTS и IF NOT EXISTS." --- # Создание и удаление баз данных @@ -16,9 +16,9 @@ meta: CREATE DATABASE имя_базы_данных; ``` -### MySQL +**MySQL** -В MySQL в имени базы данных обычно используют буквы, цифры, а также символы "\_" и "$". Максимальная длина имени составляет 64 символа. +В имени базы данных обычно используют буквы, цифры, а также символы "\_" и "$". Максимальная длина имени составляет 64 символа. Проконтролировать создание базы данных можно с помощью оператора `SHOW DATABASES`. @@ -26,11 +26,20 @@ CREATE DATABASE имя_базы_данных; SHOW DATABASES; ``` +| Database | +| ------------------ | +| user_table_1 | +| user_table_2 | +| information_schema | +| mysql | +| performance_schema | +| sys | + > Обратите внимание, что оператор `SHOW DATABASES` кроме пользовательских баз данных отображает также и служебные: information_schema, mysql, performance_schema, sys. -### PostgreSQL +**PostgreSQL** -В PostgreSQL, если имя базы данных записывается без двойных кавычек, оно должно начинаться с буквы или символа "\_". Далее можно использовать буквы, цифры, а также символы "\_" и "$". Максимальная длина имени составляет 63 символа. +Если имя базы данных записывается без двойных кавычек, оно должно начинаться с буквы или символа "\_". Далее можно использовать буквы, цифры, а также символы "\_" и "$". Максимальная длина имени составляет 63 символа. Проконтролировать создание базы данных можно с помощью SQL запроса: @@ -38,6 +47,12 @@ SHOW DATABASES; SELECT datname FROM pg_database WHERE datistemplate = false; ``` +| datname | +| --------------- | +| user_database_1 | +| user_database_2 | +| postgres | + > Обратите внимание, что кроме пользовательских баз данных PostgreSQL также содержит служебные базы данных: postgres, template0, template1. ## Удаление базы данных @@ -48,15 +63,17 @@ SELECT datname FROM pg_database WHERE datistemplate = false; DROP DATABASE имя_базы_данных; ``` -> PostgreSQL: нельзя удалить базу данных, если текущая сессия подключена именно к ней. Также удаление завершится ошибкой, если к базе подключены другие активные сессии. +**PostgreSQL** -## IF EXISTS и IF NOT EXISTS +> Нельзя удалить базу данных, если текущая сессия подключена именно к ней. Также удаление завершится ошибкой, если к базе подключены другие активные сессии. -### MySQL +**MySQL** + +## IF EXISTS и IF NOT EXISTS При создании или удалении базы данных может возникнуть ошибка: например, если база данных с таким именем уже существует или, наоборот, ещё не создана. В таких случаях используются конструкции `IF EXISTS` и `IF NOT EXISTS`. -Если мы хотим создать базу данных только при условии, что она пока не существует, то используется следующий синтаксис: +То есть, если мы хотим создать базу данных только при условии, что она пока не существует, то используется следующий синтаксис: ```sql CREATE DATABASE IF NOT EXISTS имя_базы_данных; @@ -68,11 +85,13 @@ CREATE DATABASE IF NOT EXISTS имя_базы_данных; DROP DATABASE IF EXISTS имя_базы_данных; ``` -### PostgreSQL +**PostgreSQL** + +## IF EXISTS При удалении базы данных может возникнуть ошибка, если такой базы данных не существует. В этом случае можно использовать конструкцию `IF EXISTS`. -В PostgreSQL для удаления базы данных можно использовать конструкцию `IF EXISTS`: +Для удаления базы данных можно использовать конструкцию `IF EXISTS`: ```sql DROP DATABASE IF EXISTS имя_базы_данных; diff --git a/course/module-6/create-table/article.md b/course/module-6/create-table/article.md index bba1609..b0150e2 100644 --- a/course/module-6/create-table/article.md +++ b/course/module-6/create-table/article.md @@ -1,14 +1,14 @@ --- meta: - title: 'Создание и удаление таблиц: MySQL и PostgreSQL' - description: 'SQL создание и удаление таблиц в MySQL и PostgreSQL. Операторы описания таблиц.' + title: "Создание и удаление таблиц: MySQL и PostgreSQL" + description: "SQL создание и удаление таблиц в MySQL и PostgreSQL. Операторы описания таблиц." --- # Создание и удаление таблиц ## Создание таблицы -### MySQL +**MySQL** Перед созданием таблицы необходимо выбрать базу данных, в которую таблица будет записана. Это делается с помощью оператора `USE`: @@ -27,7 +27,9 @@ CREATE TABLE [IF NOT EXISTS] имя_таблицы ( ); ``` -Например, создадим таблицу пользователей: +Например, создадим таблицу пользователей. + +**MySQL** ```sql CREATE TABLE Users ( @@ -37,22 +39,7 @@ CREATE TABLE Users ( ); ``` -`INTEGER`, `VARCHAR(255)` - типы данных: числовой и строковый соответственно. Более подробно о них можно будет узнать в следующих статьях. - -### PostgreSQL - -Для создания таблицы используется оператор `CREATE TABLE`. Его базовый синтаксис имеет следующий вид: - -```sql -CREATE TABLE [IF NOT EXISTS] имя_таблицы ( - столбец_1 тип_данных, - [столбец_2 тип_данных,] - ... - [столбец_n тип_данных,] -); -``` - -Например, создадим таблицу пользователей: +**PostgreSQL** ```sql CREATE TABLE Users ( @@ -62,279 +49,323 @@ CREATE TABLE Users ( ); ``` +**MySQL** + +`INTEGER`, `VARCHAR(255)` - типы данных: числовой и строковый соответственно. Более подробно о них можно будет узнать в следующих статьях. + +**PostgreSQL** + `INTEGER`, `VARCHAR(255)` - типы данных: числовой и строковый соответственно. Более подробно о них можно будет узнать в следующих статьях. ## Дополнительные параметры определения столбцов -Вышеприведённое определение столбцов в таблице является упрощённым. Помимо названия столбца и его типа в определение иногда необходимо добавлять следующие необязательные параметры: +Вышеприведённое определение столбцов в таблице является упрощённым. +Помимо названия столбца и его типа в определение иногда необходимо добавлять следующие необязательные параметры: -- `PRIMARY KEY` — указывает колонку или множество колонок как первичный ключ. -- `UNIQUE` — указывает, что значения в данной колонке для всех записей должны быть отличными друг от друга. -- `NOT NULL` — указывает, что значения в данной колонке должны быть отличными от `NULL`. -- `DEFAULT` — указывает значение по умолчанию. +- `PRIMARY KEY` -### MySQL + Указывает колонку или множество колонок как первичный ключ. -Дополнительно можно использовать параметр `AUTO_INCREMENT`. Он указывает, что значение данной колонки будет автоматически увеличиваться при добавлении новых записей в таблицу. Каждая таблица имеет максимум одну `AUTO_INCREMENT` колонку. Стоит отметить, что данный параметр можно применять только к целочисленным типам и к типам с плавающей запятой. +**MySQL** -Для нашей таблицы пользователей можно указать следующие параметры: +- `AUTO_INCREMENT` -```sql -CREATE TABLE Users ( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18 -); -``` + Указывает, что значение данной колонки будет автоматически увеличиваться при добавлении новых записей в таблицу. Каждая таблица имеет максимум одну `AUTO_INCREMENT` колонку. + Стоит отметить, что данный параметр можно применять только к целочисленным типам и к типам с плавающей запятой. -В данном примере: +**PostgreSQL** -- `id` - поле числового типа, являющееся первичным ключом с автоинкрементом; -- `name` - поле строкового типа с максимальной длиной в 255 символов, являющееся обязательным к заполнению; -- `age` - поле числового типа со значением по умолчанию равным 18. +- `SERIAL` или `GENERATED ALWAYS AS IDENTITY` -### PostgreSQL + Указывает, что значение данной колонки будет автоматически увеличиваться при добавлении новых записей в таблицу. `SERIAL` — это сокращение для создания автоинкрементного поля. -Дополнительно можно использовать `SERIAL` или `GENERATED ALWAYS AS IDENTITY`. Эти конструкции указывают, что значение данной колонки будет автоматически увеличиваться при добавлении новых записей в таблицу. `SERIAL` — это сокращение для создания автоинкрементного поля. +* `UNIQUE` -Для нашей таблицы пользователей можно указать следующие параметры: + Указывает, что значения в данной колонке для всех записей должны быть отличными друг от друга. -```sql -CREATE TABLE Users ( - id SERIAL PRIMARY KEY, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18 -); -``` +* `NOT NULL` -В данном примере: + Указывает, что значения в данной колонке должны быть отличными от `NULL`. -- `id` - поле типа `SERIAL` (автоинкрементное целое число), являющееся первичным ключом; -- `name` - поле строкового типа с максимальной длиной в 255 символов, являющееся обязательным к заполнению; -- `age` - поле числового типа со значением по умолчанию равным 18. +* `DEFAULT` -## CURRENT_TIMESTAMP как значение по умолчанию + Указывает значение по умолчанию. -`CURRENT_TIMESTAMP` удобно использовать, когда нужно автоматически записывать время создания строки. Например, его можно использовать вместе с типом `TIMESTAMP`. +Для нашей таблицы пользователей можно указать следующие параметры: -### MySQL +**MySQL** ```sql CREATE TABLE Users ( id INTEGER PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + age INTEGER NOT NULL DEFAULT 18 ); ``` -### PostgreSQL +**PostgreSQL** ```sql CREATE TABLE Users ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + age INTEGER NOT NULL DEFAULT 18 ); ``` -## Описание таблицы - -### MySQL - -Для того, чтобы посмотреть описание созданной таблицы, можно воспользоваться оператором `DESCRIBE`. - -```sql -DESCRIBE Users; -``` - -### PostgreSQL +Так, в данном примере: -Для того, чтобы посмотреть описание созданной таблицы, можно воспользоваться SQL запросом к информационной схеме: +**MySQL** -```sql -SELECT column_name, data_type, is_nullable, column_default -FROM information_schema.columns -WHERE table_schema = current_schema() AND table_name = 'users'; -``` - -## Дополнительные параметры определения таблицы - -Помимо описания столбцов, при создании таблицы можно дополнительно указать следующие параметры. - -### MySQL - -#### Первичный ключ +- `id` - поле числового типа, являющееся первичным ключом с автоинкрементом; -Если вы не определили первичный ключ с помощью параметров столбца, то это можно сделать с помощью дополнительных параметров таблицы, добавив запись `PRIMARY KEY (<столбец_1>, <столбец_n>)` после перечисления столбцов: +**PostgreSQL** -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - PRIMARY KEY (id) -); -``` +- `id` - поле типа SERIAL (автоинкрементное целое число), являющееся первичным ключом; -#### Внешние ключи +* `name` - поле строкового типа с максимальной длиной в 255 символов, являющееся обязательным к заполнению; +* `age` - поле числового типа со значением по умолчанию равным 18. -Предположим, что мы хотим хранить данные о компании, в которой работают наши пользователи. Давайте создадим небольшую таблицу `Companies`, в которой мы будем хранить уникальный идентификатор и название компании: +## CURRENT_TIMESTAMP как значение по умолчанию -```sql -CREATE TABLE Companies ( - id INTEGER, - name VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -); -``` +`CURRENT_TIMESTAMP` удобно использовать, когда нужно автоматически записывать время создания строки. Например, его можно использовать вместе с типом `TIMESTAMP`. -Дальше нужно добавить в таблицу `Users` поле `company` - место работы нашего пользователя, которое будет ссылаться на запись в таблице `Companies`. Полный запрос для создания таблицы будет выглядеть так: +**MySQL** ```sql CREATE TABLE Users ( - id INTEGER, + id INTEGER PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id) + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` -Для того, чтобы при добавлении новых записей в таблицу `Users` гарантировать, что в колонке `company` находится идентификатор, существующий в таблице `Companies`, используется внешний ключ. Он имеет следующий синтаксис: - -```sql -FOREIGN KEY (<столбец_1>, <столбец_n>) -REFERENCES <внешняя_таблица> (<столбец_во_внешней_таблице_1>, <столбец_во_внешней_таблице_n>) -[ON DELETE действие] -[ON UPDATE действие] -``` - -Полный запрос для создания таблицы с внешним ключом будет таким: +**PostgreSQL** ```sql CREATE TABLE Users ( - id INTEGER, + id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (company) REFERENCES Companies (id) + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` -При наличии внешних ключей можно определить поведение текущей записи при изменении или удалении записи, на которую она ссылается: +## Описание таблицы -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (company) REFERENCES Companies (id) - ON DELETE RESTRICT ON UPDATE CASCADE -); -``` +**MySQL** -`ON DELETE RESTRICT` означает, что если попробовать удалить компанию, у которой в таблице `Users` есть данные, база данных не даст этого сделать: +Для того чтобы посмотреть описание созданной таблицы, можно воспользоваться оператором `DESCRIBE`. ```sql -Cannot delete or update a parent row: a foreign key constraint fails +DESCRIBE Users; ``` -Если бы было указано `ON DELETE CASCADE`, то при удалении компании были бы удалены все пользователи, ссылающиеся на эту компанию. - -Есть ещё одна опция - `ON DELETE SET NULL`. При её использовании база данных запишет `NULL` в качестве значения поля `company` для всех пользователей, работавших в удалённой компании. +| Field | Type | Null | Key | Default | Extra | +| ----- | ------------ | ---- | --- | ------- | -------------- | +| id | int | NO | PRI | NULL | auto_increment | +| name | varchar(255) | NO | | NULL | | +| age | int | NO | | 18 | | -`ON UPDATE CASCADE` означает, что если компания изменит свой идентификатор, то все пользователи (`Users`) получат новый идентификатор в поле `company`. +**PostgreSQL** -### PostgreSQL - -#### Первичный ключ - -Если вы не определили первичный ключ с помощью параметров столбца, то это можно сделать с помощью дополнительных параметров таблицы, добавив запись `PRIMARY KEY (<столбец_1>, <столбец_n>)` после перечисления столбцов: +Для того чтобы посмотреть описание созданной таблицы, можно воспользоваться SQL запросом к информационной схеме: ```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - PRIMARY KEY (id) -); +SELECT column_name, data_type, is_nullable, column_default +FROM information_schema.columns +WHERE table_schema = current_schema() AND table_name = 'users'; ``` -#### Внешние ключи +| column_name | data_type | is_nullable | column_default | +| ----------- | ----------------- | ----------- | --------------------------------- | +| id | integer | NO | nextval('users_id_seq'::regclass) | +| name | character varying | NO | null | +| age | integer | NO | 18 | -Предположим, что мы хотим хранить данные о компании, в которой работают наши пользователи. Давайте создадим небольшую таблицу `Companies`, в которой мы будем хранить уникальный идентификатор и название компании: +## Дополнительные параметры определения таблицы -```sql -CREATE TABLE Companies ( - id INTEGER, - name VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -); -``` +Помимо описания столбцов, при создании таблицы можно дополнительно указать следующие параметры: + +**MySQL** + +- Первичный ключ. -Дальше нужно добавить в таблицу `Users` поле `company` - место работы нашего пользователя, которое будет ссылаться на запись в таблице `Companies`. Полный запрос для создания таблицы будет выглядеть так: + Если вы не определили первичный ключ с помощью параметров столбца, то это можно сделать с помощью дополнительных параметров таблицы, добавив запись `PRIMARY KEY (<столбец_1>, <столбец_n>)` после перечисления столбцов: -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id) -); -``` - -Для того, чтобы при добавлении новых записей в таблицу `Users` гарантировать, что в колонке `company` находится идентификатор, существующий в таблице `Companies`, используется внешний ключ. Он имеет следующий синтаксис: - -```sql -FOREIGN KEY (<столбец_1>, <столбец_n>) -REFERENCES <внешняя_таблица> (<столбец_во_внешней_таблице_1>, <столбец_во_внешней_таблице_n>) -[ON DELETE действие] -[ON UPDATE действие] -``` + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + PRIMARY KEY (id) + ); + ``` -Полный запрос для создания таблицы с внешним ключом будет таким: +**PostgreSQL** -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (company) REFERENCES Companies (id) -); -``` +- Первичный ключ. -При наличии внешних ключей можно определить поведение текущей записи при изменении или удалении записи, на которую она ссылается: + Если вы не определили первичный ключ с помощью параметров столбца, то это можно сделать с помощью дополнительных параметров таблицы, добавив запись `PRIMARY KEY (<столбец_1>, <столбец_n>)` после перечисления столбцов: -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - company INTEGER, - PRIMARY KEY (id), - FOREIGN KEY (company) REFERENCES Companies (id) - ON DELETE RESTRICT ON UPDATE CASCADE -); -``` + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + PRIMARY KEY (id) + ); + ``` + +**MySQL** -`ON DELETE RESTRICT` означает, что если попробовать удалить компанию, у которой в таблице `Users` есть данные, база данных не даст этого сделать: +- Внешние ключи. -```sql -ERROR: update or delete on table "companies" violates foreign key constraint "users_company_fkey" on table "users" -DETAIL: Key (id)=(1) is still referenced from table "users". -``` + Предположим, что мы хотим хранить данные о компании, в которой работают наши пользователи. Давайте создадим небольшую таблицу `Companies`, в которой мы будем хранить уникальный идентификатор и название компании: -Если бы было указано `ON DELETE CASCADE`, то при удалении компании были бы удалены все пользователи, ссылающиеся на эту компанию. + ```sql + CREATE TABLE Companies ( + id INTEGER, + name VARCHAR(255) NOT NULL, + PRIMARY KEY (id) + ); + ``` -Есть ещё одна опция - `ON DELETE SET NULL`. При её использовании база данных запишет `NULL` в качестве значения поля `company` для всех пользователей, работавших в удалённой компании. + Дальше нужно добавить в таблицу `Users` поле `company` – место работы нашего пользователя, которое будет ссылаться на запись в таблице `Companies`. Полный запрос для создания таблицы будет выглядеть так: + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id) + ); + ``` + + Для того, чтобы при добавлении новых записей в таблицу `Users` гарантировать, что в колонке `company` находится идентификатор, существующий в таблице `Companies`, + используется внешний ключ. Он имеет следующий синтаксис: + + ```sql + FOREIGN KEY (<столбец_1>, <столбец_n>) + REFERENCES <внешняя_таблица> (<столбец_во_внешней_таблице_1>, <столбец_во_внешней_таблице_n>) + [ON DELETE действие] + [ON UPDATE действие] + ``` + + Полный запрос для создания таблицы с внешним ключом будет таким: + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (company) REFERENCES Companies (id) + ); + ``` + + При наличии внешних ключей можно определить поведение текущей записи, при изменении или удалении записи, на которую она ссылается. + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (company) REFERENCES Companies (id) + ON DELETE RESTRICT ON UPDATE CASCADE + ); + ``` + + `ON DELETE RESTRICT` означает, что если попробовать удалить компанию, у которой в таблице `Users` есть данные, база данных не даст этого сделать: + + ```sql + Cannot delete or update a parent row: a foreign key constraint fails + ``` + + Если бы было указано `ON DELETE CASCADE`, то при удалении компании были бы удалены все пользователи, ссылающиеся на эту компанию. + + Есть ещё одна опция — `ON DELETE SET NULL`. При её использовании база данных запишет `NULL` в качестве значения поля `company` для всех пользователей, работавших в удалённой компании. + + `ON UPDATE CASCADE` означает, что если компания изменит свой идентификатор, то все пользователи (`Users`) получат новый идентификатор в поле company. + +**PostgreSQL** + +- Внешние ключи. + + Предположим, что мы хотим хранить данные о компании, в которой работают наши пользователи. Давайте создадим небольшую таблицу `Companies`, в которой мы будем хранить уникальный идентификатор и название компании: + + ```sql + CREATE TABLE Companies ( + id INTEGER, + name VARCHAR(255) NOT NULL, + PRIMARY KEY (id) + ); + ``` + + Дальше нужно добавить в таблицу `Users` поле `company` – место работы нашего пользователя, которое будет ссылаться на запись в таблице `Companies`. Полный запрос для создания таблицы будет выглядеть так: + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id) + ); + ``` + + Для того, чтобы при добавлении новых записей в таблицу `Users` гарантировать, что в колонке `company` находится идентификатор, существующий в таблице `Companies`, + используется внешний ключ. Он имеет следующий синтаксис: + + ```sql + FOREIGN KEY (<столбец_1>, <столбец_n>) + REFERENCES <внешняя_таблица> (<столбец_во_внешней_таблице_1>, <столбец_во_внешней_таблице_n>) + [ON DELETE действие] + [ON UPDATE действие] + ``` + + Полный запрос для создания таблицы с внешним ключом будет таким: + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (company) REFERENCES Companies (id) + ); + ``` + + При наличии внешних ключей можно определить поведение текущей записи, при изменении или удалении записи, на которую она ссылается. + + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + company INTEGER, + PRIMARY KEY (id), + FOREIGN KEY (company) REFERENCES Companies (id) + ON DELETE RESTRICT ON UPDATE CASCADE + ); + ``` + + `ON DELETE RESTRICT` означает, что если попробовать удалить компанию, у которой в таблице `Users` есть данные, база данных не даст этого сделать: + + ```sql + ERROR: update or delete on table "companies" violates foreign key constraint "users_company_fkey" on table "users" + DETAIL: Key (id)=(1) is still referenced from table "users". + ``` + + Если бы было указано `ON DELETE CASCADE`, то при удалении компании были бы удалены все пользователи, ссылающиеся на эту компанию. + + Есть ещё одна опция — `ON DELETE SET NULL`. При её использовании база данных запишет `NULL` в качестве значения поля `company` для всех пользователей, работавших в удалённой компании. -`ON UPDATE CASCADE` означает, что если компания изменит свой идентификатор, то все пользователи (`Users`) получат новый идентификатор в поле `company`. + `ON UPDATE CASCADE` означает, что если компания изменит свой идентификатор, то все пользователи (`Users`) получат новый идентификатор в поле company. ## Удаление таблицы @@ -343,3 +374,9 @@ DETAIL: Key (id)=(1) is still referenced from table "users". ```sql DROP TABLE [IF EXISTS] имя_таблицы; ``` + +## Интерактивное задание + +Теперь, когда вы изучили основы создания таблиц, попробуйте закрепить материал с помощью интерактивного задания: + +Интерактивная демонстрация доступна [в уроке на SQL Academy](https://sql-academy.org/ru/guide/create-table). diff --git a/course/module-6/datetime-data-type/article.md b/course/module-6/datetime-data-type/article.md index de840bd..b8582cf 100644 --- a/course/module-6/datetime-data-type/article.md +++ b/course/module-6/datetime-data-type/article.md @@ -1,12 +1,12 @@ --- meta: - title: "Работа с датами и временем в SQL: MySQL и PostgreSQL" - description: "Функции для работы с датами и временем в MySQL и PostgreSQL. Типы данных DATE, TIME, DATETIME, TIMESTAMP и их отличия." + title: "Работа с датами и временем в SQL: MySQL и PostgreSQL" + description: "Функции для работы с датами и временем в MySQL и PostgreSQL. Типы данных DATE, TIME, DATETIME, TIMESTAMP и их отличия." --- # Работа с датами и временем - +**MySQL** Для работы с датой и временем в MySQL есть несколько типов данных: `DATE`, `TIME`, `DATETIME` и `TIMESTAMP`. @@ -17,9 +17,7 @@ meta: | `DATETIME` | Хранит значение даты и времени в виде ГГГГ-MM-ДД ЧЧ:ММ:СС.
Например, 2022-12-05 10:37:22 | от 1000-01-01 00:00:00 до 9999-12-31 23:59:59 | 8 байта | | `TIMESTAMP` | Хранит значение даты и времени в виде ГГГГ-MM-ДД ЧЧ:ММ:СС.
Например, 2022-12-05 10:37:22 | от 1970-01-01 00:00:01 до 2038-01-19 03:14:07 | 4 байта | -
- - +**PostgreSQL** Для работы с датой и временем в PostgreSQL есть несколько типов данных: `DATE`, `TIME`, `TIMESTAMP`, `TIMESTAMPTZ` и `INTERVAL`. @@ -31,9 +29,7 @@ meta: | `TIMESTAMPTZ` | Хранит значение даты и времени с часовым поясом.
Например, 2022-12-05 10:37:22+03 | от 4713 BC до 294276 AD | 8 байт | | `INTERVAL` | Хранит интервал времени.
Например, 1 year 2 months 3 days 4 hours | от -178000000 лет до 178000000 лет | 16 байт | -
- - +**MySQL** ## Отличие TIMESTAMP и DATETIME @@ -54,6 +50,10 @@ SET @@session.time_zone="+03:00"; -- меняем часовой пояс в MYS SELECT * FROM datetime_table; ``` +| datetime_field | +| ------------------- | +| 2022-06-16 16:37:23 | + ## TIMESTAMP Хранит, сколько прошло секунд с 1970-01-01 00:00:00 по нулевому часовому поясу, и занимает 4 байта. @@ -69,12 +69,14 @@ SET @@session.time_zone="+03:00"; -- меняем часовой пояс в MYS SELECT * FROM timestamp_table; ``` +| timestamp_field | +| ------------------- | +| 2022-06-16 19:37:23 | + Также стоит помнить о существующем ограничении `TIMESTAMP` в диапазоне возможных значений от 1970-01-01 00:00:01 до 2038-01-19 03:14:07, что ограничивает его применение. Так, данный тип данных не подойдёт для хранения дат рождения пользователей. - - - +**PostgreSQL** ## Отличие TIMESTAMP и TIMESTAMPTZ @@ -120,11 +122,9 @@ SELECT '2 weeks'::INTERVAL; SELECT '90 minutes'::INTERVAL; ``` - - ## Способ задания значений - +**MySQL** Значения `DATETIME`, `DATE` и `TIMESTAMP` могут быть заданы одним из следующих способов: @@ -133,7 +133,7 @@ SELECT '90 minutes'::INTERVAL; При указании даты допускается использовать любой знак пунктуации в качестве разделительного между частями разделов даты или времени. Также возможно задавать дату вообще без разделительного знака, слитно. -```sql-executable +```sql CREATE TABLE date_table (datetime TIMESTAMP); INSERT INTO date_table VALUES("2022-06-16 16:37:23"); INSERT INTO date_table VALUES("22.05.31 8+15+04"); @@ -143,9 +143,15 @@ INSERT INTO date_table VALUES("2021-02-12"); SELECT * FROM date_table; ``` - +| datetime | +| ------------------- | +| 2022-06-16 16:37:23 | +| 2022-05-31 08:15:04 | +| 2014-02-22 16:37:22 | +| 2022-06-16 16:37:23 | +| 2021-02-12 00:00:00 | - +**PostgreSQL** Значения типов даты и времени могут быть заданы в различных форматах: @@ -154,7 +160,7 @@ SELECT * FROM date_table; - Только дата: 'YYYY-MM-DD' - Только время: 'HH:MM:SS' -```sql-executable +```sql CREATE TABLE date_table ( date_field DATE, time_field TIME, @@ -173,5 +179,3 @@ SELECT * FROM date_table; ``` PostgreSQL строго следует стандарту ISO 8601 и предпочитает использовать стандартные форматы дат. - - diff --git a/course/module-6/indexes/article.md b/course/module-6/indexes/article.md index 05a039d..27cc94b 100644 --- a/course/module-6/indexes/article.md +++ b/course/module-6/indexes/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Индексы в SQL: ускорение поиска данных в MySQL и PostgreSQL" - description: "Полное руководство по индексам в SQL, объясняющее, как они упрощают и ускоряют поиск данных в таблицах баз данных в MySQL и PostgreSQL. Узнайте, как создавать, управлять и оптимизировать индексы для улучшения производительности ваших запросов." + title: "Индексы в SQL: ускорение поиска данных в MySQL и PostgreSQL" + description: "Полное руководство по индексам в SQL, объясняющее, как они упрощают и ускоряют поиск данных в таблицах баз данных в MySQL и PostgreSQL. Узнайте, как создавать, управлять и оптимизировать индексы для улучшения производительности ваших запросов." --- # Индексы в SQL @@ -40,7 +40,7 @@ SELECT email FROM Users WHERE email LIKE 'l%'; индекс к столбцу `email`, чтобы ускорить любые запросы, которые работают со значением этого столбца. - +**MySQL** Вот как можно добавить такой индекс в СУБД MySQL: @@ -61,6 +61,11 @@ CREATE INDEX idx_email SHOW INDEX FROM Users; ``` +| Table | Non_unique | Key_name | Seq_in_index | Column_name | +| ----- | ---------- | --------- | ------------ | ----------- | +| users | 0 | PRIMARY | 1 | id | +| users | 1 | idx_email | 1 | email | + Вывод демонстрирует, что в таблице `Users` есть 2 индекса: один — для столбца `id` с именем `PRIMARY` и ещё один для столбца `email`, который мы только что определили. @@ -71,9 +76,7 @@ SHOW INDEX FROM Users; что каждое значение в столбце или группе столбцов, назначенных в качестве первичного ключа таблицы, уникально и не может быть `NULL`. - - - +**PostgreSQL** Вот как можно добавить такой индекс в СУБД PostgreSQL: @@ -96,6 +99,11 @@ FROM pg_indexes WHERE tablename = 'users'; ``` +| indexname | indexdef | +| ---------- | --------------------------------------------------------------- | +| users_pkey | CREATE UNIQUE INDEX users_pkey ON public.users USING btree (id) | +| idx_email | CREATE INDEX idx_email ON public.users USING btree (email) | + PostgreSQL автоматически создаёт индекс для столбца первичного ключа, которым в данном случае является `id`. Это особый тип индекса, используемый с ограничением первичного ключа, которое гарантирует, что каждое значение в столбце или группе столбцов, назначенных в качестве первичного ключа таблицы, @@ -109,11 +117,9 @@ PostgreSQL поддерживает различные типы индексов - **GiST** — для геометрических данных и полнотекстового поиска - **BRIN** — для очень больших таблиц с естественной сортировкой - - ## Удаление индекса - +**MySQL** Если после создания индекса вы решите, что он больше не нужен, можете удалить его следующим образом: @@ -122,9 +128,7 @@ PostgreSQL поддерживает различные типы индексов DROP INDEX idx_email ON Users; ``` - - - +**PostgreSQL** Если после создания индекса вы решите, что он больше не нужен, можете удалить его следующим образом: @@ -133,8 +137,6 @@ DROP INDEX idx_email ON Users; DROP INDEX idx_email; ``` - - ## Уникальные (UNIQUE) индексы При проектировании баз данных важно определить, для каких столбцов допускаются повторения значений, @@ -161,7 +163,7 @@ CREATE UNIQUE INDEX idx_email ON Users (email); ``` - +**MySQL** При наличии индекса вы получите сообщение об ошибке, если попытаетесь добавить нового клиента с уже существующим адресом электронной почты: @@ -170,9 +172,7 @@ CREATE UNIQUE INDEX idx_email Error(1062) 23000: "Duplicate entry 'duplicate@gmail.com' for key 'users.idx_email'" ``` - - - +**PostgreSQL** При наличии индекса вы получите сообщение об ошибке, если попытаетесь добавить нового клиента с уже существующим адресом электронной почты: @@ -182,8 +182,6 @@ ERROR: duplicate key value violates unique constraint "idx_email" DETAIL: Key (email)=(duplicate@gmail.com) already exists. ``` - - Создание уникальных индексов для столбца или столбцов, определённых как первичный ключ, излишне, так как система управления базой данных автоматически обеспечивает уникальность значений первичного ключа. Впрочем, размещение нескольких уникальных индексов в одной таблице допустимо и может быть целесообразно, @@ -218,7 +216,7 @@ CREATE INDEX idx_full_name а затем для получения дополнительных данных из связанных таблиц по запросу пользователя. Возьмём для примера запрос: -```sql-executable-Schedule +```sql SELECT id, first_name, last_name FROM Student WHERE first_name LIKE 'A%' AND last_name LIKE 'L%' @@ -233,7 +231,7 @@ SELECT id, first_name, last_name Последний метод представляется наиболее эффективным, так как позволяет найти все необходимые строки за один проход, избегая повторного обращения к таблице. - +**MySQL** Но как определить, какой из методов выберет оптимизатор запросов MySQL? Для этого можно использовать команду `EXPLAIN`, которая показывает, как СУБД планирует @@ -247,13 +245,15 @@ EXPLAIN AND last_name LIKE 'L%'; ``` +| id | select_type | table | partitions | possible_keys | key | +| --- | ----------- | ------- | ---------- | --------------------------- | ------------- | +| 1 | SIMPLE | Student | null | idx_full_name,idx_last_name | idx_full_name | + Анализируя результаты, можно увидеть, что в столбце `possible_keys` указаны потенциально применимые индексы `idx_last_name` или `idx_full_name`, а в столбце `key` указано, что выбран индекс `idx_full_name`. - - - +**PostgreSQL** Но как определить, какой из методов выберет оптимизатор запросов PostgreSQL? Для этого можно использовать команду `EXPLAIN`, которая показывает, как СУБД планирует @@ -267,6 +267,12 @@ EXPLAIN AND last_name LIKE 'L%'; ``` +| QUERY PLAN | +| --------------------------------------------------------------------------- | +| Index Scan using idx_full_name on student (cost=0.42..8.44 rows=1 width=68) | +| Index Cond: ((last_name >= 'L'::text) AND (last_name \< 'M'::text)) | +| Filter: ((first_name \~\~ 'A%'::text) AND (last_name \~\~ 'L%'::text)) | + Также можно использовать `EXPLAIN ANALYZE` для получения реальной статистики выполнения: ```sql @@ -277,11 +283,17 @@ EXPLAIN ANALYZE AND last_name LIKE 'L%'; ``` +| QUERY PLAN | +| --------------------------------------------------------------------------------------------------------------------- | +| Index Scan using idx_full_name on student (cost=0.42..8.44 rows=1 width=68) (actual time=0.025..0.027 rows=1 loops=1) | +| Index Cond: ((last_name >= 'L'::text) AND (last_name \< 'M'::text)) | +| Filter: ((first_name \~\~ 'A%'::text) AND (last_name \~\~ 'L%'::text)) | +| Planning Time: 0.156 ms | +| Execution Time: 0.048 ms | + Анализируя результаты `EXPLAIN`, можно увидеть, какой метод доступа выбрал оптимизатор — полное сканирование таблицы (Seq Scan) или сканирование индекса (Index Scan). - - ## Обратная сторона индексов Если индексы столь эффективны, возникает вопрос: почему бы просто не индексировать всё подряд? 🧐 @@ -307,3 +319,11 @@ EXPLAIN ANALYZE **Давайте проверим, как вы усвоили тему:** Какое утверждение наилучшим образом объясняет причину, по которой **не следует** индексировать каждый столбец в таблице базы данных? + +1. Индексы увеличивают скорость всех операций в базе данных, включая вставку, обновление и удаление данных. — Хотя индексы действительно могут увеличить скорость выполнения запросов на чтение, они могут замедлить операции вставки, обновления и удаления данных, так как требуют дополнительного обновления индексных структур. + +2. Индексы не требуют дополнительного места на диске и поэтому могут быть созданы без каких-либо недостатков. — Индексы занимают дополнительное пространство на диске, что является одной из причин, почему не следует бездумно индексировать каждый столбец. + +3. Индексы уменьшают необходимость в оптимизации запросов, так как автоматически оптимизируют все запросы. — Несмотря на то что индексы могут значительно улучшить производительность некоторых запросов, они не заменяют необходимость в тщательной оптимизации запросов и проектировании схемы базы данных. + +4. **Правильный ответ:** Индексы ускоряют операции чтения, но могут замедлить операции записи, так как каждый индекс нужно обновить при изменении данных. — Это утверждение правильно отражает компромисс, связанный с использованием индексов. Они действительно ускоряют чтение за счёт потенциального замедления операций записи, что делает важным балансирование между количеством индексов и их влиянием на производительность всей системы. diff --git a/course/module-6/number-data-type/article.md b/course/module-6/number-data-type/article.md index 8a5ad30..ded949a 100644 --- a/course/module-6/number-data-type/article.md +++ b/course/module-6/number-data-type/article.md @@ -1,14 +1,14 @@ --- meta: - title: "Числовой тип данных в SQL: MySQL и PostgreSQL" - description: "Работа с числами в MySQL и PostgreSQL. Основные числовые типы данных: INTEGER, DECIMAL, FLOAT и другие." + title: "Числовые типы данных в SQL: INT, DECIMAL, FLOAT — отличия" + description: "Числовые типы данных SQL и их отличия: целые INT и BIGINT, точные DECIMAL и NUMERIC, приближённые FLOAT и DOUBLE. Какой тип выбрать для денег, счётчиков и измерений в MySQL и PostgreSQL." --- # Числовой тип данных Числовые данные разделяются на точные и приближенные, на целые и вещественные. В отдельную категорию можно отнести битовые значения. - +**MySQL** ## Точные целые числа @@ -71,9 +71,7 @@ CREATE TABLE Users ( Как и в целочисленных типах, этот атрибут предотвращает хранение в отмеченном столбце отрицательных величин, но, в отличие от целочисленных типов, максимальный интервал для величин столбца остаётся прежним. - - - +**PostgreSQL** ## Целые числа @@ -121,5 +119,3 @@ CREATE TABLE Users ( | `DOUBLE PRECISION` | 8 байтов | 15 знаков | от 1E-307 до 1E+308 | Типы с плавающей точкой используются для приближенных вычислений. PostgreSQL также поддерживает специальные значения: `Infinity`, `-Infinity` и `NaN` (не число). - - diff --git a/course/module-6/string-data-type/article.md b/course/module-6/string-data-type/article.md index 9bc2288..955bade 100644 --- a/course/module-6/string-data-type/article.md +++ b/course/module-6/string-data-type/article.md @@ -1,32 +1,32 @@ --- meta: - title: "Строковый тип данных в SQL: MySQL и PostgreSQL" - description: "Работа со строками в MySQL и PostgreSQL. Основные типы данных для текстовой информации." + title: "Строковый тип данных в SQL: MySQL и PostgreSQL" + description: "Работа со строками в MySQL и PostgreSQL. Основные типы данных для текстовой информации." --- # Строковый тип данных Строковый тип данных является наиболее используемым типом данных. Благодаря ему в базе данных хранятся как текстовые, так и различные двоичные данные (например, картинки). - +**MySQL** В MySQL он представлен следующими типами: ## CHAR и VARCHAR -| Тип | Описание | Диапазон символов | -| :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------ | +| Тип | Описание | Диапазон символов | +| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------ | | `CHAR(X)` | Содержит текстовые строки. Длина фиксированная, её вы указываете при объявлении. В случае, если длина строки меньше указанной, она дополняется правыми пробелами до указанной длины. | Длина может быть любой в диапазоне от 0 до 255 | -| `VARCHAR(X)` | Содержит текстовые строки. Длина строк динамическая. | Длина может быть любой в диапазоне от 0 до 65,535 | +| `VARCHAR(X)` | Содержит текстовые строки. Длина строк динамическая. | Длина может быть любой в диапазоне от 0 до 65,535 | ## BINARY и VARBINARY Типы данных `BINARY` и `VARBINARY` аналогичны `VARCHAR` и `CHAR` только они хранят двоичные строки. -| Тип | Описание | Диапазон символов | -| :------------- | :---------------------------------------------------------------------------- | :------------------------------------------------ | +| Тип | Описание | Диапазон символов | +| :------------- | :------------------------------------------------------------------------------ | :------------------------------------------------ | | `BINARY(X)` | Содержит двоичные строки. Длина фиксированная, её вы указываете при объявлении. | Длина может быть любой в диапазоне от 0 до 255 | -| `VARBINARY(X)` | Содержит двоичные строки. Длина строк динамическая. | Длина может быть любой в диапазоне от 0 до 65,535 | +| `VARBINARY(X)` | Содержит двоичные строки. Длина строк динамическая. | Длина может быть любой в диапазоне от 0 до 65,535 | ## BLOB и TEXT @@ -50,9 +50,7 @@ meta: | `MEDIUMTEXT` | Максимальная длина 16,777,215 | | `LONGTEXT` | Максимальная длина 4,294,967,295 | - - - +**PostgreSQL** В PostgreSQL он представлен следующими типами: @@ -65,5 +63,3 @@ meta: | `TEXT` | Содержит текстовые строки неограниченной переменной длины. | Практически неограниченная длина (до 1 ГБ) | Важно отметить, что в PostgreSQL тип `TEXT` предпочтительнее использовать вместо `VARCHAR` без ограничения длины, так как они имеют одинаковую производительность. - - diff --git a/course/module-6/table-data-type/article.md b/course/module-6/table-data-type/article.md index 7dd002a..dc3489a 100644 --- a/course/module-6/table-data-type/article.md +++ b/course/module-6/table-data-type/article.md @@ -1,7 +1,7 @@ --- meta: - title: 'Типы данных для колонок таблиц' - description: 'Типы данных для колонок таблиц в SQL' + title: "Типы данных для колонок таблиц" + description: "Типы данных для колонок таблиц в SQL" --- # Типы данных для колонок таблиц diff --git a/course/module-6/view/article.md b/course/module-6/view/article.md index 8f1a191..a68801f 100644 --- a/course/module-6/view/article.md +++ b/course/module-6/view/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Представление VIEW в SQL: MySQL и PostgreSQL" - description: "Синтаксис создания представлений в MySQL и PostgreSQL, описание работы представлений и зачем они нужны." + title: "Представление VIEW в SQL: MySQL и PostgreSQL" + description: "Синтаксис создания представлений в MySQL и PostgreSQL, описание работы представлений и зачем они нужны." --- # Представления, VIEW @@ -30,15 +30,15 @@ meta: В качестве простого примера предположим, что вы хотите частично скрыть адреса электронной почты в таблице пользователей (`Users`). - +ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/view). Это может быть полезно, например, если политика вашей компании не позволяет всем использовать -конфиденциальную информацию о пользователях. +конфиденциальную информацию об пользователях. Поэтому вместо того, чтобы разрешить прямой доступ к таблице пользователей (`Users`), вы определяете представление с именем `ViewUsers` и требуете, чтобы все использовали его для доступа к данным о пользователях. - +**MySQL** Вот пример определения этого представления: @@ -50,9 +50,7 @@ CREATE VIEW ViewUsers AS FROM Users; ``` - - - +**PostgreSQL** Вот пример определения этого представления: @@ -64,15 +62,49 @@ CREATE VIEW ViewUsers AS FROM Users; ``` - - Представление в SQL-запросе выглядит и используется как обычная таблица: ```sql SELECT * FROM ViewUsers; ``` - +| id | name | email | +| --- | -------------------- | -------------- | +| 1 | Bruce Willis | ba\*\*\*\*.com | +| 2 | George Clooney | te\*\*\*\*.com | +| 3 | Kevin Costner | me\*\*\*\*.com | +| 4 | Donald Sutherland | ra\*\*\*\*.net | +| 5 | Jennifer Lopez | ba\*\*\*\*.com | +| 6 | Ray Liotta | jd\*\*\*\*.net | +| 7 | Samuel L. Jackson | mo\*\*\*\*.com | +| 8 | Nikole Kidman | ok\*\*\*\*.com | +| 9 | Alan Rickman | ka\*\*\*\*.net | +| 10 | Kurt Russell | ga\*\*\*\*.com | +| 11 | Harrison Ford | ko\*\*\*\*.com | +| 12 | Russell Crowe | gl\*\*\*\*.net | +| 13 | Steve Martin | ne\*\*\*\*.com | +| 14 | Michael Caine | dm\*\*\*\*.com | +| 15 | Angelina Jolie | ch\*\*\*\*.net | +| 16 | Mel Gibson | ro\*\*\*\*o.ca | +| 17 | Michael Douglas | ti\*\*\*\*.com | +| 18 | John Travolta | wa\*\*\*\*.com | +| 19 | Sylvester Stallone | ko\*\*\*\*.com | +| 20 | Tommy Lee Jones | sz\*\*\*\*.com | +| 21 | Catherine Zeta-Jones | fl\*\*\*\*.com | +| 22 | Antonio Banderas | sa\*\*\*\*.net | +| 23 | Kim Basinger | ja\*\*\*\*.net | +| 24 | Sam Neill | cl\*\*\*\*.com | +| 25 | Hideo Kojima | ad\*\*\*\*.org | +| 26 | ClINT Eastwood | fr\*\*\*\*.net | +| 27 | Brad Pitt | ke\*\*\*\*.net | +| 28 | Johnny Depp | cg\*\*\*\*o.ca | +| 29 | Pierce Brosnan | tr\*\*\*\*.com | +| 30 | Sean Connery | js\*\*\*\*.com | +| 31 | Bruce Willis | ke\*\*\*\*.com | +| 32 | Mullah Omar | jg\*\*\*\*.com | +| 33 | Vasanta Roberta | ro\*\*\*\*.com | + +**MySQL** Если вы хотите узнать, какие столбцы доступны в представлении, вы можете использовать оператор `DESCRIBE`: @@ -80,9 +112,13 @@ SELECT * FROM ViewUsers; DESCRIBE ViewUsers; ``` - +| Field | Type | Null | Key | Default | Extra | +| ----- | ----------- | ---- | --- | ------- | ----- | +| id | int | NO | | \ | | +| name | varchar(32) | NO | | \ | | +| email | varchar(38) | YES | | \ | | - +**PostgreSQL** Если вы хотите узнать, какие столбцы доступны в представлении, вы можете использовать запрос к `information_schema`: @@ -92,11 +128,9 @@ FROM information_schema.columns WHERE table_name = 'viewusers'; ``` - - ## Общий синтаксис представления - +**MySQL** ```sql CREATE [OR REPLACE] @@ -105,12 +139,10 @@ AS select_выражение ``` `OR REPLACE` — при использовании этого опционального параметра в случае, если представление с таким -именем уже существует, старое представление будет удалено, а новое создано. В противном случае, при попытке создать -представление с существующим именем, возникнет ошибка. - - +именем уже существует, старое представление будет удалено, а новое создано. В противном случае при попытке создать +представление с существующим именем возникнет ошибка. - +**PostgreSQL** ```sql CREATE [OR REPLACE] VIEW имя_представления [(имена_полей_представления)] @@ -121,8 +153,6 @@ AS select_выражение именем уже существует, старое представление будет удалено, а новое создано. В противном случае, при попытке создать представление с существующим именем, возникнет ошибка. - - ## Зачем нужны представления ### Упрощение сложных запросов @@ -132,21 +162,17 @@ AS select_выражение ### Улучшение производительности - +**MySQL** Создание представлений, которые инкапсулируют сложные запросы, может помочь оптимизировать выполнение этих запросов. Это может привести к более быстрому выполнению запросов и улучшению общей производительности базы данных. - - - +**PostgreSQL** Создание представлений, которые инкапсулируют сложные запросы, может помочь оптимизировать выполнение этих запросов. PostgreSQL поддерживает материализованные представления (`MATERIALIZED VIEW`), которые физически хранят результаты запроса и периодически обновляются, что может значительно улучшить производительность для сложных запросов. - - ### Обеспечение безопасности Представления могут использоваться для обеспечения безопасности конфиденциальных данных. @@ -159,3 +185,11 @@ PostgreSQL поддерживает материализованные пред Представления являются важным инструментом в SQL, который позволяет упростить сложные запросы, стандартизировать доступ к данным, повысить производительность и обеспечить безопасность данных. Давайте проверим, как вы усвоили тему: выберите правильное утверждение на вопрос «Что такое представление в базе данных?» + +1. **Правильный ответ:** Виртуальная таблица, которая не хранит данные, а извлекает их из других таблиц при обращении. — Представление в базе данных действительно является виртуальной таблицей, которая не хранит данные самостоятельно, а извлекает их из других таблиц при обращении. + +2. Физическая таблица, которая хранит данные постоянно. — Нет, представление не является физической таблицей, которая хранит данные постоянно. Оно является виртуальной таблицей, которая извлекает данные из других таблиц при обращении. Представления не хранят данные сами по себе, а предоставляют доступ к данным, уже хранящимся в других таблицах. + +3. Интерфейс для прямого доступа пользователей к базе данных. — Нет, представление не является интерфейсом для прямого доступа пользователей к базе данных. Оно скрывает детали реализации и предоставляет упрощённый интерфейс доступа к данным. Пользователи обращаются к представлению, а не к базе данных напрямую. + +4. Временная таблица, используемая для манипуляции данными. — Нет, представление не является временной таблицей, используемой для манипуляции данными. Оно представляет собой виртуальную таблицу, которая извлекает данные из других таблиц при обращении. Представления используются не для изменения данных, а для предоставления удобного доступа к ним. diff --git a/interviewQuestions/1/ru.mdx b/interviewQuestions/1/ru.mdx index e22b489..9dd1e6f 100644 --- a/interviewQuestions/1/ru.mdx +++ b/interviewQuestions/1/ru.mdx @@ -1,14 +1,14 @@ --- meta: - title: 'Что такое SQL и для чего он используется?' - description: 'SQL — это язык для работы с реляционными базами данных, который позволяет создавать таблицы, управлять данными и выполнять ключевые операции с ними.' + title: "Что такое SQL и для чего он используется?" + description: "SQL — это язык для работы с реляционными базами данных, который позволяет создавать таблицы, управлять данными и выполнять ключевые операции с ними." --- > SQL (Structured Query Language) — это стандартный язык для взаимодействия с реляционными базами данных. Он используется для определения, управления и извлечения данных из баз данных. С помощью SQL можно выполнять следующие операции: -- Создание новых баз данных и таблиц -- Вставка новых данных в таблицы -- Чтение данных с использованием запросов -- Обновление существующих данных -- Удаление данных -- Управление доступом и разрешениями +- Создание новых баз данных и таблиц +- Вставка новых данных в таблицы +- Чтение данных с использованием запросов +- Обновление существующих данных +- Удаление данных +- Управление доступом и разрешениями diff --git a/interviewQuestions/10/ru.mdx b/interviewQuestions/10/ru.mdx index 564ee09..0f2c7eb 100644 --- a/interviewQuestions/10/ru.mdx +++ b/interviewQuestions/10/ru.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'Каковы основные различия между DELETE и TRUNCATE?' - description: 'DELETE удаляет отдельные записи с условием WHERE, TRUNCATE — все записи таблицы без возможности восстановления. Узнайте ключевые различия между этими командами.' + title: "Каковы основные различия между DELETE и TRUNCATE?" + description: "DELETE удаляет отдельные записи с условием WHERE, TRUNCATE — все записи таблицы без возможности восстановления. Узнайте ключевые различия между этими командами." --- ## DELETE: -- Удаляет выбранные записи из таблицы. -- Можно использовать условие `WHERE` для удаления конкретных записей. -- Операция записывается в журнал транзакций построчно. -- Триггеры `ON DELETE` срабатывают. -- Медленнее по сравнению с `TRUNCATE`. +- Удаляет выбранные записи из таблицы. +- Можно использовать условие `WHERE` для удаления конкретных записей. +- Операция записывается в журнал транзакций построчно. +- Триггеры `ON DELETE` срабатывают. +- Медленнее по сравнению с `TRUNCATE`. Пример: @@ -20,14 +20,16 @@ DELETE FROM employees WHERE salary < 30000; ## TRUNCATE: -- Удаляет все записи из таблицы без возможности восстановления через `ROLLBACK` (в большинстве СУБД). -- Нельзя использовать `WHERE`. -- Операция быстрее, так как не логируется построчно. -- Сбрасывает идентификаторы (если используется автоинкремент). -- Триггеры не срабатывают. +- Удаляет все записи из таблицы без возможности восстановления через `ROLLBACK` (в большинстве СУБД). +- Нельзя использовать `WHERE`. +- Операция быстрее, так как не логируется построчно. +- Сбрасывает идентификаторы (если используется автоинкремент). +- Триггеры не срабатывают. Пример: ```sql TRUNCATE TABLE employees; ``` + +Подробный разбор темы с примерами — в статье [«TRUNCATE, DELETE и DROP: в чём разница и что выбрать»](https://sql-academy.org/ru/blog/sql-truncate-delete-drop). diff --git a/interviewQuestions/11/ru.mdx b/interviewQuestions/11/ru.mdx index 970a34c..5f87b81 100644 --- a/interviewQuestions/11/ru.mdx +++ b/interviewQuestions/11/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое транзакция и какие свойства транзакции (ACID)?' - description: 'Транзакция в SQL — это последовательность операций, обладающая свойствами ACID: атомарность, согласованность, изоляция и долговечность. Узнайте о их значении.' + title: "Что такое транзакция и какие свойства транзакции (ACID)?" + description: "Транзакция в SQL — это последовательность операций, обладающая свойствами ACID: атомарность, согласованность, изоляция и долговечность. Узнайте о их значении." --- > **Транзакция** — это последовательность операций, выполняемых как единое логическое действие, которое должно быть полностью выполнено или полностью отменено. @@ -10,20 +10,22 @@ meta: **Атомарность (Atomicity):** -- Транзакция выполняется полностью или не выполняется вовсе. -- Если происходит сбой, все изменения отменяются. +- Транзакция выполняется полностью или не выполняется вовсе. +- Если происходит сбой, все изменения отменяются. **Согласованность (Consistency):** -- Транзакция переводит базу данных из одного согласованного состояния в другое. -- Все правила и ограничения базы данных соблюдаются. +- Транзакция переводит базу данных из одного согласованного состояния в другое. +- Все правила и ограничения базы данных соблюдаются. **Изоляция (Isolation):** -- Результаты транзакции невидимы для других транзакций до ее завершения. -- Предотвращает взаимное влияние параллельных транзакций. +- Результаты транзакции невидимы для других транзакций до ее завершения. +- Предотвращает взаимное влияние параллельных транзакций. **Долговечность (Durability):** -- После успешного завершения транзакции ее результаты сохраняются даже при сбоях системы. -- Изменения записываются на постоянное хранилище. +- После успешного завершения транзакции ее результаты сохраняются даже при сбоях системы. +- Изменения записываются на постоянное хранилище. + +Подробный разбор темы с примерами — в статье [«Что такое ACID: 4 свойства транзакций простыми словами»](https://sql-academy.org/ru/blog/sql-acid). diff --git a/interviewQuestions/12/ru.mdx b/interviewQuestions/12/ru.mdx index a869335..dfc9cdd 100644 --- a/interviewQuestions/12/ru.mdx +++ b/interviewQuestions/12/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое триггеры в SQL?' - description: 'Триггеры в SQL — это процедуры, автоматически выполняемые при операциях INSERT, UPDATE или DELETE. Узнайте о типах триггеров и их применении в базах данных.' + title: "Что такое триггеры в SQL?" + description: "Триггеры в SQL — это процедуры, автоматически выполняемые при операциях INSERT, UPDATE или DELETE. Узнайте о типах триггеров и их применении в базах данных." --- > **Триггер** — это хранимая процедура, которая автоматически выполняется при наступлении определенного @@ -9,15 +9,15 @@ meta: ## Типы триггеров: -- DML триггеры: реагируют на операции `INSERT`, `UPDATE`, `DELETE`. -- DDL триггеры: реагируют на операции `CREATE`, `ALTER`, `DROP`. -- Триггеры уровня строки или оператора. +- DML триггеры: реагируют на операции `INSERT`, `UPDATE`, `DELETE`. +- DDL триггеры: реагируют на операции `CREATE`, `ALTER`, `DROP`. +- Триггеры уровня строки или оператора. ## Преимущества триггеров: -- Автоматизация проверок и ограничений. -- Логирование изменений. -- Поддержание целостности данных. +- Автоматизация проверок и ограничений. +- Логирование изменений. +- Поддержание целостности данных. ## Пример создания триггера: diff --git a/interviewQuestions/13/ru.mdx b/interviewQuestions/13/ru.mdx index 930f28b..74eab84 100644 --- a/interviewQuestions/13/ru.mdx +++ b/interviewQuestions/13/ru.mdx @@ -1,17 +1,17 @@ --- meta: - title: 'Объясните, что такое VIEW и его преимущества' - description: 'VIEW в SQL — это виртуальная таблица, основанная на запросе. Узнайте, как представления упрощают запросы, повышают безопасность и поддерживают целостность данных.' + title: "Объясните, что такое VIEW и его преимущества" + description: "VIEW в SQL — это виртуальная таблица, основанная на запросе. Узнайте, как представления упрощают запросы, повышают безопасность и поддерживают целостность данных." --- > **VIEW (представление)** — это виртуальная таблица, основанная на результате SQL-запроса. Представление не хранит данные самостоятельно, а предоставляет определенный способ просмотра данных из одной или нескольких таблиц. ## Преимущества VIEW: -- **Упрощение сложных запросов**: позволяет сохранить сложный запрос и использовать его как простую таблицу. -- **Безопасность**: предоставляет пользователям доступ только к определенным данным, скрывая остальные. -- **Обновляемость**: в некоторых случаях можно обновлять данные через представление. -- **Поддержание целостности данных**: может содержать данные из нескольких таблиц, объединенные определенным образом. +- **Упрощение сложных запросов**: позволяет сохранить сложный запрос и использовать его как простую таблицу. +- **Безопасность**: предоставляет пользователям доступ только к определенным данным, скрывая остальные. +- **Обновляемость**: в некоторых случаях можно обновлять данные через представление. +- **Поддержание целостности данных**: может содержать данные из нескольких таблиц, объединенные определенным образом. ## Пример создания VIEW: diff --git a/interviewQuestions/14/ru.mdx b/interviewQuestions/14/ru.mdx index e56f4bb..dd2c6c1 100644 --- a/interviewQuestions/14/ru.mdx +++ b/interviewQuestions/14/ru.mdx @@ -1,14 +1,14 @@ --- meta: - title: 'Как использовать оператор LIKE и для чего он применяется?' - description: 'Оператор LIKE в SQL используется для поиска строк по шаблону с помощью символов % и _. Узнайте, как применять LIKE для фильтрации данных.' + title: "Как использовать оператор LIKE и для чего он применяется?" + description: "Оператор LIKE в SQL используется для поиска строк по шаблону с помощью символов % и _. Узнайте, как применять LIKE для фильтрации данных." --- Оператор `LIKE` используется в условиях `WHERE` для поиска строк, соответствующих определенному шаблону. В шаблонах используются подстановочные символы: -- `%` — соответствует любой последовательности символов (включая нулевую длину). -- `_` — соответствует одному любому символу. +- `%` — соответствует любой последовательности символов (включая нулевую длину). +- `_` — соответствует одному любому символу. ## Примеры использования: diff --git a/interviewQuestions/15/ru.mdx b/interviewQuestions/15/ru.mdx index f252b3c..70ff861 100644 --- a/interviewQuestions/15/ru.mdx +++ b/interviewQuestions/15/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое агрегатные функции? Приведите примеры' - description: 'Агрегатные функции в SQL вычисляют значения для набора строк. Узнайте, как использовать COUNT, SUM, AVG, MAX и MIN для анализа данных.' + title: "Что такое агрегатные функции? Приведите примеры" + description: "Агрегатные функции в SQL вычисляют значения для набора строк. Узнайте, как использовать COUNT, SUM, AVG, MAX и MIN для анализа данных." --- Агрегатные функции выполняют вычисления над набором значений и возвращают одно значение. @@ -9,11 +9,11 @@ meta: ## Основные агрегатные функции -- `COUNT()` — подсчитывает количество строк. -- `SUM()` — вычисляет сумму значений. -- `AVG()` — вычисляет среднее значение. -- `MAX()` — находит максимальное значение. -- `MIN()` — находит минимальное значение. +- `COUNT()` — подсчитывает количество строк. +- `SUM()` — вычисляет сумму значений. +- `AVG()` — вычисляет среднее значение. +- `MAX()` — находит максимальное значение. +- `MIN()` — находит минимальное значение. ## Примеры использования diff --git a/interviewQuestions/16/ru.mdx b/interviewQuestions/16/ru.mdx index 8355343..f91ed32 100644 --- a/interviewQuestions/16/ru.mdx +++ b/interviewQuestions/16/ru.mdx @@ -1,13 +1,13 @@ --- meta: - title: 'Объясните разницу между UNION и UNION ALL' - description: 'UNION в SQL объединяет результаты запросов с удалением дубликатов, UNION ALL сохраняет дубликаты и работает быстрее. Узнайте ключевые различия.' + title: "Объясните разницу между UNION и UNION ALL" + description: "UNION в SQL объединяет результаты запросов с удалением дубликатов, UNION ALL сохраняет дубликаты и работает быстрее. Узнайте ключевые различия." --- ## UNION: -- Объединяет результаты двух или более `SELECT`-запросов. -- Удаляет дубликаты из объединенного результата. +- Объединяет результаты двух или более `SELECT`-запросов. +- Удаляет дубликаты из объединенного результата. Синтаксис @@ -19,9 +19,9 @@ SELECT column_list FROM table2; ## UNION ALL: -- Объединяет результаты двух или более `SELECT`-запросов. -- Сохраняет дубликаты в объединенном результате. -- Быстрее, так как не выполняет дополнительную операцию по удалению дубликатов. +- Объединяет результаты двух или более `SELECT`-запросов. +- Сохраняет дубликаты в объединенном результате. +- Быстрее, так как не выполняет дополнительную операцию по удалению дубликатов. Синтаксис diff --git a/interviewQuestions/17/ru.mdx b/interviewQuestions/17/ru.mdx index 32c89f3..dc6c6c4 100644 --- a/interviewQuestions/17/ru.mdx +++ b/interviewQuestions/17/ru.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'Что такое хранимая процедура и как она отличается от функции?' - description: 'Хранимая процедура выполняет набор команд в SQL, а функция возвращает значение и может использоваться в запросах. Узнайте ключевые различия между ними.' + title: "Что такое хранимая процедура и как она отличается от функции?" + description: "Хранимая процедура выполняет набор команд в SQL, а функция возвращает значение и может использоваться в запросах. Узнайте ключевые различия между ними." --- ## Хранимая процедура (Stored Procedure): -- Набор SQL-команд, сохраненных на сервере для повторного использования. -- Может выполнять операции `SELECT`, `INSERT`, `UPDATE`, `DELETE`. -- Может возвращать несколько наборов результатов или ничего не возвращать. -- Может иметь входные и выходные параметры. -- Не может быть вызвана внутри SQL-запроса. +- Набор SQL-команд, сохраненных на сервере для повторного использования. +- Может выполнять операции `SELECT`, `INSERT`, `UPDATE`, `DELETE`. +- Может возвращать несколько наборов результатов или ничего не возвращать. +- Может иметь входные и выходные параметры. +- Не может быть вызвана внутри SQL-запроса. Пример хранимой процедуры: @@ -29,10 +29,10 @@ CALL GetEmployeeByID(1); ## Функция (Function): -- Возвращает одно значение (скалярная функция) или таблицу (табличная функция). -- Может использоваться в SQL-выражениях (например, в SELECT или WHERE). -- Должна возвращать значение. -- Обычно используется для вычислений и возвращает детерминированный результат. +- Возвращает одно значение (скалярная функция) или таблицу (табличная функция). +- Может использоваться в SQL-выражениях (например, в SELECT или WHERE). +- Должна возвращать значение. +- Обычно используется для вычислений и возвращает детерминированный результат. Пример функции: diff --git a/interviewQuestions/18/ru.mdx b/interviewQuestions/18/ru.mdx index 58ba74a..68b293c 100644 --- a/interviewQuestions/18/ru.mdx +++ b/interviewQuestions/18/ru.mdx @@ -1,36 +1,38 @@ --- meta: - title: 'Как оптимизировать производительность SQL-запросов?' - description: 'Оптимизация SQL-запросов включает использование индексов, избегание SELECT *, оптимизацию JOIN и WHERE, ограничение результатов и анализ плана выполнения запросов.' + title: "Как оптимизировать производительность SQL-запросов?" + description: "Оптимизация SQL-запросов включает использование индексов, избегание SELECT *, оптимизацию JOIN и WHERE, ограничение результатов и анализ плана выполнения запросов." --- **Использовать индексы:** -- Создавайте индексы на столбцах, часто используемых в условиях `WHERE`, `JOIN` и `ORDER BY`. -- Избегайте избыточных индексов. +- Создавайте индексы на столбцах, часто используемых в условиях `WHERE`, `JOIN` и `ORDER BY`. +- Избегайте избыточных индексов. **Избегать `SELECT *`:** -- Выбирайте только необходимые столбцы. -- Уменьшает объем передаваемых данных. +- Выбирайте только необходимые столбцы. +- Уменьшает объем передаваемых данных. **Оптимизировать условия `JOIN` и `WHERE`:** -- Используйте равенство (=) вместо неравенства, где возможно. -- Избегайте функций и вычислений над индексируемыми столбцами в условиях. +- Используйте равенство (=) вместо неравенства, где возможно. +- Избегайте функций и вычислений над индексируемыми столбцами в условиях. **Использовать ограничения результатов (`LIMIT`):** -- Ограничивайте количество возвращаемых строк, если не нужны все данные. +- Ограничивайте количество возвращаемых строк, если не нужны все данные. **Избегать подзапросов, где возможны соединения:** -- Заменяйте коррелированные подзапросы на `JOIN` или `EXISTS`. +- Заменяйте коррелированные подзапросы на `JOIN` или `EXISTS`. **Кеширование часто используемых данных:** -- Используйте материализованные представления или кеширование на уровне приложения. +- Используйте материализованные представления или кеширование на уровне приложения. **Профилирование и анализ запросов:** -- Используйте инструменты (`EXPLAIN`, `EXPLAIN PLAN`) для анализа плана выполнения запросов. +- Используйте инструменты (`EXPLAIN`, `EXPLAIN PLAN`) для анализа плана выполнения запросов. + +Подробный разбор темы с примерами — в статье [«Оптимизация SQL-запросов: 10 способов ускорить медленный запрос»](https://sql-academy.org/ru/blog/sql-query-optimization). diff --git a/interviewQuestions/19/ru.mdx b/interviewQuestions/19/ru.mdx index 51a44e6..747bd1b 100644 --- a/interviewQuestions/19/ru.mdx +++ b/interviewQuestions/19/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое ограничения (constraints) и какие виды существуют?' - description: 'Ограничения в SQL обеспечивают целостность данных. Узнайте о NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK и DEFAULT для надежности данных в таблицах.' + title: "Что такое ограничения (constraints) и какие виды существуют?" + description: "Ограничения в SQL обеспечивают целостность данных. Узнайте о NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK и DEFAULT для надежности данных в таблицах." --- **Ограничения** обеспечивают целостность и надежность данных в таблице, определяя правила для данных в столбцах. @@ -10,7 +10,7 @@ meta: **NOT NULL:** -- Запрещает хранение `NULL` значений в столбце. +- Запрещает хранение `NULL` значений в столбце. Пример: @@ -23,7 +23,7 @@ CREATE TABLE products ( **UNIQUE:** -- Обеспечивает уникальность значений в столбце или группе столбцов. +- Обеспечивает уникальность значений в столбце или группе столбцов. Пример: @@ -36,13 +36,13 @@ CREATE TABLE users ( **PRIMARY KEY:** -- Комбинация `NOT NULL` и `UNIQUE`. -- Идентифицирует каждую запись в таблице. +- Комбинация `NOT NULL` и `UNIQUE`. +- Идентифицирует каждую запись в таблице. **FOREIGN KEY:** -- Обеспечивает ссылочную целостность между таблицами. -- Значение должно соответствовать существующему значению первичного ключа в связанной таблице. +- Обеспечивает ссылочную целостность между таблицами. +- Значение должно соответствовать существующему значению первичного ключа в связанной таблице. Пример: @@ -56,7 +56,7 @@ CREATE TABLE orders ( **CHECK:** -- Определяет условие, которому должны соответствовать значения в столбце. +- Определяет условие, которому должны соответствовать значения в столбце. Пример: @@ -69,7 +69,7 @@ CREATE TABLE employees ( **DEFAULT:** -- Устанавливает значение по умолчанию для столбца, если значение не указано при вставке. +- Устанавливает значение по умолчанию для столбца, если значение не указано при вставке. ```sql CREATE TABLE tasks ( diff --git a/interviewQuestions/2/ru.mdx b/interviewQuestions/2/ru.mdx index 3455b77..85c7e99 100644 --- a/interviewQuestions/2/ru.mdx +++ b/interviewQuestions/2/ru.mdx @@ -1,22 +1,23 @@ --- meta: - title: 'Объясните различия между DDL, DML и DCL в SQL?' - description: 'Узнайте различия между DDL, DML и DCL в SQL: определение структуры базы данных, манипуляция данными и управление правами доступа.' + title: "Объясните различия между DDL, DML и DCL в SQL?" + seoTitle: "DDL, DML и DCL в SQL: в чём разница — ответ с собеседования" + description: "Узнайте различия между DDL, DML и DCL в SQL: определение структуры базы данных, манипуляция данными и управление правами доступа." --- SQL-команды разделяются на три основные категории: DDL (Data Definition Language) — язык определения данных: -- Используется для определения структуры базы данных (схемы). -- Основные команды: `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `RENAME`. +- Используется для определения структуры базы данных (схемы). +- Основные команды: `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `RENAME`. DML (Data Manipulation Language) — язык манипулирования данными: -- Используется для работы с данными внутри таблиц. -- Основные команды: `SELECT`, `INSERT`, `UPDATE`, `DELETE`. +- Используется для работы с данными внутри таблиц. +- Основные команды: `SELECT`, `INSERT`, `UPDATE`, `DELETE`. DCL (Data Control Language) — язык управления доступом: -- Используется для управления правами доступа к базе данных. -- Основные команды: `GRANT`, `REVOKE`. +- Используется для управления правами доступа к базе данных. +- Основные команды: `GRANT`, `REVOKE`. diff --git a/interviewQuestions/20/ru.mdx b/interviewQuestions/20/ru.mdx index 830b066..72a3c02 100644 --- a/interviewQuestions/20/ru.mdx +++ b/interviewQuestions/20/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое SQL-инъекция и как от нее защититься?' - description: 'SQL-инъекция — это метод атаки на базы данных. Узнайте, как защититься с помощью параметризированных запросов, ORM, валидации данных и ограничений прав доступа.' + title: "Что такое SQL-инъекция и как от нее защититься?" + description: "SQL-инъекция — это метод атаки на базы данных. Узнайте, как защититься с помощью параметризированных запросов, ORM, валидации данных и ограничений прав доступа." --- > **SQL-инъекция** — это метод атаки на базу данных, при котором злоумышленник вставляет @@ -9,16 +9,16 @@ meta: ## Последствия SQL-инъекции: -- Кража данных. -- Удаление или изменение данных. -- Получение административного доступа. +- Кража данных. +- Удаление или изменение данных. +- Получение административного доступа. ## Способы защиты от SQL-инъекций: **1. Параметризированные запросы (Prepared Statements):** -- Использование параметров вместо конкатенации строк. -- СУБД автоматически экранирует специальные символы. +- Использование параметров вместо конкатенации строк. +- СУБД автоматически экранирует специальные символы. Пример (на языке Java с использованием JDBC) @@ -32,19 +32,19 @@ ResultSet rs = stmt.executeQuery(); **2. Использование ORM (Object-Relational Mapping):** -- Библиотеки ORM часто включают механизмы защиты от SQL-инъекций. +- Библиотеки ORM часто включают механизмы защиты от SQL-инъекций. **3. Проверка и фильтрация вводимых данных:** -- Проверять данные на соответствие ожидаемому формату. -- Использовать валидацию на стороне сервера и клиента. +- Проверять данные на соответствие ожидаемому формату. +- Использовать валидацию на стороне сервера и клиента. **4. Ограничение прав доступа:** -- Предоставлять минимально необходимые права пользователям базы данных. -- Ограничить доступ к системным таблицам и операциям. +- Предоставлять минимально необходимые права пользователям базы данных. +- Ограничить доступ к системным таблицам и операциям. **5. Использование хранимых процедур:** -- Логика работы с данными инкапсулирована в процедуре. -- Пользователи имеют доступ только к процедурам, а не к таблицам напрямую. +- Логика работы с данными инкапсулирована в процедуре. +- Пользователи имеют доступ только к процедурам, а не к таблицам напрямую. diff --git a/interviewQuestions/21/ru.mdx b/interviewQuestions/21/ru.mdx index 344e146..3fe0be2 100644 --- a/interviewQuestions/21/ru.mdx +++ b/interviewQuestions/21/ru.mdx @@ -1,20 +1,20 @@ --- meta: - title: 'Что такое реляционная база данных?' - description: 'Реляционная база данных хранит данные в таблицах и использует ключи для установления связей между ними. Узнайте о преимуществах и характеристиках реляционных баз данных.' + title: "Что такое реляционная база данных?" + description: "Реляционная база данных хранит данные в таблицах и использует ключи для установления связей между ними. Узнайте о преимуществах и характеристиках реляционных баз данных." --- > **Реляционная база данных** — это база данных, основанная на реляционной модели данных. В такой базе данных данные хранятся в таблицах, и отношения между данными определяются с помощью ключей. ## Основные характеристики: -- Таблицы (отношения): данные организованы в таблицы, состоящие из строк и столбцов. -- Строки (записи): каждая строка представляет отдельную запись. -- Столбцы (атрибуты): каждый столбец содержит данные определенного типа. -- Ключи: используются для идентификации записей и установления связей между таблицами. +- Таблицы (отношения): данные организованы в таблицы, состоящие из строк и столбцов. +- Строки (записи): каждая строка представляет отдельную запись. +- Столбцы (атрибуты): каждый столбец содержит данные определенного типа. +- Ключи: используются для идентификации записей и установления связей между таблицами. ## Преимущества реляционных баз данных: -- Гибкость: легко добавлять новые таблицы и столбцы. -- Целостность данных: использование ограничений для поддержания целостности. -- SQL: стандартный язык для управления данными. +- Гибкость: легко добавлять новые таблицы и столбцы. +- Целостность данных: использование ограничений для поддержания целостности. +- SQL: стандартный язык для управления данными. diff --git a/interviewQuestions/22/ru.mdx b/interviewQuestions/22/ru.mdx index e14c57d..7b28999 100644 --- a/interviewQuestions/22/ru.mdx +++ b/interviewQuestions/22/ru.mdx @@ -1,13 +1,13 @@ --- meta: - title: 'Объясните разницу между INNER JOIN и OUTER JOIN' - description: 'INNER JOIN возвращает только совпадающие записи из обеих таблиц, тогда как OUTER JOIN включает все записи, даже если нет соответствий. Узнайте ключевые различия.' + title: "Объясните разницу между INNER JOIN и OUTER JOIN" + description: "INNER JOIN возвращает только совпадающие записи из обеих таблиц, тогда как OUTER JOIN включает все записи, даже если нет соответствий. Узнайте ключевые различия." --- ## INNER JOIN: -- Возвращает только те записи, у которых есть соответствующие записи в обеих объединяемых таблицах. -- Если соответствия нет, запись не включается в результат. +- Возвращает только те записи, у которых есть соответствующие записи в обеих объединяемых таблицах. +- Если соответствия нет, запись не включается в результат. Пример: @@ -19,14 +19,14 @@ INNER JOIN departments d ON e.department_id = d.id; ## OUTER JOIN: -- Возвращает записи, которые имеют соответствия, а также записи из одной таблицы, для которых соответствий нет. +- Возвращает записи, которые имеют соответствия, а также записи из одной таблицы, для которых соответствий нет. ### Виды OUTER JOIN: **LEFT OUTER JOIN (LEFT JOIN):** -- Возвращает все записи из левой таблицы и соответствующие записи из правой таблицы. -- Если соответствия нет, столбцы правой таблицы будут `NULL`. +- Возвращает все записи из левой таблицы и соответствующие записи из правой таблицы. +- Если соответствия нет, столбцы правой таблицы будут `NULL`. Пример: @@ -38,8 +38,8 @@ LEFT JOIN departments d ON e.department_id = d.id; **RIGHT OUTER JOIN (RIGHT JOIN):** -- Возвращает все записи из правой таблицы и соответствующие записи из левой таблицы. -- Если соответствия нет, столбцы левой таблицы будут `NULL`. +- Возвращает все записи из правой таблицы и соответствующие записи из левой таблицы. +- Если соответствия нет, столбцы левой таблицы будут `NULL`. Пример: @@ -51,8 +51,8 @@ RIGHT JOIN departments d ON e.department_id = d.id; **FULL OUTER JOIN (FULL JOIN):** -- Возвращает все записи, когда есть соответствие в одной из таблиц. -- Если соответствия нет, соответствующие столбцы будут `NULL`. +- Возвращает все записи, когда есть соответствие в одной из таблиц. +- Если соответствия нет, соответствующие столбцы будут `NULL`. ```sql SELECT * diff --git a/interviewQuestions/23/ru.mdx b/interviewQuestions/23/ru.mdx index 661044d..d9a6749 100644 --- a/interviewQuestions/23/ru.mdx +++ b/interviewQuestions/23/ru.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'Что такое NULL и как с ним работать в SQL?' - description: 'NULL в SQL обозначает отсутствие данных. Узнайте, как работать с NULL с помощью операторов IS NULL, IS NOT NULL и функций COALESCE, ISNULL, IFNULL.' + title: "Что такое NULL и как с ним работать в SQL?" + description: "NULL в SQL обозначает отсутствие данных. Узнайте, как работать с NULL с помощью операторов IS NULL, IS NOT NULL и функций COALESCE, ISNULL, IFNULL." --- > **NULL** — это специальное значение в SQL, обозначающее отсутствие данных или неизвестное значение. ## Особенности NULL: -- `NULL` не эквивалентно пустой строке или нулю. -- Операции с `NULL` возвращают `NULL`. -- Сравнение `NULL` = `NULL` возвращает `FALSE`. +- `NULL` не эквивалентно пустой строке или нулю. +- Операции с `NULL` возвращают `NULL`. +- Сравнение `NULL` = `NULL` возвращает `FALSE`. ## Работа с NULL @@ -26,30 +26,35 @@ SELECT * FROM employees WHERE birth_date IS NOT NULL; ## Функции для работы с NULL -- - **COALESCE** - +- + **COALESCE** + + Возвращает первый элемент списка, не равный `NULL` ```sql COALESCE(val1[, val2, ...., val_n]) ``` -- - **ISNULL** - +- + **ISNULL** + + Возвращает 1 или 0 в зависимости от того, равно ли выражение `NULL` ```sql ISNULL(value) ``` -- - **IFNULL** - - Возвращает значение, переданное 1-ым аргументом, если оно не равно `NULL`. В противном случае возвращает значение, переданное - вторым аргументом. +- + **IFNULL** + + + Возвращает значение, переданное 1-ым аргументом, если оно не равно `NULL`. В противном + случае возвращает значение, переданное вторым аргументом. ```sql IFNULL(value, alternative_value) ``` + +Подробный разбор темы с примерами — в статье [«COALESCE в SQL: замена NULL и связка с NULLIF»](https://sql-academy.org/ru/blog/sql-coalesce). diff --git a/interviewQuestions/24/ru.mdx b/interviewQuestions/24/ru.mdx index 4cae531..f47d526 100644 --- a/interviewQuestions/24/ru.mdx +++ b/interviewQuestions/24/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Как использовать оператор CASE в SQL?' - description: 'Оператор CASE в SQL используется для условной логики в запросах. Узнайте, как применять CASE для присвоения значений на основе условий.' + title: "Как использовать оператор CASE в SQL?" + description: "Оператор CASE в SQL используется для условной логики в запросах. Узнайте, как применять CASE для присвоения значений на основе условий." --- Оператор `CASE` используется для реализации условной логики в SQL-запросах. @@ -18,7 +18,7 @@ END ## Примеры -- Присвоение категорий на основе зарплаты: +- Присвоение категорий на основе зарплаты: ```sql SELECT name, salary, diff --git a/interviewQuestions/25/ru.mdx b/interviewQuestions/25/ru.mdx index 447cd93..3b00a79 100644 --- a/interviewQuestions/25/ru.mdx +++ b/interviewQuestions/25/ru.mdx @@ -1,14 +1,14 @@ --- meta: - title: 'Объясните транзакционные команды COMMIT и ROLLBACK.' - description: 'COMMIT фиксирует транзакцию, делая изменения постоянными, ROLLBACK отменяет изменения, возвращая базу данных в исходное состояние. Узнайте, как управлять транзакциями.' + title: "Объясните транзакционные команды COMMIT и ROLLBACK." + description: "COMMIT фиксирует транзакцию, делая изменения постоянными, ROLLBACK отменяет изменения, возвращая базу данных в исходное состояние. Узнайте, как управлять транзакциями." --- ## COMMIT -- Фиксирует текущую транзакцию. -- Все изменения, сделанные в транзакции, становятся постоянными и видимыми для других пользователей. -- После COMMIT отменить изменения нельзя. +- Фиксирует текущую транзакцию. +- Все изменения, сделанные в транзакции, становятся постоянными и видимыми для других пользователей. +- После COMMIT отменить изменения нельзя. ```sql BEGIN TRANSACTION; @@ -21,9 +21,9 @@ COMMIT; ## ROLLBACK -- Отменяет текущую транзакцию. -- Все изменения, сделанные в транзакции, откатываются. -- База данных возвращается в состояние до начала транзакции. +- Отменяет текущую транзакцию. +- Все изменения, сделанные в транзакции, откатываются. +- База данных возвращается в состояние до начала транзакции. ```sql BEGIN TRANSACTION; @@ -36,6 +36,6 @@ ROLLBACK; ## Использование в управлении транзакциями: -- `BEGIN TRANSACTION` или `START TRANSACTION`: начало транзакции. -- `COMMIT`: фиксация транзакции -- `ROLLBACK`: откат транзакции. +- `BEGIN TRANSACTION` или `START TRANSACTION`: начало транзакции. +- `COMMIT`: фиксация транзакции +- `ROLLBACK`: откат транзакции. diff --git a/interviewQuestions/26/ru.mdx b/interviewQuestions/26/ru.mdx index 556c59b..484432c 100644 --- a/interviewQuestions/26/ru.mdx +++ b/interviewQuestions/26/ru.mdx @@ -1,32 +1,32 @@ --- meta: - title: 'Объясните различия между CHAR и VARCHAR' - description: 'CHAR хранит строки фиксированной длины, а VARCHAR — переменной. Узнайте, как выбирать между CHAR и VARCHAR в зависимости от данных и использования памяти.' + title: "Объясните различия между CHAR и VARCHAR" + description: "CHAR хранит строки фиксированной длины, а VARCHAR — переменной. Узнайте, как выбирать между CHAR и VARCHAR в зависимости от данных и использования памяти." --- ## CHAR(n): -- Хранит строки фиксированной длины `n`. -- Если введенная строка короче `n`, она дополняется пробелами до длины `n`. -- Используется для хранения данных одинаковой длины (например, коды стран, почтовые индексы). +- Хранит строки фиксированной длины `n`. +- Если введенная строка короче `n`, она дополняется пробелами до длины `n`. +- Используется для хранения данных одинаковой длины (например, коды стран, почтовые индексы). ## VARCHAR(n): -- Хранит строки переменной длины до `n` символов. -- Фактически занимает столько места, сколько символов в строке, плюс небольшой служебный объем для хранения длины. -- Используется для хранения строковых данных переменной длины. +- Хранит строки переменной длины до `n` символов. +- Фактически занимает столько места, сколько символов в строке, плюс небольшой служебный объем для хранения длины. +- Используется для хранения строковых данных переменной длины. ## Основные различия: Память и производительность: -- `CHAR` всегда занимает фиксированное количество памяти. -- `VARCHAR` более эффективен с точки зрения использования памяти, но может быть немного медленнее при доступе. +- `CHAR` всегда занимает фиксированное количество памяти. +- `VARCHAR` более эффективен с точки зрения использования памяти, но может быть немного медленнее при доступе. Применение: -- `CHAR` подходит для данных с предсказуемой длиной. -- `VARCHAR` подходит для данных переменной длины. +- `CHAR` подходит для данных с предсказуемой длиной. +- `VARCHAR` подходит для данных переменной длины. Пример: diff --git a/interviewQuestions/27/ru.mdx b/interviewQuestions/27/ru.mdx index 8dd0f85..b77f4fc 100644 --- a/interviewQuestions/27/ru.mdx +++ b/interviewQuestions/27/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое временная таблица в SQL?' - description: 'Временная таблица в SQL существует только в рамках сессии и автоматически удаляется после ее завершения. Узнайте, как создавать и использовать временные таблицы.' + title: "Что такое временная таблица в SQL?" + description: "Временная таблица в SQL существует только в рамках сессии и автоматически удаляется после ее завершения. Узнайте, как создавать и использовать временные таблицы." --- > **Временная таблица** — это таблица, которая существует только в рамках текущей сессии @@ -31,6 +31,6 @@ SELECT * FROM #TempTable; ## Применение временной таблицы -- Хранение промежуточных результатов в сложных запросах. -- Обработка больших объемов данных в пакетных операциях. -- Избегание конфликтов при одновременной работе нескольких пользователей. +- Хранение промежуточных результатов в сложных запросах. +- Обработка больших объемов данных в пакетных операциях. +- Избегание конфликтов при одновременной работе нескольких пользователей. diff --git a/interviewQuestions/28/ru.mdx b/interviewQuestions/28/ru.mdx index 3438eec..c3be880 100644 --- a/interviewQuestions/28/ru.mdx +++ b/interviewQuestions/28/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое оконные функции в SQL?' - description: 'Оконные функции в SQL позволяют выполнять вычисления по набору строк без группировки. Узнайте, как использовать SUM, ROW_NUMBER, LAG и другие оконные функции.' + title: "Что такое оконные функции в SQL?" + description: "Оконные функции в SQL позволяют выполнять вычисления по набору строк без группировки. Узнайте, как использовать SUM, ROW_NUMBER, LAG и другие оконные функции." --- > **Оконные функции** — это функции, которые выполняют вычисления по набору @@ -11,23 +11,25 @@ meta: ### Агрегатные функции: -- `SUM` — подсчитывает общую сумму значений -- `COUNT` — считает общее количество записей в колонке -- `AVG` — рассчитывает среднее арифметическое -- `MAX` — находит наибольшее значение -- `MIN` — определяет наименьшее значение +- `SUM` — подсчитывает общую сумму значений +- `COUNT` — считает общее количество записей в колонке +- `AVG` — рассчитывает среднее арифметическое +- `MAX` — находит наибольшее значение +- `MIN` — определяет наименьшее значение ### Ранжирующие функции: -- `ROW_NUMBER`: присваивает последовательный номер строке в пределах окна -- `RANK`: присваивает ранг строке в пределах окна с пропусками при совпадении значений -- `DENSE_RANK`: присваивает ранг строке без пропусков +- `ROW_NUMBER`: присваивает последовательный номер строке в пределах окна +- `RANK`: присваивает ранг строке в пределах окна с пропусками при совпадении значений +- `DENSE_RANK`: присваивает ранг строке без пропусков ### Функции смещения: -- `LAG`: возвращает значение из предыдущей строки -- `LEAD`: возвращает значение из следующей строки -- `FIRST_VALUE`: возвращает первое значение в окне -- `LAST_VALUE`: возвращает последнее значение в окне +- `LAG`: возвращает значение из предыдущей строки +- `LEAD`: возвращает значение из следующей строки +- `FIRST_VALUE`: возвращает первое значение в окне +- `LAST_VALUE`: возвращает последнее значение в окне Подробное объяснение работы оконных функций есть в нашем курсе. + +Подробный разбор темы с примерами — в статье [«ROW_NUMBER, RANK и DENSE_RANK: отличия на одном примере»](https://sql-academy.org/ru/blog/row-number-rank-dense-rank). diff --git a/interviewQuestions/29/ru.mdx b/interviewQuestions/29/ru.mdx index 041beee..302e909 100644 --- a/interviewQuestions/29/ru.mdx +++ b/interviewQuestions/29/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Объясните понятие CTE (Common Table Expression)' - description: 'CTE (Common Table Expression) — это временный результат набора, улучшающий читаемость и структуру сложных SQL-запросов. Узнайте, как использовать CTE и его преимущества.' + title: "Объясните понятие CTE (Common Table Expression)" + description: "CTE (Common Table Expression) — это временный результат набора, улучшающий читаемость и структуру сложных SQL-запросов. Узнайте, как использовать CTE и его преимущества." --- > **CTE (Common Table Expression)** — это временный именованный результат набора, @@ -22,8 +22,10 @@ SELECT * FROM CTEName; ## Преимущества CTE -- Улучшает читаемость кода. -- Позволяет разбивать сложные запросы на логические части. -- Поддерживает рекурсивные запросы (рекурсивные CTE). +- Улучшает читаемость кода. +- Позволяет разбивать сложные запросы на логические части. +- Поддерживает рекурсивные запросы (рекурсивные CTE). Подробное объяснение работы CTE в нашем курсе. + +Подробный разбор темы с примерами — в статье [«CTE в SQL: что такое Common Table Expression — с рекурсией»](https://sql-academy.org/ru/blog/sql-cte). diff --git a/interviewQuestions/3/ru.mdx b/interviewQuestions/3/ru.mdx index 15d5c42..858f300 100644 --- a/interviewQuestions/3/ru.mdx +++ b/interviewQuestions/3/ru.mdx @@ -1,14 +1,14 @@ --- meta: - title: 'Что такое первичный ключ и внешний ключ?' - description: 'Первичный ключ — уникальный идентификатор записи, внешний ключ — связывает таблицы, поддерживая целостность данных в базе данных.' + title: "Что такое первичный ключ и внешний ключ?" + description: "Первичный ключ — уникальный идентификатор записи, внешний ключ — связывает таблицы, поддерживая целостность данных в базе данных." --- ## Первичный ключ (PRIMARY KEY): -- Уникальный идентификатор записи в таблице. -- Не допускает дубликатов и `NULL` значений. -- Может состоять из одного или нескольких столбцов (составной ключ). +- Уникальный идентификатор записи в таблице. +- Не допускает дубликатов и `NULL` значений. +- Может состоять из одного или нескольких столбцов (составной ключ). ```sql CREATE TABLE students ( @@ -20,9 +20,9 @@ CREATE TABLE students ( ## Внешний ключ (FOREIGN KEY): -- Столбец или набор столбцов, которые ссылаются на первичный ключ другой таблицы. -- Обеспечивает ссылочную целостность между таблицами. -- Позволяет связать записи из разных таблиц. +- Столбец или набор столбцов, которые ссылаются на первичный ключ другой таблицы. +- Обеспечивает ссылочную целостность между таблицами. +- Позволяет связать записи из разных таблиц. ```sql CREATE TABLE enrollments ( diff --git a/interviewQuestions/30/ru.mdx b/interviewQuestions/30/ru.mdx index 5431063..8753093 100644 --- a/interviewQuestions/30/ru.mdx +++ b/interviewQuestions/30/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Как удалить таблицу вместе с ее данными?' - description: 'Команда DROP TABLE в SQL удаляет таблицу вместе с ее данными, индексами и триггерами. Узнайте, как использовать DROP TABLE и его особенности.' + title: "Как удалить таблицу вместе с ее данными?" + description: "Команда DROP TABLE в SQL удаляет таблицу вместе с ее данными, индексами и триггерами. Узнайте, как использовать DROP TABLE и его особенности." --- Для этого используется команда `DROP TABLE`, которая удаляет таблицу и все ее данные из базы данных. @@ -14,5 +14,5 @@ DROP TABLE table_name; ## Особенности: -- Все данные, индексы, триггеры и разрешения, связанные с таблицей, удаляются. -- Действие необратимо, если не настроено резервное копирование или механизмы восстановления. +- Все данные, индексы, триггеры и разрешения, связанные с таблицей, удаляются. +- Действие необратимо, если не настроено резервное копирование или механизмы восстановления. diff --git a/interviewQuestions/31/ru.mdx b/interviewQuestions/31/ru.mdx index 631f641..43f683e 100644 --- a/interviewQuestions/31/ru.mdx +++ b/interviewQuestions/31/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое FOREIGN KEY и как он обеспечивает целостность данных?' - description: 'FOREIGN KEY в SQL устанавливает связь между таблицами и обеспечивает целостность данных, гарантируя, что внешние ключи соответствуют существующим значениям.' + title: "Что такое FOREIGN KEY и как он обеспечивает целостность данных?" + description: "FOREIGN KEY в SQL устанавливает связь между таблицами и обеспечивает целостность данных, гарантируя, что внешние ключи соответствуют существующим значениям." --- > **FOREIGN KEY** (внешний ключ) — это ограничение, которое устанавливает связь между @@ -11,11 +11,11 @@ meta: ## Как обеспечивается целостность данных: -- **Ограничивается вставка некорректных данных** - Невозможно вставить значение в столбец внешнего ключа, если такого значения нет в связанной таблице. +- **Ограничивается вставка некорректных данных** + Невозможно вставить значение в столбец внешнего ключа, если такого значения нет в связанной таблице. -- **Ограничивается удаление связанных записей** - Невозможно удалить запись из родительской таблицы, если на нее ссылаются записи в дочерней таблице, без дополнительных действий. +- **Ограничивается удаление связанных записей** + Невозможно удалить запись из родительской таблицы, если на нее ссылаются записи в дочерней таблице, без дополнительных действий. ### Пример внешнего ключа: diff --git a/interviewQuestions/32/ru.mdx b/interviewQuestions/32/ru.mdx index 871f3ca..62fde05 100644 --- a/interviewQuestions/32/ru.mdx +++ b/interviewQuestions/32/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Как добавить новый столбец в существующую таблицу?' - description: 'Команда ALTER TABLE с оператором ADD позволяет добавить новый столбец в существующую таблицу. Узнайте, как добавить столбец с типом данных и ограничениями.' + title: "Как добавить новый столбец в существующую таблицу?" + description: "Команда ALTER TABLE с оператором ADD позволяет добавить новый столбец в существующую таблицу. Узнайте, как добавить столбец с типом данных и ограничениями." --- Для этого используется команда `ALTER TABLE` с оператором `ADD` для добавления нового столбца в таблицу. @@ -29,6 +29,6 @@ ALTER TABLE employees ADD date_of_birth DATE NOT NULL DEFAULT '1900-01-01'; ``` -**Особенность** +**Особенность**\ При добавлении столбца с ограничением `NOT NULL`, если в таблице уже есть данные, необходимо указать значение по умолчанию, иначе будет ошибка. diff --git a/interviewQuestions/33/ru.mdx b/interviewQuestions/33/ru.mdx index d7b07f9..203758b 100644 --- a/interviewQuestions/33/ru.mdx +++ b/interviewQuestions/33/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое коррелированный подзапрос?' - description: 'Коррелированный подзапрос в SQL выполняется для каждой строки внешнего запроса, используя её значения. Узнайте, как и когда применять коррелированные подзапросы.' + title: "Что такое коррелированный подзапрос?" + description: "Коррелированный подзапрос в SQL выполняется для каждой строки внешнего запроса, используя её значения. Узнайте, как и когда применять коррелированные подзапросы." --- > **Коррелированный подзапрос** — это подзапрос, который зависит от внешнего запроса. @@ -9,8 +9,8 @@ meta: ## Особенности -- Подзапрос ссылается на столбцы из внешнего запроса. -- Может быть менее эффективным из-за множественного выполнения. +- Подзапрос ссылается на столбцы из внешнего запроса. +- Может быть менее эффективным из-за множественного выполнения. ## Пример @@ -26,7 +26,7 @@ WHERE e.salary > ( ); ``` -- Здесь подзапрос вычисляет среднюю зарплату для отдела каждого сотрудника -- Основной запрос выбирает сотрудников, чья зарплата выше средней по отделу +- Здесь подзапрос вычисляет среднюю зарплату для отдела каждого сотрудника +- Основной запрос выбирает сотрудников, чья зарплата выше средней по отделу Больше информации о коррелированных подзапросах в нашем курсе. diff --git a/interviewQuestions/34/ru.mdx b/interviewQuestions/34/ru.mdx index 07351b3..f58f5d5 100644 --- a/interviewQuestions/34/ru.mdx +++ b/interviewQuestions/34/ru.mdx @@ -1,15 +1,15 @@ --- meta: - title: 'Объясните разницу между DELETE, TRUNCATE и DROP' - description: 'DELETE удаляет выбранные записи, TRUNCATE очищает всю таблицу, сохраняя структуру, DROP полностью удаляет таблицу. Узнайте ключевые различия между этими командами.' + title: "Объясните разницу между DELETE, TRUNCATE и DROP" + description: "DELETE удаляет выбранные записи, TRUNCATE очищает всю таблицу, сохраняя структуру, DROP полностью удаляет таблицу. Узнайте ключевые различия между этими командами." --- ## DELETE -- Удаляет выбранные записи из таблицы. -- Можно использовать условие `WHERE` для удаления конкретных записей. -- Операция записывается в журнал транзакций построчно. -- Триггеры `ON DELETE` срабатывают. +- Удаляет выбранные записи из таблицы. +- Можно использовать условие `WHERE` для удаления конкретных записей. +- Операция записывается в журнал транзакций построчно. +- Триггеры `ON DELETE` срабатывают. ### Синтаксис @@ -19,11 +19,11 @@ DELETE FROM table_name [WHERE condition]; ## TRUNCATE -- Удаляет все данные из таблицы без возможности восстановления. -- Нельзя использовать `WHERE`. -- Быстрее, так как не логирует удаление каждой строки. -- Сбрасывает идентификаторы автоинкремента. -- Триггеры не срабатывают. +- Удаляет все данные из таблицы без возможности восстановления. +- Нельзя использовать `WHERE`. +- Быстрее, так как не логирует удаление каждой строки. +- Сбрасывает идентификаторы автоинкремента. +- Триггеры не срабатывают. ### Синтаксис @@ -33,8 +33,8 @@ TRUNCATE TABLE table_name; ## DROP -- Удаляет всю таблицу вместе с данными, структурой, индексами, ограничениями. -- Действие необратимо. +- Удаляет всю таблицу вместе с данными, структурой, индексами, ограничениями. +- Действие необратимо. ### Синтаксис @@ -44,6 +44,8 @@ DROP TABLE table_name; ## Выбор между командами -- `DELETE` используется, когда нужно удалить определенные записи. -- `TRUNCATE` используется для быстрого удаления всех данных из таблицы, сохраняя ее структуру. -- `DROP` используется для полного удаления таблицы из базы данных. +- `DELETE` используется, когда нужно удалить определенные записи. +- `TRUNCATE` используется для быстрого удаления всех данных из таблицы, сохраняя ее структуру. +- `DROP` используется для полного удаления таблицы из базы данных. + +Подробный разбор темы с примерами — в статье [«TRUNCATE, DELETE и DROP: в чём разница и что выбрать»](https://sql-academy.org/ru/blog/sql-truncate-delete-drop). diff --git a/interviewQuestions/35/ru.mdx b/interviewQuestions/35/ru.mdx index 6e594f9..f6b4be1 100644 --- a/interviewQuestions/35/ru.mdx +++ b/interviewQuestions/35/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое Self-Join и когда он используется?' - description: 'Self-Join в SQL объединяет таблицу с самой собой, что полезно для обработки иерархий и сравнения строк. Узнайте, как и когда использовать Self-Join.' + title: "Что такое Self-Join и когда он используется?" + description: "Self-Join в SQL объединяет таблицу с самой собой, что полезно для обработки иерархий и сравнения строк. Узнайте, как и когда использовать Self-Join." --- > **Self-Join** — это тип соединения в SQL, когда таблица объединяется сама с собой. @@ -9,45 +9,20 @@ meta: ## Когда используется Self-Join: -- **Иерархические структуры** - Например, в таблице сотрудников, где каждый сотрудник может иметь менеджера, - также являющегося сотрудником в той же таблице. -- **Сравнение записей** - Для нахождения дубликатов или сравнения значений в разных строках одной таблицы. +- **Иерархические структуры** + Например, в таблице сотрудников, где каждый сотрудник может иметь менеджера, + также являющегося сотрудником в той же таблице. +- **Сравнение записей** + Для нахождения дубликатов или сравнения значений в разных строках одной таблицы. ## Пример -export const exampleFields = ['employeeId', 'name', 'managerId']; -export const exampleRows = [ - { - employeeId: 1, - name: 'John', - managerId: null, - }, - { - employeeId: 2, - name: 'Michail', - managerId: 1, - }, - { - employeeId: 3, - name: 'Alisa', - managerId: 1, - }, - { - employeeId: 4, - name: 'Max', - managerId: 2, - }, -]; - - +| employeeId | name | managerId | +| ---------- | ------- | --------- | +| 1 | John | null | +| 2 | Michail | 1 | +| 3 | Alisa | 1 | +| 4 | Max | 2 | Чтобы получить список сотрудников и их менеджеров: diff --git a/interviewQuestions/36/ru.mdx b/interviewQuestions/36/ru.mdx index 7c39758..a47146e 100644 --- a/interviewQuestions/36/ru.mdx +++ b/interviewQuestions/36/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Как выполнить резервное копирование и восстановление базы данных?' - description: 'Резервное копирование и восстановление базы данных в MySQL и PostgreSQL с помощью утилит mysqldump и pg_dump. Узнайте, как защитить данные с регулярными бэкапами.' + title: "Как выполнить резервное копирование и восстановление базы данных?" + description: "Резервное копирование и восстановление базы данных в MySQL и PostgreSQL с помощью утилит mysqldump и pg_dump. Узнайте, как защитить данные с регулярными бэкапами." --- Резервное копирование и восстановление базы данных — это критически важные операции для @@ -21,9 +21,9 @@ meta: mysqldump -u username -p mydatabase > backup.sql ``` -- `username` — имя пользователя базы данных. -- `mydatabase` — имя базы данных, которую нужно скопировать. -- `backup.sql` — файл, куда будет сохранена резервная копия. +- `username` — имя пользователя базы данных. +- `mydatabase` — имя базы данных, которую нужно скопировать. +- `backup.sql` — файл, куда будет сохранена резервная копия. ### PostgreSQL @@ -33,9 +33,9 @@ mysqldump -u username -p mydatabase > backup.sql pg_dump -U username mydatabase > backup.sql ``` -- `-U username` — имя пользователя базы данных. -- `mydatabase` — имя базы данных. -- `backup.sql` — выходной файл резервной копии. +- `-U username` — имя пользователя базы данных. +- `mydatabase` — имя базы данных. +- `backup.sql` — выходной файл резервной копии. ## Как восстановить базу данных из резервной копии: @@ -57,11 +57,11 @@ psql -U username mydatabase < backup.sql ## Рекомендации -- **Права доступа** - Убедитесь, что у вас есть необходимые права для выполнения операций резервного копирования и восстановления. -- **Регулярность** - Настройте регулярное автоматическое резервное копирование для минимизации риска потери данных. -- **Хранение копий** - Сохраняйте резервные копии в безопасном и надежном месте, предпочтительно вне основного сервера. -- **Тестирование** - Периодически проверяйте резервные копии путем восстановления на тестовом сервере, чтобы убедиться в их целостности и работоспособности. +- **Права доступа**\ + Убедитесь, что у вас есть необходимые права для выполнения операций резервного копирования и восстановления. +- **Регулярность**\ + Настройте регулярное автоматическое резервное копирование для минимизации риска потери данных. +- **Хранение копий**\ + Сохраняйте резервные копии в безопасном и надежном месте, предпочтительно вне основного сервера. +- **Тестирование**\ + Периодически проверяйте резервные копии путем восстановления на тестовом сервере, чтобы убедиться в их целостности и работоспособности. diff --git a/interviewQuestions/37/ru.mdx b/interviewQuestions/37/ru.mdx index 01112fe..db69c85 100644 --- a/interviewQuestions/37/ru.mdx +++ b/interviewQuestions/37/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Как реализовать отношения многие-ко-многим в SQL?' - description: 'Отношения многие-ко-многим в SQL реализуются через промежуточную таблицу с внешними ключами. Узнайте, как создать связи между таблицами с примерами.' + title: "Как реализовать отношения многие-ко-многим в SQL?" + description: "Отношения многие-ко-многим в SQL реализуются через промежуточную таблицу с внешними ключами. Узнайте, как создать связи между таблицами с примерами." --- Отношения **многие-ко-многим** в реляционных базах данных возникают, @@ -12,9 +12,9 @@ meta: ## Как реализовать отношения многие-ко-многим в SQL -- **Создайте две основные таблицы**, которые нужно связать. -- **Создайте промежуточную таблицу**, содержащую внешние ключи на первичные ключи обеих основных таблиц. -- **Определите внешние ключи и составной первичный ключ** в промежуточной таблице для обеспечения ссылочной целостности и уникальности пар связей. +- **Создайте две основные таблицы**, которые нужно связать. +- **Создайте промежуточную таблицу**, содержащую внешние ключи на первичные ключи обеих основных таблиц. +- **Определите внешние ключи и составной первичный ключ** в промежуточной таблице для обеспечения ссылочной целостности и уникальности пар связей. ## Пример реализации @@ -22,21 +22,21 @@ meta: где один студент может записаться на несколько курсов, и один курс может быть пройден несколькими студентами. -- Создание таблицы студентов: +- Создание таблицы студентов: ```sql CREATE TABLE Student ( StudentID INT PRIMARY KEY, Name VARCHAR(100) ); ``` -- Создание таблицы курсов: +- Создание таблицы курсов: ```sql CREATE TABLE Course ( CourseID INT PRIMARY KEY, Title VARCHAR(100) ); ``` -- Создание промежуточной таблицы для установления связи многие-ко-многим: +- Создание промежуточной таблицы для установления связи многие-ко-многим: ```sql CREATE TABLE StudentCourse ( StudentID INT, @@ -49,6 +49,6 @@ meta: В результате: -- **Промежуточная таблица** `StudentCourse` содержит пары `StudentID` и `CourseID`, представляющие связи между студентами и курсами. -- **Составной первичный ключ** (`StudentID`, `CourseID`) гарантирует, что каждая пара уникальна, предотвращая дублирование связей. -- **Внешние ключи** обеспечивают целостность данных, ссылаясь на соответствующие записи в таблицах `Student` и `Course`. +- **Промежуточная таблица** `StudentCourse` содержит пары `StudentID` и `CourseID`, представляющие связи между студентами и курсами. +- **Составной первичный ключ** (`StudentID`, `CourseID`) гарантирует, что каждая пара уникальна, предотвращая дублирование связей. +- **Внешние ключи** обеспечивают целостность данных, ссылаясь на соответствующие записи в таблицах `Student` и `Course`. diff --git a/interviewQuestions/38/ru.mdx b/interviewQuestions/38/ru.mdx index 473dfa6..12a8bac 100644 --- a/interviewQuestions/38/ru.mdx +++ b/interviewQuestions/38/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Как работают команды REVOKE и GRANT?' - description: 'Команды GRANT и REVOKE в SQL управляют правами доступа к объектам базы данных. Узнайте, как предоставлять и отзывать привилегии пользователей с примерами.' + title: "Как работают команды REVOKE и GRANT?" + description: "Команды GRANT и REVOKE в SQL управляют правами доступа к объектам базы данных. Узнайте, как предоставлять и отзывать привилегии пользователей с примерами." --- Команды `GRANT` и `REVOKE` в SQL используются для управления правами доступа пользователей @@ -18,12 +18,12 @@ meta: GRANT privileges ON object TO user [WITH GRANT OPTION]; ``` -- `privileges`: действия, которые разрешено выполнять (например, SELECT, INSERT, UPDATE, DELETE, ALL PRIVILEGES). -- `object`: база данных, таблица, представление, процедура и т.д. -- `user`: имя пользователя или роли, которой предоставляются права. -- `WITH GRANT OPTION` (опционально): позволяет получателю привилегий передавать их другим пользователям. +- `privileges`: действия, которые разрешено выполнять (например, SELECT, INSERT, UPDATE, DELETE, ALL PRIVILEGES). +- `object`: база данных, таблица, представление, процедура и т.д. +- `user`: имя пользователя или роли, которой предоставляются права. +- `WITH GRANT OPTION` (опционально): позволяет получателю привилегий передавать их другим пользователям. -**Пример:** +**Пример:**\ Предоставить пользователю `user1` право выбора данных из таблицы `employees` можно следующим способом: ```sql @@ -40,7 +40,7 @@ GRANT SELECT ON employees TO user1; REVOKE privileges ON object FROM user; ``` -**Пример:** +**Пример:**\ Отозвать у пользователя `user1` право выбора данных из таблицы `employees`: ```sql diff --git a/interviewQuestions/39/ru.mdx b/interviewQuestions/39/ru.mdx index f61017c..1d0991c 100644 --- a/interviewQuestions/39/ru.mdx +++ b/interviewQuestions/39/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Объясните использование функций хеширования в SQL' - description: 'Хеш-функции в SQL преобразуют данные в фиксированные строки для безопасности и целостности. Узнайте, как использовать хеширование для хранения паролей и оптимизации поиска.' + title: "Объясните использование функций хеширования в SQL" + description: "Хеш-функции в SQL преобразуют данные в фиксированные строки для безопасности и целостности. Узнайте, как использовать хеширование для хранения паролей и оптимизации поиска." --- Хеш-функции в SQL используются для преобразования входных данных произвольной длины в фиксированную строку определенной длины. @@ -11,8 +11,8 @@ meta: ### 1. Хранение паролей -- Вместо хранения паролей в открытом виде, их хранят в виде хешей. Это повышает безопасность, поскольку даже при компрометации базы данных злоумышленники не смогут восстановить исходные пароли. -- Используются криптографические хеш-функции, такие как `SHA-256`, `SHA-512` и другие. +- Вместо хранения паролей в открытом виде, их хранят в виде хешей. Это повышает безопасность, поскольку даже при компрометации базы данных злоумышленники не смогут восстановить исходные пароли. +- Используются криптографические хеш-функции, такие как `SHA-256`, `SHA-512` и другие. ### 2. Проверка целостности данных @@ -49,8 +49,8 @@ WHERE Username = 'user1' AND PasswordHash = HASHBYTES('SHA2_512', 'password123') ### Выбор хеш-функции -- Отдавайте предпочтение более современным и стойким алгоритмам, таким как `SHA-256` или `SHA-512`. -- Избегайте использования устаревших функций, таких как `MD5` или `SHA1`, из-за известных уязвимостей. +- Отдавайте предпочтение более современным и стойким алгоритмам, таким как `SHA-256` или `SHA-512`. +- Избегайте использования устаревших функций, таких как `MD5` или `SHA1`, из-за известных уязвимостей. ### Безопасность хранения diff --git a/interviewQuestions/4/ru.mdx b/interviewQuestions/4/ru.mdx index 06d7ea9..5b98dcb 100644 --- a/interviewQuestions/4/ru.mdx +++ b/interviewQuestions/4/ru.mdx @@ -1,116 +1,52 @@ --- meta: - title: 'Объясните понятие нормализации и ее преимущества' - description: 'Нормализация в SQL уменьшает избыточность данных и улучшает целостность базы. Узнайте о нормальных формах и преимуществах этого процесса.' + title: "Объясните понятие нормализации и ее преимущества" + description: "Нормализация в SQL уменьшает избыточность данных и улучшает целостность базы. Узнайте о нормальных формах и преимуществах этого процесса." --- > Нормализация — это процесс организации структуры базы данных с целью уменьшения избыточности данных и обеспечения их целостности. ## Основные цели нормализации: -- Устранение избыточности: предотвращает дублирование данных. -- Повышение целостности данных: минимизирует вероятность неконсистентности данных. -- Облегчение поддержки и обновления: делает структуру базы данных более гибкой и понятной. +- Устранение избыточности: предотвращает дублирование данных. +- Повышение целостности данных: минимизирует вероятность неконсистентности данных. +- Облегчение поддержки и обновления: делает структуру базы данных более гибкой и понятной. ## Основные нормальные формы -- Первая нормальная форма (1НФ): все столбцы содержат атомарные (неделимые) значения. -- Вторая нормальная форма (2НФ): удовлетворяет 1НФ и все неключевые столбцы зависят от всего первичного ключа. -- Третья нормальная форма (3НФ): удовлетворяет 2НФ и нет транзитивных зависимостей между неключевыми столбцами. +- Первая нормальная форма (1НФ): все столбцы содержат атомарные (неделимые) значения. +- Вторая нормальная форма (2НФ): удовлетворяет 1НФ и все неключевые столбцы зависят от всего первичного ключа. +- Третья нормальная форма (3НФ): удовлетворяет 2НФ и нет транзитивных зависимостей между неключевыми столбцами. ## Пример **До нормализации:** -export const beforeNormalizationTableFields = [ - 'StudentID', - 'StudentName', - 'CourseID', - 'CourseName', -]; -export const beforeNormalizationTableRows = [ - { - StudentID: '1', - StudentName: 'John', - CourseID: '101', - CourseName: 'Math', - }, - { - StudentID: '1', - StudentName: 'John', - CourseID: '102', - CourseName: 'Music', - }, -]; - - +| StudentID | StudentName | CourseID | CourseName | +| --------- | ----------- | -------- | ---------- | +| 1 | John | 101 | Math | +| 1 | John | 102 | Music | **После нормализации:** Таблица Students -export const studentsTableFields = ['StudentID', 'StudentName']; -export const studentsTableRows = [ - { - StudentID: '1', - StudentName: 'John', - }, -]; - - +| StudentID | StudentName | +| --------- | ----------- | +| 1 | John | Таблица Courses -export const coursesTableFields = ['CourseID', 'CourseName']; -export const coursesTableRows = [ - { - CourseID: '101', - CourseName: 'Math', - }, - { - CourseID: '102', - CourseName: 'Music', - }, -]; - - +| CourseID | CourseName | +| -------- | ---------- | +| 101 | Math | +| 102 | Music | Таблица Enrollments -export const enrollmentsTableFields = ['StudentID', 'CourseID']; -export const enrollmentsTableRows = [ - { - StudentID: '1', - CourseID: '101', - }, - { - StudentID: '1', - CourseID: '102', - }, -]; - - +| StudentID | CourseID | +| --------- | -------- | +| 1 | 101 | +| 1 | 102 | + +Подробный разбор темы с примерами — в статье [«Нормализация баз данных: нормальные формы простыми словами»](https://sql-academy.org/ru/blog/database-normalization). diff --git a/interviewQuestions/40/ru.mdx b/interviewQuestions/40/ru.mdx index 899ea28..fb4d0c3 100644 --- a/interviewQuestions/40/ru.mdx +++ b/interviewQuestions/40/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Как работает SQL-триггер?' - description: 'SQL-триггер — это хранимая процедура, автоматически выполняемая при событиях INSERT, UPDATE или DELETE. Узнайте, как использовать триггеры для логирования и поддержания целостности данных.' + title: "Как работает SQL-триггер?" + description: "SQL-триггер — это хранимая процедура, автоматически выполняемая при событиях INSERT, UPDATE или DELETE. Узнайте, как использовать триггеры для логирования и поддержания целостности данных." --- ## Что такое SQL-триггер @@ -16,12 +16,12 @@ meta: ### Типы триггеров -- `BEFORE`: Срабатывает до выполнения операции. - Используется для проверки или изменения данных перед их сохранением. -- `AFTER`: Срабатывает после выполнения операции. - Часто используется для ведения логов или обновления связанных таблиц. -- `INSTEAD OF`: Заменяет стандартное поведение операции. - Используется в случаях, когда необходимо переопределить действие по умолчанию, например, при работе с представлениями. +- `BEFORE`: Срабатывает до выполнения операции.\ + Используется для проверки или изменения данных перед их сохранением. +- `AFTER`: Срабатывает после выполнения операции.\ + Часто используется для ведения логов или обновления связанных таблиц. +- `INSTEAD OF`: Заменяет стандартное поведение операции.\ + Используется в случаях, когда необходимо переопределить действие по умолчанию, например, при работе с представлениями. Внутри триггера можно обращаться к старым и новым значениям данных через специальные псевдотаблицы: `OLD` и `NEW`. @@ -68,11 +68,11 @@ DELIMITER ; ## Когда использовать триггеры -- **Ведение журналов и аудита**: - Автоматическое логирование изменений данных для отслеживания действий пользователей. -- **Поддержание целостности данных**: - Обеспечение сложных бизнес-правил, не реализуемых с помощью ограничений. -- **Синхронизация данных**: - Автоматическое обновление или модификация связанных таблиц при изменении данных. -- **Вычисление значений**: - Автоматический расчет и обновление агрегированных или производных данных. +- **Ведение журналов и аудита**:\ + Автоматическое логирование изменений данных для отслеживания действий пользователей. +- **Поддержание целостности данных**:\ + Обеспечение сложных бизнес-правил, не реализуемых с помощью ограничений. +- **Синхронизация данных**:\ + Автоматическое обновление или модификация связанных таблиц при изменении данных. +- **Вычисление значений**:\ + Автоматический расчет и обновление агрегированных или производных данных. diff --git a/interviewQuestions/5/ru.mdx b/interviewQuestions/5/ru.mdx index 8f64e99..a78d9c1 100644 --- a/interviewQuestions/5/ru.mdx +++ b/interviewQuestions/5/ru.mdx @@ -1,24 +1,24 @@ --- meta: - title: 'Что такое JOIN и какие виды JOIN вы знаете?' - description: 'JOIN в SQL объединяет данные из нескольких таблиц. Узнайте о видах JOIN: INNER, LEFT, RIGHT, FULL и CROSS JOIN для эффективной работы с базами данных.' + title: "Что такое JOIN и какие виды JOIN вы знаете?" + description: "JOIN в SQL объединяет данные из нескольких таблиц. Узнайте о видах JOIN: INNER, LEFT, RIGHT, FULL и CROSS JOIN для эффективной работы с базами данных." --- > JOIN — это операция в SQL, которая позволяет объединить строки из двух или более таблиц на основе связанных между ними столбцов. ## Виды JOIN: -- `INNER JOIN`: - Возвращает записи, у которых есть соответствующие записи в обеих таблицах. +- `INNER JOIN`:\ + Возвращает записи, у которых есть соответствующие записи в обеих таблицах. -- `LEFT JOIN (или LEFT OUTER JOIN)`: - Возвращает все записи из левой таблицы и соответствующие записи из правой таблицы. Если соответствия нет, возвращает `NULL` для правой таблицы. +- `LEFT JOIN (или LEFT OUTER JOIN)`:\ + Возвращает все записи из левой таблицы и соответствующие записи из правой таблицы. Если соответствия нет, возвращает `NULL` для правой таблицы. -- `RIGHT JOIN (или RIGHT OUTER JOIN)`: - Возвращает все записи из правой таблицы и соответствующие записи из левой таблицы. Если соответствия нет, возвращает `NULL` для левой таблицы. +- `RIGHT JOIN (или RIGHT OUTER JOIN)`:\ + Возвращает все записи из правой таблицы и соответствующие записи из левой таблицы. Если соответствия нет, возвращает `NULL` для левой таблицы. -- `FULL OUTER JOIN`: - Возвращает все записи, когда есть соответствие в одной из таблиц. +- `FULL OUTER JOIN`:\ + Возвращает все записи, когда есть соответствие в одной из таблиц. -- `CROSS JOIN`: - Выполняет декартово произведение двух таблиц, объединяя каждую строку первой таблицы с каждой строкой второй таблицы. +- `CROSS JOIN`:\ + Выполняет декартово произведение двух таблиц, объединяя каждую строку первой таблицы с каждой строкой второй таблицы. diff --git a/interviewQuestions/6/ru.mdx b/interviewQuestions/6/ru.mdx index 5581769..b5080e3 100644 --- a/interviewQuestions/6/ru.mdx +++ b/interviewQuestions/6/ru.mdx @@ -1,16 +1,16 @@ --- meta: - title: 'Что такое подзапрос (subquery) и когда он используется?' - description: 'Подзапрос (subquery) в SQL — это вложенный запрос, используемый для фильтрации данных, выборки или создания виртуальных таблиц. Узнайте, когда и как его применять.' + title: "Что такое подзапрос (subquery) и когда он используется?" + description: "Подзапрос (subquery) в SQL — это вложенный запрос, используемый для фильтрации данных, выборки или создания виртуальных таблиц. Узнайте, когда и как его применять." --- > Подзапрос — это SQL-запрос, вложенный внутри другого запроса. Он используется для выполнения операций, результат которых необходим для основного запроса. ## Случаи использования подзапросов: -- **Фильтрация данных**: Использование результатов подзапроса в условиях `WHERE` или `HAVING`. -- **Выборка данных**: Использование подзапроса в списке выбранных столбцов. -- **Создание виртуальных таблиц**: Использование подзапроса в операторе `FROM`. +- **Фильтрация данных**: Использование результатов подзапроса в условиях `WHERE` или `HAVING`. +- **Выборка данных**: Использование подзапроса в списке выбранных столбцов. +- **Создание виртуальных таблиц**: Использование подзапроса в операторе `FROM`. ## Примеры: diff --git a/interviewQuestions/7/ru.mdx b/interviewQuestions/7/ru.mdx index ba4f327..6ba463e 100644 --- a/interviewQuestions/7/ru.mdx +++ b/interviewQuestions/7/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Как удалить дубликаты в результате SQL-запроса?' - description: 'Удаление дубликатов в SQL выполняется с помощью ключевого слова DISTINCT. Узнайте, как использовать его для получения уникальных записей.' + title: "Как удалить дубликаты в результате SQL-запроса?" + description: "Удаление дубликатов в SQL выполняется с помощью ключевого слова DISTINCT. Узнайте, как использовать его для получения уникальных записей." --- Использовать ключевое слово `DISTINCT` в операторе `SELECT`, чтобы вернуть только уникальные записи. diff --git a/interviewQuestions/8/ru.mdx b/interviewQuestions/8/ru.mdx index 3c91fc8..64cf92c 100644 --- a/interviewQuestions/8/ru.mdx +++ b/interviewQuestions/8/ru.mdx @@ -1,14 +1,14 @@ --- meta: - title: 'Объясните разницу между WHERE и HAVING' - description: 'Разница между WHERE и HAVING в SQL: WHERE фильтрует данные до группировки, HAVING — после. Узнайте, когда и как использовать эти операторы.' + title: "Объясните разницу между WHERE и HAVING" + description: "Разница между WHERE и HAVING в SQL: WHERE фильтрует данные до группировки, HAVING — после. Узнайте, когда и как использовать эти операторы." --- ## WHERE -- Фильтрует строки **до** группировки данных. -- Не может использовать агрегатные функции (`SUM()`, `COUNT()`, `AVG()`, и т.д.). -- Применяется к отдельным записям таблицы. +- Фильтрует строки **до** группировки данных. +- Не может использовать агрегатные функции (`SUM()`, `COUNT()`, `AVG()`, и т.д.). +- Применяется к отдельным записям таблицы. Пример: @@ -21,9 +21,9 @@ GROUP BY department_id; ## HAVING -- Фильтрует группы строк после группировки данных. -- Может использовать агрегатные функции. -- Применяется к результатам `GROUP BY`. +- Фильтрует группы строк после группировки данных. +- Может использовать агрегатные функции. +- Применяется к результатам `GROUP BY`. Пример: diff --git a/interviewQuestions/9/ru.mdx b/interviewQuestions/9/ru.mdx index c711dd8..a5a7d23 100644 --- a/interviewQuestions/9/ru.mdx +++ b/interviewQuestions/9/ru.mdx @@ -1,7 +1,7 @@ --- meta: - title: 'Что такое индекс и как он влияет на производительность?' - description: 'Индекс в SQL улучшает скорость выборки данных, но может замедлять операции записи. Узнайте, как индексы влияют на производительность и их преимущества.' + title: "Что такое индекс и как он влияет на производительность?" + description: "Индекс в SQL улучшает скорость выборки данных, но может замедлять операции записи. Узнайте, как индексы влияют на производительность и их преимущества." --- > **Индекс** — это специальная структура данных, которая улучшает скорость операций выборки данных из таблицы за счет создания указателей на данные. @@ -11,13 +11,13 @@ meta: ## Преимущества индексов: -- Быстрое выполнение операций `SELECT`. -- Улучшение производительности при сортировке и поиске данных. +- Быстрое выполнение операций `SELECT`. +- Улучшение производительности при сортировке и поиске данных. ## Недостатки индексов: -- Дополнительное пространство на диске. -- Замедление операций `INSERT`, `UPDATE`, `DELETE`. +- Дополнительное пространство на диске. +- Замедление операций `INSERT`, `UPDATE`, `DELETE`. ## Пример создания индекса: