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..2a1b067 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..1b4c70e 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..e875c86 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..face020 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..b9db72f 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` Давайте рассмотрим их применение. @@ -27,8 +27,8 @@ WHERE middle_name IS NULL; | id | first_name | middle_name | last_name | | --- | ---------- | ----------- | --------- | -| 10 | YUrij | null | Krylov | -| 11 | Andrej | null | Evseev | +| 10 | YUrij | | Krylov | +| 11 | Andrej | | Evseev | Для использования отрицания, то есть, если мы хотим найти все записи, где поле не равно `NULL`, мы должны использовать следующий синтаксис: diff --git a/course/module-2/literals/article.md b/course/module-2/literals/article.md index e2b3ab8..974ac89 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..ef3b3b3 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,25 +114,40 @@ 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, мы выводим «Начальная школа». @@ -136,9 +170,9 @@ END Используя этот синтаксис, можно переписать наш предыдущий пример таким образом: - +**MySQL** -```sql-executable-Schedule +```sql SELECT name, CASE SUBSTRING(name, 1, INSTR(name, ' ')) WHEN 11 THEN 'Старшая школа' @@ -153,11 +187,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 +204,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 +234,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..ca713e3 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 | + | ----------- | + | | - +**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 | + | ------ | + | | - +**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 26112b5..b054455 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..3ea775d 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 | | +| 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..0cbafc5 100644 --- a/course/module-3/outer-join/article.md +++ b/course/module-3/outer-join/article.md @@ -1,7 +1,7 @@ --- meta: - title: "Внешнее соединение OUTER JOIN" - description: "Описание и синтаксис внешнего соединения OUTER JOIN" + title: "Внешнее соединение OUTER JOIN" + description: "Описание и синтаксис внешнего соединения OUTER JOIN" --- # Внешнее соединение OUTER JOIN @@ -17,19 +17,119 @@ meta: Для примера получим из базы данных расписание звонков, объединённых с соответствующими занятиями в расписании занятий. - +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; ``` +| 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 | | | | | | | | +| 7 | 14:35:00 | 15:20:00 | | | | | | | | +| 8 | 15:25:00 | 16:10:00 | | | | | | | | + В выборку попали все строки из левой таблицы, дополненные данными о занятиях. Примечательно, что в конце таблицы есть строки с полями, заполненными `NULL`. Это те строки, для которых не нашлось соответствующих занятий, однако они присутствуют в левой таблице, поэтому тоже были выведены. @@ -39,7 +139,7 @@ FROM Timepair Соединение, которое возвращает все значения из правой таблицы, соединённые с соответствующими значениями из левой таблицы, если они удовлетворяют условию соединения, или заменяет их на `NULL` в обратном случае. - +**PostgreSQL** ## Внешнее полное соединение (FULL OUTER JOIN) @@ -51,9 +151,7 @@ FROM Timepair - В таблицу добавляются значения, не вошедшие в результат формирования из левой таблицы (`LEFT OUTER JOIN`) - В таблицу добавляются значения, не вошедшие в результат формирования из правой таблицы (`RIGHT OUTER JOIN`) - - - +**MySQL** ## Эмуляция полного соединения в MySQL @@ -74,170 +172,177 @@ ON правая_таблица.ключ = левая_таблица.ключ WHERE левая_таблица.ключ IS NULL ``` - - ## Базовые запросы для разных вариантов объединения таблиц - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
СхемаЗапрос с 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 правая_таблица.ключ = левая_таблица.ключ - ``` -
- - - Получение всех данных, относящихся к левой и правой таблицам, а также их - внутреннему соединению: - - - -```sql -SELECT поля_таблиц -FROM левая_таблица - FULL OUTER JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ -``` - - - - - -```sql -SELECT поля_таблиц -FROM левая_таблица -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 -``` - - - - - -```sql -SELECT поля_таблиц -FROM левая_таблица -LEFT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ -WHERE правая_таблица.ключ IS NULL - -UNION ALL - -SELECT поля_таблиц -FROM левая_таблица -RIGHT JOIN правая_таблица - ON правая_таблица.ключ = левая_таблица.ключ -WHERE левая_таблица.ключ IS NULL -``` - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
СхемаЗапрос с 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 правая_таблица.ключ = левая_таблица.ключ + ``` + + **MySQL** + + ```sql + SELECT поля_таблиц + FROM левая_таблица + LEFT JOIN правая_таблица + ON правая_таблица.ключ = левая_таблица.ключ + + UNION ALL + + SELECT поля_таблиц + FROM левая_таблица + RIGHT JOIN правая_таблица + ON правая_таблица.ключ = левая_таблица.ключ + WHERE левая_таблица.ключ IS NULL + ``` +
+ + + Получение данных, не относящихся к левой и правой таблицам одновременно + (обратное INNER JOIN): + + **PostgreSQL** + + ```sql + SELECT поля_таблиц + FROM левая_таблица + FULL OUTER JOIN правая_таблица + ON правая_таблица.ключ = левая_таблица.ключ + WHERE левая_таблица.ключ IS NULL + OR правая_таблица.ключ IS NULL + ``` + + **MySQL** + + ```sql + SELECT поля_таблиц + FROM левая_таблица + LEFT JOIN правая_таблица + ON правая_таблица.ключ = левая_таблица.ключ + WHERE правая_таблица.ключ IS NULL + + UNION ALL + + SELECT поля_таблиц + FROM левая_таблица + RIGHT JOIN правая_таблица + ON правая_таблица.ключ = левая_таблица.ключ + WHERE левая_таблица.ключ IS NULL + ``` +
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 31f527e..0109a7b 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 для управления изменениями и обеспечения стабильности данных. Откройте для себя применение точек сохранения для гибкого контроля над транзакциями, минимизируя риски и повышая эффективность обработки данных." --- # Создание транзакций @@ -16,7 +16,7 @@ meta: Однако, если возникнут какие-либо проблемы, будет выполнена команда `ROLLBACK`, которая указывает серверу отменить все действия, совершённые с начала транзакции. - +**MySQL** Процесс может выглядеть следующим образом: @@ -46,9 +46,7 @@ UPDATE accounts SET user_balance = user_balance + 1000 WHERE user_id = 2; COMMIT; ``` - - - +**PostgreSQL** Процесс может выглядеть следующим образом: @@ -76,25 +74,19 @@ WHERE user_id = 2; COMMIT; ``` - - С помощью транзакции программа обеспечивает сохранность ваших 1000 долларов, гарантируя, что они либо останутся на исходном счёте, либо будут переведены на другой счёт, исключая риск их утраты. ## Запуск и завершение транзакций - +**MySQL** Каждая явная транзакция в MySQL начинается с использования оператора `START TRANSACTION` или `BEGIN`. - - - +**PostgreSQL** Каждая явная транзакция в PostgreSQL начинается с использования оператора `BEGIN` или `START TRANSACTION`. - - Завершение же транзакции возможно: - с помощью команды `COMMIT`, которая даёт указание серверу пометить изменения как постоянные и освободить все ресурсы (т.е. блокировки строк), использовавшиеся во время транзакции @@ -122,7 +114,7 @@ SAVEPOINT my_savepoint; `ROLLBACK`, за которой следуют ключевые слова `TO SAVEPOINT` и имя точки сохранения, например: - +**MySQL** ```sql START TRANSACTION; @@ -144,9 +136,7 @@ UPDATE accounts SET balance = balance + 200 WHERE user_id = 2; COMMIT; ``` - - - +**PostgreSQL** ```sql BEGIN; @@ -168,8 +158,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..80288bb 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,13 +40,13 @@ meta: Существует ряд различных стратегий, которые могут использоваться, как именно блокировать ресурс. Сервер может применять блокировку на одном из трёх разных уровней, или гранулярностей. -- Блокировка таблиц +- Блокировка таблиц\ Не позволяет нескольким пользователям одновременно изменять данные в одной таблице. -- Блокировка страниц +- Блокировка страниц\ Не позволяет нескольким пользователям изменять данные в одной и той же странице (страница — это сегмент памяти, обычно в диапазоне от 2 до 16 Кбайт) таблицы одновременно. -- Блокировка строк +- Блокировка строк\ Не позволяет нескольким пользователям одновременно изменять одну и ту же строку в таблице. @@ -56,17 +56,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..a6817ce 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..2ea18a6 100644 --- a/course/module-5/stored-procedures-and-functions/article.md +++ b/course/module-5/stored-procedures-and-functions/article.md @@ -1,115 +1,46 @@ --- meta: - title: 'Хранимые процедуры и функции в SQL' - description: 'Введение в хранимые процедуры и функции SQL. Их назначение, основные различия и когда использовать каждый тип.' + title: "Хранимые процедуры и функции в SQL" + description: "Введение в хранимые процедуры и функции SQL. Их назначение, основные различия и когда использовать каждый тип." --- -# Хранимые процедуры и функции - -В SQL помимо обычных запросов существуют более мощные инструменты — **хранимые процедуры** и **хранимые функции**. -Эти объекты позволяют создавать готовые блоки кода, которые можно многократно использовать 🔄. - -> **Хранимые процедуры и функции** — это заранее написанные и сохранённые в базе данных SQL-скрипты, которые можно вызывать по имени. - -Представьте, что у вас есть сложный запрос для расчёта статистики продаж, который вы используете каждый день. -Вместо того чтобы каждый раз переписывать его, можно создать процедуру или функцию и просто вызывать её! - -## Зачем они нужны? - -Хранимые процедуры и функции решают несколько важных задач: - -- **🚀 Повторное использование кода** — написали один раз, используете везде. Никаких копий одного и того же кода в разных местах. -- **⚡ Производительность** — код выполняется прямо на сервере базы данных, что часто быстрее обычных запросов. -- **🔒 Безопасность** — можно предоставить доступ к процедуре, не давая прямого доступа к таблицам. -- **🛡️ Централизованная логика** — вся бизнес-логика находится в одном месте, в базе данных. - -## Основные различия - -Хотя процедуры и функции похожи, между ними есть важные различия: - - - -| Характеристика | Хранимые процедуры | Хранимые функции | -| ---------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- | -| **Возвращаемое значение** | Может не возвращать или возвращать несколько значений | Всегда возвращает одно значение | -| **Использование в запросах** | Вызывается отдельно | Можно использовать в SELECT, WHERE и других частях запроса | -| **Изменение данных** | Может изменять данные в таблицах | Предназначены только для чтения данных | -| **Вызов** | `CALL procedure_name()` | `SELECT function_name()` | - - - - - -| Характеристика | Хранимые процедуры | Хранимые функции | -| ---------------------------- | -------------------------------- | ---------------------------------------------------------- | -| **Возвращаемое значение** | Не могут возвращать значения | Всегда возвращает одно значение | -| **Использование в запросах** | Вызывается отдельно | Можно использовать в SELECT, WHERE и других частях запроса | -| **Изменение данных** | Может изменять данные в таблицах | Может изменять данные в таблицах | -| **Вызов** | `CALL procedure_name()` | `SELECT function_name()` | - - - -## Когда использовать процедуры? - -**Хранимые процедуры** лучше всего подходят, когда нужно: - -- Выполнить последовательность операций (например, создать заказ, списать товар со склада, отправить уведомление) -- Изменить данные в нескольких таблицах одновременно -- Реализовать сложную бизнес-логику -- Вернуть несколько результирующих наборов - -### Пример использования процедуры - -Допустим, нам нужно создать процедуру для оформления заказа: - -```sql --- Пример вызова процедуры (концептуальный) -CALL create_order(customer_id = 123, product_id = 456, quantity = 2); -``` - -Такая процедура может: - -1. Проверить наличие товара на складе +![Иллюстрация к статье](https://sql-academy.org/static/guidePage/stored-procedures-and-functions/banner.jpg)# Хранимые процедуры и функцииВ SQL помимо обычных запросов существуют более мощные инструменты — **хранимые процедуры** и **хранимые функции**. +Эти объекты позволяют создавать готовые блоки кода, которые можно многократно использовать 🔄.> **Хранимые процедуры и функции** — это заранее написанные и сохранённые в базе данных SQL-скрипты, которые можно вызывать по имени.Представьте, что у вас есть сложный запрос для расчёта статистики продаж, который вы используете каждый день. +Вместо того, чтобы каждый раз переписывать его, можно создать процедуру или функцию и просто вызывать её!## Зачем они нужны?Хранимые процедуры и функции решают несколько важных задач:- **🚀 Повторное использование кода** — написали один раз, используете везде. Никаких копий одного и того же кода в разных местах. + +- **⚡ Производительность** — код выполняется прямо на сервере базы данных, что часто быстрее обычных запросов. +- **🔒 Безопасность** — можно предоставить доступ к процедуре, не давая прямого доступа к таблицам. +- | **🛡️ Централизованная логика** — вся бизнес-логика находится в одном месте, в базе данных.## Основные различияХотя процедуры и функции похожи, между ними есть важные различия:**MySQL** | Характеристика | Хранимые процедуры | Хранимые функции | + | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | ------------------ | ---------------- | + | **Возвращаемое значение** | Может не возвращать или возвращать несколько значений | Всегда возвращает одно значение | + | **Использование в запросах** | Вызывается отдельно | Можно использовать в SELECT, WHERE и других частях запроса | + | **Изменение данных** | Может изменять данные в таблицах | Предназначены только для чтения данных | + | **Вызов** | `CALL procedure_name()` | `SELECT function_name()` | **PostgreSQL** | Характеристика | Хранимые процедуры | Хранимые функции | + | ---------------------------- | -------------------------------- | ---------------------------------------------------------- | + | **Возвращаемое значение** | Не могут возвращать значения | Всегда возвращает одно значение | + | **Использование в запросах** | Вызывается отдельно | Можно использовать в SELECT, WHERE и других частях запроса | + | **Изменение данных** | Может изменять данные в таблицах | Может изменять данные в таблицах | + | **Вызов** | `CALL procedure_name()` | `SELECT function_name()` | ## Когда использовать процедуры?**Хранимые процедуры** лучше всего подходят, когда нужно:- Выполнить последовательность операций (например, создать заказ, списать товар со склада, отправить уведомление) | +- Изменить данные в нескольких таблицах одновременно +- Реализовать сложную бизнес-логику +- Вернуть несколько результирующих наборов### Пример использования процедурыДопустим, нам нужно создать процедуру для оформления заказа:```sql + -- Пример вызова процедуры (концептуальный) + CALL create_order(customer_id = 123, product_id = 456, quantity = 2); + +````Такая процедура может:1. Проверить наличие товара на складе 2. Создать запись в таблице заказов 3. Обновить остатки товара -4. Добавить запись в историю операций - -## Когда использовать функции? - -**Хранимые функции** идеальны, когда нужно: - -- Выполнить вычисления и вернуть результат -- Создать переиспользуемую формулу -- Преобразовать данные определённым образом -- Использовать результат в других SQL-запросах - -### Пример использования функции - -Создадим функцию для расчёта скидки: - -```sql +4. Добавить запись в историю операций## Когда использовать функции?**Хранимые функции** идеальны, когда нужно:- Выполнить вычисления и вернуть результат +- Создать переиспользуемую формулу +- Преобразовать данные определённым образом +- Использовать результат в других SQL-запросах### Пример использования функцииСоздадим функцию для расчёта скидки:```sql -- Пример использования функции в запросе SELECT product_name, price, calculate_discount(price, customer_type) AS discount_amount 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..9f354ef 100644 --- a/course/module-5/transactions/article.md +++ b/course/module-5/transactions/article.md @@ -1,20 +1,12 @@ --- meta: - title: "Транзакции" - description: "Изучите важность транзакций в управлении базами данных и как они обеспечивают надёжность работы приложений. Узнайте, почему транзакции необходимы для поддержания целостности данных и как они помогают предотвращать ошибки при одновременном доступе множества пользователей." + title: "Транзакции: MySQL и PostgreSQL" + description: "Изучите важность транзакций в управлении базами данных MySQL и PostgreSQL и как они обеспечивают надёжность работы приложений. Узнайте, почему транзакции необходимы для поддержания целостности данных и как они помогают предотвращать ошибки при одновременном доступе множества пользователей." --- -# Транзакции - -Если бы серверы баз данных безотказно работали все 100% времени, +![Иллюстрация к статье](https://sql-academy.org/static/guidePage/transactions/banner.jpg)# ТранзакцииЕсли бы серверы баз данных безотказно работали все 100% времени, если бы пользователи всегда позволяли программам завершать выполнение и если бы приложения всегда завершались без фатальных ошибок, -останавливающих выполнение, не было бы ничего, что следовало было бы обсуждать об одновременном доступе к базе данных. - -Однако такая идеальная ситуация нереалистична, и поэтому мы должны рассмотреть механизмы, +останавливающих выполнение, не было бы ничего, что следовало было бы обсуждать об одновременном доступе к базе данных.Однако такая идеальная ситуация нереалистична, и поэтому мы должны рассмотреть механизмы, позволяющие множеству пользователей работать с одними и теми же данными. -Одним из ключевых элементов в решении этой задачи является транзакция. - -> Транзакция — это последовательность операций с базой данных, которые выполняются как единое целое. - -В данном блоке мы обсудим транзакции, которые позволяют объединять несколько SQL-инструкций в одну группу, +Одним из ключевых элементов в решении этой задачи является транзакция.> Транзакция — это последовательность операций с базой данных, которые выполняются как единое целое.В данном блоке мы обсудим транзакции, которые позволяют объединять несколько SQL-инструкций в одну группу, гарантируя, что либо все инструкции выполнятся успешно, либо ни одна из них не будет выполнена. diff --git a/course/module-5/type-conversion-functions/article.md b/course/module-5/type-conversion-functions/article.md index 4e82f00..46d3e7b 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..f177c05 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 | | | 85 | 80 | 299 | +| 38 | Entire home/apt | 85 | 80 | | 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 | | 80 | 299 | +| 37 | Private room | 35 | | | 44 | 35 | 150 | +| 29 | Private room | 44 | 35 | | 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 | | 35 | 150 | +| 40 | Shared room | 40 | | | | 40 | 40 | diff --git a/course/module-5/windows-functions-frames/article.md b/course/module-5/windows-functions-frames/article.md index c13ba2b..a4ef9b0 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..4bef4c6 100644 --- a/course/module-5/windows-functions/article.md +++ b/course/module-5/windows-functions/article.md @@ -1,113 +1,147 @@ --- meta: - title: 'Оконные функции SQL' - description: 'Оконные функции SQL, синтаксис OVER окна данных, оконной функции, пример использования оконной функции, очередь выполнения оконных функций в SELECT запросе' + title: "Оконные функции SQL: MySQL и PostgreSQL" + description: "Оконные функции SQL в MySQL и PostgreSQL, синтаксис OVER окна данных, оконной функции, пример использования оконной функции, очередь выполнения оконных функций в SELECT запросе" --- -# Оконные функции SQL +![Иллюстрация к статье](https://sql-academy.org/static/guidePage/windows-functions/banner.jpg)# Оконные функции SQLОконные функции — мощный инструмент языка SQL, позволяющий проводить сложные вычисления по группам строк, +которые связаны с текущей строкой.## Принцип работыВозможно, вы зададитесь вопросом: «Что значит оконные?».В стандартном SQL-запросе все наборы строк рассматриваются как один сплошной блок данных, +для которого и вычисляются агрегатные значения.Однако, когда применяются оконные функции, запрос сегментируется на группы строк (или «окна»), +и для каждого такого сегмента подсчитываются индивидуальные агрегатные значения.Это окно, которое подаётся в оконную функцию, может быть:- всей таблицей -Оконные функции — мощный инструмент языка SQL, позволяющий проводить сложные вычисления по группам строк, -которые связаны с текущей строкой. - -## Принцип работы - -Возможно, вы зададитесь вопросом: «Что значит оконные?». - -В стандартном SQL-запросе все наборы строк рассматриваются как один сплошной блок данных, -для которого и вычисляются агрегатные значения. - -Однако, когда применяются оконные функции, запрос сегментируется на группы строк (или «окна»), -и для каждого такого сегмента подсчитываются индивидуальные агрегатные значения. - -Это окно, которое подаётся в оконную функцию, может быть: - -- всей таблицей - отдельными партициями таблицы, то есть группой строк на основе одного или нескольких полей - или даже конкретным диапазоном строк в пределах таблицы или партиции. - Например, мы может определить окно, которое будет передаваться в оконную функцию, + Например, мы можем определить окно, которое будет передаваться в оконную функцию, как предыдущая + текущая строка таблицы. И тогда для каждой строки значение агрегатной функции будет подсчитываться по-своему, так как данные, которые поступают в функцию, будут динамически меняться - от строки к строке. Окно будет как бы «скользить» по таблице. - -### Визуализация - -Оконные функции всегда принимают на вход окно данных, которое указывает пользователь, и возвращает результат в отдельный столбец. - -Давайте рассмотрим, как это может выглядеть. Для этого возьмём оконную функцию `AVG` для вычисления среднего значения и вот -такую небольшую таблицу: - -![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/1.png "Схема разбиения на партиции") - -А теперь давайте посмотрим, как оконная функция будет работать для разных переданных окон: - -- Если в качестве окна указать всю таблицу, то для всех строк окно будет совпадать и на вход функции `AVG` будет + от строки к строке. Окно будет как бы «скользить» по таблице.### ВизуализацияОконные функции всегда принимают на вход окно данных, которое указывает пользователь, и возвращают результат в отдельный столбец.Давайте рассмотрим как это может выглядеть. Для этого возьмём оконную функцию `AVG` для вычисления среднего значения и вот + такую небольшую таблицу:![Изначальная таблица](https://sql-academy.org/static/guidePage/windows-functions/schema_table.png "Изначальная таблица")А теперь давайте посмотрим, как оконная функция будет работать для разных переданных окон:- Если в качестве окна указать всю таблицу, то для всех строк окно будет совпадать, и на вход функции `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 "Схема разбиения на партиции") - - Стоит отметить, что для первой строки окно будет состоять только из 1-ой записи, так как предыдущей строки нет. + ![Схема разбиения на партиции](https://sql-academy.org/static/guidePage/windows-functions/4.png "Схема разбиения на партиции") -## Синтаксис оконной функции - -```sql + Стоит отметить, что для первой строки окно будет состоять только из 1-ой записи, так как предыдущей строки нет.## Синтаксис оконной функции`sql SELECT <оконная_функция>(<поле_таблицы>) OVER ( [PARTITION BY <столбцы_для_разделения>] [ORDER BY <столбцы_для_сортировки>] [ROWS|RANGE <определение_диапазона_строк>] ) -``` - -Где: +`Где:- `<оконная_функция>(<поле_таблицы>)` — используемая оконная функция. Например `AVG(price)`. -- `<оконная_функция>(<поле_таблицы>)` — используемая оконная функция. Например `AVG(price)`. - Далее следует `OVER`, который определяет окно (группу строк), которое будет передаваться в оконную функцию. - Если конструкцию `OVER ()` оставить без параметров, то окном будет выступать вся таблица. - -Далее внутри `OVER` следуют 3 необязательных параметра, с помощью которых можно гибко настраивать окно: - -- с помощью `PARTITION BY <столбцы_для_разделения>` выборка делится на + Если конструкцию `OVER ()` оставить без параметров, то окном будет выступать вся таблица.Далее внутри `OVER` следуют 3 необязательных параметра, с помощью которых можно гибко настраивать окно:- с помощью `PARTITION BY <столбцы_для_разделения>` выборка делится на непересекающиеся подмножества, где каждое подмножество содержит строки с одинаковыми значениями в одном или нескольких столбцах, образуются партиции. - с помощью `ORDER BY <столбцы_для_сортировки>` устанавливается порядок строк внутри окна, особо важную роль играет в оконных функциях ранжирования. -- с помощью `ROWS|RANGE <определение_диапазона_строк>` формируется диапазоны строк. С помощью этого параметра можно указать сколько строк брать до и после - текущей в окно. - -На каждом из этих параметров мы подробнее остановимся в следующих статьях. - -## Пример использования оконной функции - -Давайте с помощью оконных функций попробуем получить список имён студентов и то, сколько человек у них в классе. - - - -Для начала давайте получим список студентов и идентификатор класса, в котором они учатся: - -```sql-Schedule-executable -SELECT - Student.first_name, - Student.last_name, - Student_in_class.class -FROM - Student_in_class -JOIN - Student ON Student_in_class.student = Student.id; -``` - -А теперь, чтобы вычислить сколько учащихся учится в каждом из классов и вывести эту информацию в новую колонку, -мы можем применить оконную функцию: - -```sql-Schedule-executable +- с помощью `ROWS|RANGE <определение_диапазона_строк>` формируются диапазоны строк. С помощью этого параметра можно указать, сколько строк брать до и после + текущей в окно.На каждом из этих параметров мы подробнее остановимся в следующих статьях.## Пример использования оконной функцииДавайте с помощью оконных функций попробуем получить список имён студентов и то, сколько человек у них в классе.ER-диаграмма базы данных Schedule: [открыть на SQL Academy](https://sql-academy.org/ru/guide/windows-functions).Для начала давайте получим список студентов и идентификатор класса, в котором они учатся:```sql + SELECT + Student.first_name, + Student.last_name, + Student_in_class.class + FROM + Student_in_class + 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 SELECT Student.first_name, Student.last_name, @@ -117,26 +151,100 @@ FROM Student_in_class JOIN Student ON Student_in_class.student = Student.id; -``` - -### Что делает наша оконная функция ? - -Выражение `PARTITION BY Student_in_class.class` разделяет все строки таблицы на партиции по полю `class`. +```| 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` -совпадает с полем `class` в текущей строке. - -Функция `COUNT` же возвращает количество переданных в неё строк, тем самым мы и получаем сколько учащихся -учится в каждом из классов. - -## Порядок выполнения оконных функций в SELECT - -При использовании оконный функций важно понимать, в какой последовательности они будут исполняться. Так, как мы +совпадает с полем `class` в текущей строке.Функция `COUNT` же возвращает количество переданных в неё строк, тем самым мы и получаем сколько учащихся +учится в каждом из классов.## Порядок выполнения оконных функций в SELECTПри использовании оконных функций важно понимать, в какой последовательности они будут исполняться. Так, как мы можем увидеть на схеме ниже, окна отрабатывают предпоследним шагом, уже после фильтрации и группировки, но -перед финальной сортировкой результатов выборки. - -![Очередь выполнения оконной функции в SELECT запросе](https://sql-academy.org/static/guidePage/windows-functions/query-order.png "Очередь выполнения оконной функции в SELECT запросе") +перед финальной сортировкой результатов выборки.![Очередь выполнения оконной функции в SELECT запросе](https://sql-academy.org/static/guidePage/windows-functions/query-order.png "Очередь выполнения оконной функции в SELECT запросе")## ЗаключениеВ этой статье мы кратко рассмотрели понятие оконных функций, их возможности и практическую пользу. +В следующих статьях мы более подробно рассмотрим каждый аспект оконных функций.И напоследок давайте проверим, все ли мы поняли:**Какое ключевое отличие между оконными функциями и агрегатными функциями с группировкой в 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..d4cdf22 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..0401f4d 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..d8f085d 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,327 @@ 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` -- `id` - поле типа `SERIAL` (автоинкрементное целое число), являющееся первичным ключом; -- `name` - поле строкового типа с максимальной длиной в 255 символов, являющееся обязательным к заполнению; -- `age` - поле числового типа со значением по умолчанию равным 18. + Указывает, что значения в данной колонке должны быть отличными от `NULL`. -## CURRENT_TIMESTAMP как значение по умолчанию +- `DEFAULT` -`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; -``` +**MySQL** -### PostgreSQL - -Для того, чтобы посмотреть описание созданной таблицы, можно воспользоваться SQL запросом к информационной схеме: - -```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` - поле числового типа, являющееся первичным ключом с автоинкрементом; -#### Первичный ключ +**PostgreSQL** -Если вы не определили первичный ключ с помощью параметров столбца, то это можно сделать с помощью дополнительных параметров таблицы, добавив запись `PRIMARY KEY (<столбец_1>, <столбец_n>)` после перечисления столбцов: +- `id` - поле типа SERIAL (автоинкрементное целое число), являющееся первичным ключом; -```sql -CREATE TABLE Users ( - id INTEGER, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL DEFAULT 18, - PRIMARY KEY (id) -); -``` + -#### Внешние ключи +- `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` для всех пользователей, работавших в удалённой компании. - -`ON UPDATE CASCADE` означает, что если компания изменит свой идентификатор, то все пользователи (`Users`) получат новый идентификатор в поле `company`. +| Field | Type | Null | Key | Default | Extra | +| ----- | ------------ | ---- | --- | ------- | -------------- | +| id | int | NO | PRI | NULL | auto_increment | +| name | varchar(255) | NO | | NULL | | +| age | int | NO | | 18 | | -### 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 | | +| 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) -); -``` + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + PRIMARY KEY (id) + ); + ``` -Для того, чтобы при добавлении новых записей в таблицу `Users` гарантировать, что в колонке `company` находится идентификатор, существующий в таблице `Companies`, используется внешний ключ. Он имеет следующий синтаксис: +**PostgreSQL** -```sql -FOREIGN KEY (<столбец_1>, <столбец_n>) -REFERENCES <внешняя_таблица> (<столбец_во_внешней_таблице_1>, <столбец_во_внешней_таблице_n>) -[ON DELETE действие] -[ON UPDATE действие] -``` +- Первичный ключ. -Полный запрос для создания таблицы с внешним ключом будет таким: + Если вы не определили первичный ключ с помощью параметров столбца, то это можно сделать с помощью дополнительных параметров таблицы, добавив запись `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) -); -``` + ```sql + CREATE TABLE Users ( + id INTEGER, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL DEFAULT 18, + PRIMARY KEY (id) + ); + ``` + +**MySQL** -При наличии внешних ключей можно определить поведение текущей записи при изменении или удалении записи, на которую она ссылается: +- Внешние ключи. -```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". -``` + Предположим, что мы хотим хранить данные о компании, в которой работают наши пользователи. Давайте создадим небольшую таблицу `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 +378,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..ccc2599 100644 --- a/course/module-6/indexes/article.md +++ b/course/module-6/indexes/article.md @@ -1,30 +1,17 @@ --- meta: - title: "Индексы в SQL: ускорение поиска данных в MySQL и PostgreSQL" - description: "Полное руководство по индексам в SQL, объясняющее, как они упрощают и ускоряют поиск данных в таблицах баз данных в MySQL и PostgreSQL. Узнайте, как создавать, управлять и оптимизировать индексы для улучшения производительности ваших запросов." + title: "Индексы в SQL: ускорение поиска данных в MySQL и PostgreSQL" + description: "Полное руководство по индексам в SQL, объясняющее, как они упрощают и ускоряют поиск данных в таблицах баз данных в MySQL и PostgreSQL. Узнайте, как создавать, управлять и оптимизировать индексы для улучшения производительности ваших запросов." --- -# Индексы в SQL - -Когда вы добавляете в таблицу новую строку, СУБД размещает эти данные не оптимально. Например, если +![Иллюстрация к статье](https://sql-academy.org/static/guidePage/indexes/banner.jpg)# Индексы в SQLКогда вы добавляете в таблицу новую строку, СУБД размещает эти данные не оптимально. Например, если вы добавляете строку в таблицу `Users`, СУБД не размещает строки в числовом порядке значений столбца `id` или в алфавитном порядке значений столбца `last_name`. -Вместо этого он просто помещает данные в следующее доступное место в файле (СУБД поддерживает список свободных мест для каждой таблицы). - -Это приводит к тому, что для выполнения запроса типа: - -```sql +Вместо этого он просто помещает данные в следующее доступное место в файле (СУБД поддерживает список свободных мест для каждой таблицы).Это приводит к тому, что для выполнения запроса типа:```sql SELECT email FROM Users WHERE email LIKE 'l%'; -``` - -Серверу базы данных приходится проверять каждую строку таблицы, чтобы найти соответствия. -Это подходит для маленьких таблиц, но становится чрезмерно времязатратным по мере роста объёма данных. - -Для сравнения как запрос на поиск по `email` отработает в зависимости от наличия индекса на поле. - -![Сравнение скорости поиска в таблице с индексом](https://sql-academy.org/static/guidePage/indexes/statistic_ru.png "Сравнение скорости поиска в таблице с индексом") -Индексы функционируют как предметные указатели в книге 📖, позволяя быстро находить информацию +````Серверу базы данных приходится проверять каждую строку таблицы, чтобы найти соответствия. +Это подходит для маленьких таблиц, но становится чрезмерно времязатратным по мере роста объёма данных.Для сравнения как запрос на поиск по `email` отработает в зависимости от наличия индекса на поле.![Сравнение скорости поиска в таблице с индексом](https://sql-academy.org/static/guidePage/indexes/statistic_ru.png "Сравнение скорости поиска в таблице с индексом")Индексы функционируют как предметные указатели в книге 📖, позволяя быстро находить информацию без прочтения всего текста. Они представляют собой специальные таблицы, строки которых, в отличие от обычных таблиц данных, расположены в строго определённом порядке. Но вместо того, чтобы содержать все данные о некоторой @@ -32,278 +19,149 @@ SELECT email FROM Users WHERE email LIKE 'l%'; найти строки в таблице данных, вместе с информацией, описывающей, где физически расположена эта строка. Таким образом, роль индексов состоит в том, чтобы облегчить поиск подмножества строк и столбцов таблицы без -необходимости сканировать каждую строку в таблице. - -## Создание индекса ✨ - -Возвращаясь к таблице `Users`, вы можете добавить +необходимости сканировать каждую строку в таблице.## Создание индекса ✨Возвращаясь к таблице `Users`, вы можете добавить индекс к столбцу `email`, чтобы ускорить любые запросы, которые работают -со значением этого столбца. - - - -Вот как можно добавить такой индекс в СУБД MySQL: - -```sql +со значением этого столбца.**MySQL**Вот как можно добавить такой индекс в СУБД MySQL:```sql CREATE INDEX idx_email ON Users (email); -``` - -Эта инструкция создаёт индекс c именем `idx_email` для столбца `Users.email`. При наличии индекса оптимизатор запросов может выбрать использование индекса, если +```Эта инструкция создаёт индекс c именем `idx_email` для столбца `Users.email`. При наличии индекса оптимизатор запросов может выбрать использование индекса, если сочтёт это полезным. Если в таблице имеется более одного индекса, оптимизатор должен решить, применение какого именно индекса наиболее выгодно -для конкретной инструкции SQL. - -Все системы управления базами данных предоставляют возможность просмотра существующих индексов. +для конкретной инструкции SQL.Все системы управления базами данных предоставляют возможность просмотра существующих индексов. Для пользователей MySQL существует команда `SHOW`, которая позволяет отобразить все индексы -для конкретной таблицы, как показано в примере ниже: - -```sql +для конкретной таблицы, как показано в примере ниже:```sql SHOW INDEX FROM Users; -``` - -Вывод демонстрирует, что в таблице `Users` есть 2 индекса: один — для столбца `id` с именем `PRIMARY` -и ещё один для столбца `email`, который мы только что определили. - -Когда таблица была создана, MySQL автоматически сгенерировала +```| 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`, который мы только что определили.Когда таблица была создана, MySQL автоматически сгенерировала индекс для столбца первичного ключа, которым в данном случае является `id`, и присвоил индексу имя `PRIMARY`. Это особый тип индекса, используемый с ограничением первичного ключа, которое гарантирует, что каждое значение в столбце или группе столбцов, назначенных в качестве первичного ключа таблицы, -уникально и не может быть `NULL`. - - - - - -Вот как можно добавить такой индекс в СУБД PostgreSQL: - -```sql +уникально и не может быть `NULL`.**PostgreSQL**Вот как можно добавить такой индекс в СУБД PostgreSQL:```sql CREATE INDEX idx_email ON Users (email); -``` - -Эта инструкция создаёт индекс c именем `idx_email` для столбца `Users.email`. При наличии индекса оптимизатор запросов может выбрать использование индекса, если +```Эта инструкция создаёт индекс c именем `idx_email` для столбца `Users.email`. При наличии индекса оптимизатор запросов может выбрать использование индекса, если сочтёт это полезным. Если в таблице имеется более одного индекса, оптимизатор должен решить, применение какого именно индекса наиболее выгодно -для конкретной инструкции SQL. - -Все системы управления базами данных предоставляют возможность просмотра существующих индексов. +для конкретной инструкции SQL.Все системы управления базами данных предоставляют возможность просмотра существующих индексов. Для пользователей PostgreSQL можно использовать запрос к системным таблицам для отображения всех индексов -для конкретной таблицы: - -```sql +для конкретной таблицы:```sql SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'users'; -``` - -PostgreSQL автоматически создаёт индекс для столбца первичного ключа, которым в данном случае является +```| 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`. Это особый тип индекса, используемый с ограничением первичного ключа, которое гарантирует, что каждое значение в столбце или группе столбцов, назначенных в качестве первичного ключа таблицы, -уникально и не может быть `NULL`. - -PostgreSQL поддерживает различные типы индексов: - -- **B-tree** (по умолчанию) — для операций сравнения и сортировки +уникально и не может быть `NULL`.PostgreSQL поддерживает различные типы индексов:- **B-tree** (по умолчанию) — для операций сравнения и сортировки - **Hash** — для операций равенства - **GIN** — для составных значений (массивы, JSON) - **GiST** — для геометрических данных и полнотекстового поиска -- **BRIN** — для очень больших таблиц с естественной сортировкой - - - -## Удаление индекса - - - -Если после создания индекса вы решите, что он больше не нужен, можете -удалить его следующим образом: - -```sql +- **BRIN** — для очень больших таблиц с естественной сортировкой## Удаление индекса**MySQL**Если после создания индекса вы решите, что он больше не нужен, можете +удалить его следующим образом:```sql DROP INDEX idx_email ON Users; -``` - - - - - -Если после создания индекса вы решите, что он больше не нужен, можете -удалить его следующим образом: - -```sql +```**PostgreSQL**Если после создания индекса вы решите, что он больше не нужен, можете +удалить его следующим образом:```sql DROP INDEX idx_email; -``` - - - -## Уникальные (UNIQUE) индексы - -При проектировании баз данных важно определить, для каких столбцов допускаются повторения значений, -а для каких — нет. - -Например, в таблице `Users` может быть несколько пользователей с одинаковыми именами, +```## Уникальные (UNIQUE) индексыПри проектировании баз данных важно определить, для каких столбцов допускаются повторения значений, +а для каких — нет.Например, в таблице `Users` может быть несколько пользователей с одинаковыми именами, но идентификаторы и адреса электронных почт они должны иметь разные, чтобы -была возможность их различать. - -Добиться гарантируемой уникальности значений можно, создав уникальный индекс на столбец `Users.email`. -Уникальный индекс выполняет две функции: - -- он обеспечивает все преимущества стандартного индекса -- он предотвращает дублирование значений в индексируемом столбце - -Система управления базой данных будет проверять уникальный индекс при попытке добавления или +была возможность их различать.Добиться гарантируемой уникальности значений можно, создав уникальный индекс на столбец `Users.email`. +Уникальный индекс выполняет две функции:- он обеспечивает все преимущества стандартного индекса +- он предотвращает дублирование значений в индексируемом столбцеСистема управления базой данных будет проверять уникальный индекс при попытке добавления или изменения данных в индексированном столбце, чтобы убедиться, что введённое значение не дублирует -уже существующее в таблице. - -Создание уникального индекса для столбца `Users.email` выполняется следующим образом: - -```sql +уже существующее в таблице.Создание уникального индекса для столбца `Users.email` выполняется следующим образом:```sql CREATE UNIQUE INDEX idx_email ON Users (email); -``` - - - -При наличии индекса вы получите сообщение об ошибке, если попытаетесь добавить нового клиента с уже существующим адресом электронной -почты: - -```sql +```**MySQL**При наличии индекса вы получите сообщение об ошибке, если попытаетесь добавить нового клиента с уже существующим адресом электронной +почты:```sql Error(1062) 23000: "Duplicate entry 'duplicate@gmail.com' for key 'users.idx_email'" -``` - - - - - -При наличии индекса вы получите сообщение об ошибке, если попытаетесь добавить нового клиента с уже существующим адресом электронной -почты: - -```sql +```**PostgreSQL**При наличии индекса вы получите сообщение об ошибке, если попытаетесь добавить нового клиента с уже существующим адресом электронной +почты:```sql ERROR: duplicate key value violates unique constraint "idx_email" DETAIL: Key (email)=(duplicate@gmail.com) already exists. -``` - - - -Создание уникальных индексов для столбца или столбцов, определённых как первичный ключ, излишне, +```Создание уникальных индексов для столбца или столбцов, определённых как первичный ключ, излишне, так как система управления базой данных автоматически обеспечивает уникальность значений первичного ключа. Впрочем, размещение нескольких уникальных индексов в одной таблице допустимо и может быть целесообразно, -если вы видите в этом необходимость. - -## Многостолбцовые индексы - -Помимо одностолбцовых индексов, существует возможность создавать индексы, +если вы видите в этом необходимость.## Многостолбцовые индексыПомимо одностолбцовых индексов, существует возможность создавать индексы, включающие в себя несколько столбцов. К примеру, для поиска студентов по имени и фамилии можно создать совместный индекс -по этим двум полям: - -```sql +по этим двум полям:```sql CREATE INDEX idx_full_name ON Student (last_name, first_name); -``` - -Такой индекс окажется полезным для запросов, где необходимы и имя, и фамилия, или только фамилия. +```Такой индекс окажется полезным для запросов, где необходимы и имя, и фамилия, или только фамилия. Однако, для запросов, задающих только имя, он не принесёт пользы. Это аналогично поиску номера телефона по телефонному справочнику: если известны и имя, и фамилия, поиск упрощается благодаря упорядоченности справочника по фамилии, а затем по имени. -Если же известно только имя, придётся перебирать все записи в поисках нужного человека. - -При создании индексов, включающих несколько столбцов, важно продумать порядок столбцов в индексе, +Если же известно только имя, придётся перебирать все записи в поисках нужного человека.При создании индексов, включающих несколько столбцов, важно продумать порядок столбцов в индексе, чтобы он был максимально эффективным. Однако для достижения нужной производительности запросов всегда -можно создать несколько индексов с теми же столбцами, но разным порядком их следования. - -## Как используются индексы - -Индексы часто применяются СУБД для эффективного поиска нужных строк в таблице, +можно создать несколько индексов с теми же столбцами, но разным порядком их следования.## Как используются индексыИндексы часто применяются СУБД для эффективного поиска нужных строк в таблице, а затем для получения дополнительных данных из связанных таблиц по запросу пользователя. -Возьмём для примера запрос: - -```sql-executable-Schedule +Возьмём для примера запрос:```sql SELECT id, first_name, last_name FROM Student WHERE first_name LIKE 'A%' AND last_name LIKE 'L%' -``` - -В ответ на такой запрос СУБД может выбрать один из нескольких подходов: - -- Произвести полное сканирование всех строк таблицы. +```В ответ на такой запрос СУБД может выбрать один из нескольких подходов:- Произвести полное сканирование всех строк таблицы. - Воспользоваться индексом по столбцу `last_name` для поиска студентов с фамилией на «L», а затем проверить каждую из этих строк на соответствие имени, начинающегося на «A». -- Использовать составной индекс по `last_name` и `first_name` для непосредственного нахождения студентов, удовлетворяющих обоим критериям. - -Последний метод представляется наиболее эффективным, так как позволяет найти все необходимые строки -за один проход, избегая повторного обращения к таблице. - - - -Но как определить, какой из методов выберет оптимизатор запросов MySQL? +- Использовать составной индекс по `last_name` и `first_name` для непосредственного нахождения студентов, удовлетворяющих обоим критериям.Последний метод представляется наиболее эффективным, так как позволяет найти все необходимые строки +за один проход, избегая повторного обращения к таблице.**MySQL**Но как определить, какой из методов выберет оптимизатор запросов MySQL? Для этого можно использовать команду `EXPLAIN`, которая показывает, как СУБД планирует -выполнить запрос, не запуская его фактически: - -```sql +выполнить запрос, не запуская его фактически:```sql EXPLAIN SELECT id, first_name, last_name FROM Student WHERE first_name LIKE 'A%' AND last_name LIKE 'L%'; -``` - -Анализируя результаты, можно увидеть, что в столбце `possible_keys` указаны потенциально +```| id | select\_type | table | partitions | possible\_keys | key | +| -- | ------------ | ------- | ---------- | ------------------------------- | --------------- | +| 1 | SIMPLE | Student | | idx\_full\_name,idx\_last\_name | idx\_full\_name |Анализируя результаты, можно увидеть, что в столбце `possible_keys` указаны потенциально применимые индексы `idx_last_name` или `idx_full_name`, а в столбце `key` указано, -что выбран индекс `idx_full_name`. - - - - - -Но как определить, какой из методов выберет оптимизатор запросов PostgreSQL? +что выбран индекс `idx_full_name`.**PostgreSQL**Но как определить, какой из методов выберет оптимизатор запросов PostgreSQL? Для этого можно использовать команду `EXPLAIN`, которая показывает, как СУБД планирует -выполнить запрос: - -```sql +выполнить запрос:```sql EXPLAIN SELECT id, first_name, last_name FROM Student WHERE first_name LIKE 'A%' AND last_name LIKE 'L%'; -``` - -Также можно использовать `EXPLAIN ANALYZE` для получения реальной статистики выполнения: - -```sql +```| 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 EXPLAIN ANALYZE SELECT id, first_name, last_name FROM Student WHERE first_name LIKE 'A%' AND last_name LIKE 'L%'; -``` - -Анализируя результаты `EXPLAIN`, можно увидеть, какой метод доступа выбрал оптимизатор — -полное сканирование таблицы (Seq Scan) или сканирование индекса (Index Scan). - - - -## Обратная сторона индексов - -Если индексы столь эффективны, возникает вопрос: почему бы просто не индексировать всё подряд? 🧐 - -Ответ кроется в том, что каждый индекс представляет собой таблицу (пусть и особый тип +```| 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).## Обратная сторона индексовЕсли индексы столь эффективны, возникает вопрос: почему бы просто не индексировать всё подряд? 🧐Ответ кроется в том, что каждый индекс представляет собой таблицу (пусть и особый тип таблицы, но все же это таблица). Следовательно, каждый раз, когда строка добавляется в таблицу или удаляется из неё, должны быть изменены все индексы в этой таблице. При обновлении строки любые индексы для столбца (или столбцов), которые были затронуты, также должны быть изменены. Следовательно, чем больше у вас индексов, тем больше должна работать СУБД, чтобы поддерживать все объекты схемы в актуальном состоянии — что -приводит к замедлению работы. - -Более того, индексы занимают дополнительное место на диске и требуют внимательного управления +приводит к замедлению работы.Более того, индексы занимают дополнительное место на диске и требуют внимательного управления со стороны администраторов баз данных. Поэтому оптимальным решением является создание индексов только тогда, когда это действительно необходимо. Если индекс нужен временно, например, для выполнения месячного отчёта, его можно добавить перед началом процедуры и удалить после её -завершения. - -В итоге, идеальный подход заключается в нахождении баланса: необходимо иметь достаточно индексов +завершения.В итоге, идеальный подход заключается в нахождении баланса: необходимо иметь достаточно индексов для эффективной работы, но не столько, чтобы это сказывалось на производительности. Если вы не уверены в нужном количестве индексов, начните с минимального их числа и добавляйте -по мере необходимости. +по мере необходимости.**Давайте проверим, как вы усвоили тему:**Какое утверждение наилучшим образом объясняет причину, по которой **не следует** индексировать каждый столбец в таблице базы данных?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 0f6f929..74c25da 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,7 +30,7 @@ meta: В качестве простого примера предположим, что вы хотите частично скрыть адреса электронной почты в таблице пользователей (`Users`). - +ER-диаграмма базы данных Airbnb: [открыть на SQL Academy](https://sql-academy.org/ru/guide/view). Это может быть полезно, например, если политика вашей компании не позволяет всем использовать конфиденциальную информацию об пользователях. @@ -38,7 +38,7 @@ meta: представление с именем `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..3421d54 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 | | +| 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`. ## Пример создания индекса: