|
|
@@ -1,10 +1,6 @@
|
|
|
-<table style="width: 100%;"><tr><td style="width: 40%;">
|
|
|
-<a href="../articles/5_1_1_1_erd_workbench.md">Создание ER-диаграммы
|
|
|
-</a></td><td style="width: 20%;">
|
|
|
-<a href="../readme.md">Содержание
|
|
|
-</a></td><td style="width: 40%;">
|
|
|
-<a href="../articles/sql_import.md">Создание базы данных. Импорт данных.
|
|
|
-</a></td><tr></table>
|
|
|
+Предыдущая лекция | | Следующая лекция
|
|
|
+:----------------:|:----------:|:----------------:
|
|
|
+[Словарь данных](./5_1_1_1_data_dictionary.md) | [Содержание](../readme.md#проектирование-баз-данных) | [Создание базы данных. Импорт данных.](./sql_import.md)
|
|
|
|
|
|
# Основы SQL (синтаксис MySQL)
|
|
|
|
|
|
@@ -41,6 +37,14 @@
|
|
|
|
|
|
* **Transaction Control Language (TCL)** – группа операторов для управления транзакциями. Транзакция – это команда или блок команд (инструкций), которые успешно завершаются как единое целое, при этом в базе данных все внесенные изменения фиксируются на постоянной основе или отменяются, т.е. все изменения, внесенные любой командой, входящей в транзакцию, будут отменены.
|
|
|
|
|
|
+## Ключевое слово USE
|
|
|
+
|
|
|
+В одной СУБД может быть создано несколько баз данных. При выполнении SQL команд мы можем либо указывать нужную БД в команде, либо предварительно указать какая база будет использоваться для комад
|
|
|
+
|
|
|
+```sql
|
|
|
+USE db_name;
|
|
|
+```
|
|
|
+
|
|
|
## Data Manipulation Language (DML)
|
|
|
|
|
|
### Базовый синтаксис SQL команды SELECT
|
|
|
@@ -50,7 +54,7 @@
|
|
|
Общая структура запроса:
|
|
|
|
|
|
```sql
|
|
|
-SELECT [DISTINCT | ALL] поля_таблиц
|
|
|
+SELECT [DISTINCT | ALL] поля_таблиц | функция | литерал
|
|
|
[FROM список_таблиц]
|
|
|
[WHERE условия_на_ограничения_строк]
|
|
|
[GROUP BY условия_группировки]
|
|
|
@@ -70,8 +74,8 @@ SELECT [DISTINCT | ALL] поля_таблиц
|
|
|
* **GROUP BY** используется для группировки строк
|
|
|
* **HAVING** применяется после группировки строк для фильтрации по значениям агрегатных функций
|
|
|
* **ORDER BY** используется для сортировки. У него есть два параметра:
|
|
|
-* **ASC** (по умолчанию) используется для сортировки по возрастанию
|
|
|
-* **DESC** — по убыванию
|
|
|
+ * **ASC** (по умолчанию) используется для сортировки по возрастанию
|
|
|
+ * **DESC** — по убыванию
|
|
|
* **LIMIT** используется для ограничения количества строк для вывода
|
|
|
|
|
|
#### SQL-псевдонимы
|
|
|
@@ -80,7 +84,7 @@ SELECT [DISTINCT | ALL] поля_таблиц
|
|
|
|
|
|
Например, если в вашей таблице есть столбец **goodTypeId**, вы можете переименовать его просто в **id**, для того, чтобы сделать его более коротким и удобным в использовании в будущем.
|
|
|
|
|
|
-Для создания псевдонимов используется оператор AS:
|
|
|
+Для создания псевдонимов используется оператор `AS`:
|
|
|
|
|
|
```sql
|
|
|
SELECT
|
|
|
@@ -153,8 +157,6 @@ SELECT поля_таблиц
|
|
|
[логический_оператор другое_условия_на_ограничения_строк];
|
|
|
```
|
|
|
|
|
|
-В описанной структуре запроса необязательные параметры указаны в квадратных скобках.
|
|
|
-
|
|
|
В условном операторе применяются операторы сравнения, специальные и логические операторы.
|
|
|
|
|
|
#### Операторы сравнения
|
|
|
@@ -262,10 +264,10 @@ ESCAPE '!';
|
|
|
|
|
|
Логические операторы необходимы для связывания нескольких условий ограничения строк.
|
|
|
|
|
|
-* Оператор NOT — меняет значение специального оператора на противоположный
|
|
|
-* Оператор OR — общее значение выражения истинно, если хотя бы одно из них истинно
|
|
|
-* Оператор AND — общее значение выражения истинно, если они оба истинны
|
|
|
-* Оператор XOR — общее значение выражения истинно, если один и только один аргумент является истинным
|
|
|
+* Оператор **NOT** — меняет значение специального оператора на противоположный
|
|
|
+* Оператор **OR** — общее значение выражения истинно, если хотя бы одно из них истинно
|
|
|
+* Оператор **AND** — общее значение выражения истинно, если они оба истинны
|
|
|
+* Оператор **XOR** — общее значение выражения истинно, если один и только один аргумент является истинным
|
|
|
|
|
|
Выведем все полёты, которые были совершены на самолёте «Boeing», но, при этом, вылет был не из Лондона:
|
|
|
|
|
|
@@ -335,7 +337,7 @@ id | name | phone
|
|
|
1 | Иванов| 322223
|
|
|
2 | Петров| 111111
|
|
|
|
|
|
->Сводные выборки нам понадобятся при импорте данных в базу. Сначала вы выделяете из таблиц импорта словари. А потом из таблиц импорта и словарей формируете запрос `INSERT ... SELECT` для записи данных в основную таблицу.
|
|
|
+>Сводные выборки нам понадобятся при импорте данных в базу.
|
|
|
|
|
|
#### Вложенные SQL запросы
|
|
|
|
|
|
@@ -391,7 +393,7 @@ WHERE
|
|
|
);
|
|
|
```
|
|
|
|
|
|
-С помощью данного запроса возможно получить самого старшего члена семьи. Здесь используется подзапрос для получения максимальной даты рождения, которая затем используется для фильтрации строк.
|
|
|
+С помощью данного запроса возможно получить самого младшего члена семьи. Здесь используется подзапрос для получения максимальной даты рождения, которая затем используется для фильтрации строк.
|
|
|
|
|
|
#### Подзапросы с ANY, IN, ALL
|
|
|
|
|
|
@@ -469,7 +471,7 @@ SELECT поля_таблицы_1 FROM таблица_1
|
|
|
|
|
|
```sql
|
|
|
SELECT поля_таблицы_1
|
|
|
- FROM (подзапрос) [AS] псевдоним_производной_таблицы
|
|
|
+ FROM (подзапрос) AS псевдоним_производной_таблицы
|
|
|
```
|
|
|
|
|
|
Обратите внимание на то, что для производной таблицы обязательно должен указываться её псевдоним, для того, чтобы имелась возможность обратиться к ней в других частях запроса.
|
|
|
@@ -498,7 +500,7 @@ INSERT INTO имя_таблицы [(поле_таблицы, ...)]
|
|
|
|
|
|
```sql
|
|
|
INSERT INTO Goods (goodId, goodName, `type`)
|
|
|
- VALUES (5, 'Table', 2);
|
|
|
+ VALUES (5, 'Table', 2), (6, 'Table2', 1);
|
|
|
```
|
|
|
|
|
|
```sql
|
|
|
@@ -624,130 +626,6 @@ DELETE FROM Products
|
|
|
DELETE FROM Products;
|
|
|
```
|
|
|
|
|
|
-<!--
|
|
|
-## Импорт данных (старые скрины из MSSQL)
|
|
|
-
|
|
|
-Теперь, зная синткасис команд INSERT и SELECT, можем разобраться как создать из исходного набора данных словари и загрузить данные в БД с учетом внешних ключей
|
|
|
-
|
|
|
-Допустим есть список агентов (данные полученные от заказчика в виде CSV-файла), у которых есть поля название, тип и т.д. (далее по тексту я её называю *таблица импорта*)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-В структуре БД поле "тип агента" создано как внешний ключ на таблицу типов
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-### Заполнение словарей
|
|
|
-
|
|
|
-Для добавления "типов агентов" в таблицу **AgentType** мы будем использовать альтернативный синтаксис `INSERT ... SELECT`
|
|
|
-
|
|
|
-1. Пишем инструкцию **SELECT**, которая выбирает уникальные записи из *таблицы импорта*:
|
|
|
-
|
|
|
- ```sql
|
|
|
- SELECT
|
|
|
- DISTINCT Тип_агента
|
|
|
- FROM
|
|
|
- agents_import
|
|
|
- ```
|
|
|
-
|
|
|
- 1. Ключевое слово **DISTINCT** относится только к тому полю, перед которым написано. В нашем случае выбирает уникальные названия типов агентов.
|
|
|
- 2. Откуда брать поле **Image** в предметной области не написано и в исходных данных его нет. Но т.к. в целевой таблице это поле не обязательное, то можно его пропустить
|
|
|
-
|
|
|
- Этот запрос можно выполнить отдельно, чтобы проверить что получится
|
|
|
-
|
|
|
-2. После отладки запроса **SELECT** перед ним допишем запрос **INSERT**:
|
|
|
-
|
|
|
- ```sql
|
|
|
- INSERT INTO AgentType (Title)
|
|
|
- SELECT
|
|
|
- DISTINCT Тип_агента
|
|
|
- FROM
|
|
|
- agents_import
|
|
|
- ```
|
|
|
-
|
|
|
- 1. Поле **ID** можно пропустить, оно автоинкрементное и создастся само
|
|
|
- 2. Количество и порядок вставляемых полей `(Title)` должно быть равным количеству выбираемых полей `(Тип_агента)`
|
|
|
-
|
|
|
- Если в таблице есть обязательные поля, а нам неоткуда взять для них данные, то мы можем в **SELECT** вставить фиксированные значения (в примере пустая строка):
|
|
|
-
|
|
|
- ```sql
|
|
|
- INSERT INTO AgentType (Title, Image)
|
|
|
- SELECT
|
|
|
- DISTINCT Тип_агента, ''
|
|
|
- -- ^^
|
|
|
- FROM
|
|
|
- agents_import
|
|
|
- ```
|
|
|
-
|
|
|
-### Заполнение основной таблицы
|
|
|
-
|
|
|
-1. Тоже сначала пишем **SELECT** запрос, чтобы проверить те ли данные получаются
|
|
|
-
|
|
|
- * напоминаю, что порядок и количество выбираемых и вставляемых полей должны быть одинаковыми
|
|
|
-
|
|
|
- * в поле **AgentTypeID** мы должны вставить ID соответсвующей записи из таблицы **AgentType**, поэтому выборка у нас из двух таблиц и чтобы не писать перед каждым полем полные названия таблиц мы присваиваем им алиасы
|
|
|
-
|
|
|
- ```sql
|
|
|
- SELECT
|
|
|
- asi.Наименование_агента,
|
|
|
- att.ID,
|
|
|
- asi.Юридический_адрес,
|
|
|
- asi.ИНН,
|
|
|
- asi.КПП,
|
|
|
- asi.Директор,
|
|
|
- asi.Телефон_агента,
|
|
|
- asi.Электронная_почта_агента,
|
|
|
- asi.Логотип_агента,
|
|
|
- asi.Приоритет
|
|
|
- FROM
|
|
|
- agents_import asi,
|
|
|
- AgentType att
|
|
|
- WHERE
|
|
|
- asi.Тип_агента=att.Title
|
|
|
- ```
|
|
|
-
|
|
|
- Т.е. мы выбираем перечисленные поля из таблицы **agents_import** и добавляем к ним ID агента у которого совпадает название.
|
|
|
-
|
|
|
- При выборке из нескольких таблиц исходные данные перемножаются. Т.е. если мы не заполним перед этой выборкой словарь, то `100 * 0 = пустая выборка`.
|
|
|
-
|
|
|
- Если же мы не укажем условие **WHERE**, то выберутся, к примеру, `100 * 10 = 1000` записей (каждый агент будет в каждой категории). Поэтому важно, чтобы условие **WHERE** выбирало **уникальные** значения.
|
|
|
-
|
|
|
- Естественно, количество внешних ключей в таблице может быть больше одного, в таком случае в секции **FROM** перечисляем все используемые словари и в секции **WHERE** перечисляем условия для всех таблиц объединив их логическим выражением **AND**
|
|
|
-
|
|
|
- ```sql
|
|
|
- ...
|
|
|
- WHERE
|
|
|
- a.Name=b.Name AND a.Title=c.Title AND a.Price=d.Price ...
|
|
|
- ```
|
|
|
-
|
|
|
- где алиасы b, c, d - словарные таблицы, а алиас "а" - *таблица импорта*
|
|
|
-
|
|
|
-2. Написав и проверив работу выборки (она должна возвращать столько же записей, сколько в *таблице импорта*) дописываем команду вставки данных:
|
|
|
-
|
|
|
- ```sql
|
|
|
- INSERT INTO Agent (Title, AgentTypeID, Address, INN, KPP, DirectorName, Phone, Email, Logo, Priority)
|
|
|
- SELECT
|
|
|
- asi.Наименование_агента,
|
|
|
- att.ID,
|
|
|
- asi.Юридический_адрес,
|
|
|
- asi.ИНН,
|
|
|
- asi.КПП,
|
|
|
- asi.Директор,
|
|
|
- asi.Телефон_агента,
|
|
|
- asi.Электронная_почта_агента,
|
|
|
- asi.Логотип_агента,
|
|
|
- asi.Приоритет
|
|
|
- FROM
|
|
|
- agents_import asi,
|
|
|
- AgentType att
|
|
|
- WHERE
|
|
|
- asi.Тип_агента=att.Title
|
|
|
- ```
|
|
|
--->
|
|
|
-
|
|
|
## Data Definition Language (DDL)
|
|
|
|
|
|
**Data Definition Language (DDL)** – это группа операторов **определения** данных. Другими словами, с помощью операторов, входящих в эту группы, мы определяем структуру базы данных и работаем с объектами этой базы, т.е. создаем, изменяем и удаляем их.
|
|
|
@@ -768,7 +646,7 @@ CREATE DATABASE [IF NOT EXISTS] db_name
|
|
|
|
|
|
Оператор `CREATE DATABASE` создает базу данных с указанным именем. Если база данных уже существует и не указан ключевой параметр `IF NOT EXISTS`, то возникает ошибка выполнения команды.
|
|
|
|
|
|
-Если в названии базы данных присутствуют пробелы или название совпадает с ключевым словом SQL, то название можно экранировать символами обратной кавычки (подобное экранирование применяется и к названиям других сущностей):
|
|
|
+Если в названии базы данных присутствуют пробелы или название совпадает с ключевым словом SQL, то название можно экранировать символами обратной кавычки (подобное экранирование применяется и к названиям других сущностей и атрибутов):
|
|
|
|
|
|
```
|
|
|
CREATE DATABASE `database`
|
|
|
@@ -859,7 +737,7 @@ CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
|
|
|
)
|
|
|
```
|
|
|
|
|
|
- * индекс
|
|
|
+ * индекс (альтернативный ключ)
|
|
|
|
|
|
синтаксис:
|
|
|
|
|
|
@@ -881,7 +759,7 @@ CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
|
|
|
|
|
|
* `index_name` - название индекса
|
|
|
|
|
|
- * `index_col_name` - название колонки, входящей в ключ индекса: `col_name [(length)]`. Содержимое колонки может быть обрезано по длине `length`
|
|
|
+ * `index_col_name` - название колонки (колонок), входящей в ключ индекса: `col_name [(length)]`. Содержимое колонки может быть обрезано по длине `length`
|
|
|
|
|
|
Ключ `UNIQUE` может иметь только различающиеся значения. При попытке добавить новую строку с ключом, совпадающим с существующей строкой, возникает ошибка выполнения команды.
|
|
|
|
|
|
@@ -920,18 +798,18 @@ CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
|
|
|
|
|
|
```sql
|
|
|
-- таблица "склад"
|
|
|
- CREATE TABLE `warehouse` (
|
|
|
+ CREATE TABLE `Warehouse` (
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
|
`title` varchar(100) DEFAULT NULL,
|
|
|
`quantity` int(11) DEFAULT NULL,
|
|
|
)
|
|
|
|
|
|
-- таблица "продажи"
|
|
|
- CREATE TABLE `sales` (
|
|
|
+ CREATE TABLE `Sales` (
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
|
`warehouse_id` int(11) DEFAULT NULL,
|
|
|
`quantity` int(11) DEFAULT NULL,
|
|
|
- CONSTRAINT `sales_FK`
|
|
|
+ CONSTRAINT `FK_sales_warehouse`
|
|
|
FOREIGN KEY (`warehouse_id`)
|
|
|
REFERENCES `warehouse` (`id`)
|
|
|
)
|
|
|
@@ -983,7 +861,7 @@ ALTER [IGNORE] TABLE tbl_name alter_spec [, alter_spec ...]
|
|
|
```sql
|
|
|
-- добавление внешнего ключа в таблицу "продажи"
|
|
|
ALTER TABLE `sales`
|
|
|
- ADD CONSTRAINT `sales_FK`
|
|
|
+ ADD CONSTRAINT `FK_sales_warehouse`
|
|
|
FOREIGN KEY (`warehouse_id`)
|
|
|
REFERENCES `warehouse` (`id`);
|
|
|
```
|
|
|
@@ -1017,12 +895,16 @@ ALTER [IGNORE] TABLE tbl_name alter_spec [, alter_spec ...]
|
|
|
|
|
|
## Задание
|
|
|
|
|
|
-Написать скрипт, создающий базу данных по ERD вашего курсового проекта.
|
|
|
+Прорешать несколько задач из [SQL Академии](https://sql-academy.org/ru/trainer). Количество не менее 5-ти, на троечку лёгкие, на четверку средние, на пятерку сложные.
|
|
|
+
|
|
|
+Результаты опубликовать в репозитории (скрины со сложностью задачи, текстом запроса и результатом. ERD не включать)
|
|
|
+
|
|
|
+Пример:
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+В верхней части пишете текст запроса, в нижней видите результат. Справа есть ERD для базы данных.
|
|
|
|
|
|
-<table style="width: 100%;"><tr><td style="width: 40%;">
|
|
|
-<a href="../articles/5_1_1_1_erd_workbench.md">Создание ER-диаграммы
|
|
|
-</a></td><td style="width: 20%;">
|
|
|
-<a href="../readme.md">Содержание
|
|
|
-</a></td><td style="width: 40%;">
|
|
|
-<a href="../articles/sql_view.md">Представления (View)
|
|
|
-</a></td><tr></table>
|
|
|
+Предыдущая лекция | | Следующая лекция
|
|
|
+:----------------:|:----------:|:----------------:
|
|
|
+[Словарь данных](./5_1_1_1_data_dictionary.md) | [Содержание](../readme.md#проектирование-баз-данных) | [Создание базы данных. Импорт данных.](./sql_import.md)
|