Изменение значений полей в таблице
Чтобы изменить значение в поле в таблице БД необходимо выполнить запрос UPDATE.
Общий синтаксис запроса UPDATE
UPDATE [LOW_PRIORITY] имя_таблицы SET название_поля1=выражение1,название_поля2=выражение2,... [WHERE условное_выражение] [LIMIT количество_записей]
UPDATE заменит значения текущих полей таблицы на новые значения.
SET устанавливает какие поля изменять и новые значения, которые нужно присвоить этим полям.
WHERE (если необходимо) — условие на изменение определенных записей. Если WHERE не указан, изменены будут все записи.
При указании параметра LOW_PRIORITY, выполнение UPDATE задержится пока другие клиенты читают таблицу.
Пример запроса на изменение всех записей поля «apple» таблицы «fruit» на определенное значение
UPDATE fruit SET apple=5;
Пример запроса с WHERE который изменяет определенную запись:
UPDATE tovar SET price=500 WHERE id=5
При изменении значения поля можно использовать его текущее значение.
Пример запроса увеличивающего значение поля price в 2 раза:
UPDATE tovar SET price=price*2;
SET в UPDATE вычисляет выражения слева направо.
Пример запроса который удваивает цену (поле price), а потом уменьшает его на 10:
UPDATE tovar SET price=price*2, price=price-10;
Запрос UPDATE возвратит количество полей, которые были изменены в этом запросе.
Использование LIMIT позволит изменять заданное количество записей.
Под обновлением данных в БД подразумевается изменение значений в существующих записях таблицы. При этом возможно как изменение значений полей в группе строк (даже всех строк таблицы), так и правка значения поля отдельной строки.
В SQL, изменить запись в таблице БД можно с помощью команды UPDATE. В самом минимальном виде команда обновления данных выглядит следующим образом:
UPDATE таблица SET поле = значение
Здесь, UPDATE – команда указывающая, что запрос на обновление данных;
таблица – название таблицы, в которой будет проводиться изменения;
SET – команда, после которой через запятую указываются поля с назначаемыми им значениями;
поле – поле таблицы, в которое будет внесено изменение;
значение – новое значение, которое будет внесено в поле.
Например, если необходимо задать полю во всех строках таблицы значение равное нулю, можно выполнить такой запрос:
UPDATE goods SET price = 0
В этом случае, поле price абсолютно во всех имеющиеся строках таблицы примет значение 0.
Изменение одного значения
Изменение значения всех полей в таблице необходимо крайне редко. Чаще всего необходимо поменять значение какой-то конкретной записи. Для этого в завершении строки с командой UPDATE будет добавлена директива WHERE, в которой указывается условие, определяющее с какой именно строкой нужно выполнить операцию обновления.
Имеется таблица:
num (номер товара) |
title (название) |
price (цена) |
1 | Чайник | 300 |
2 | Чашка | 100 |
3 | Ложка | 25 |
4 | Тарелка | 100 |
Для примера, нужно обновить стоимость товара с известным нам его значением num. Для этого, выполним следующий запрос:
UPDATE goods SET price = 150 WHERE num = 2
Теперь, перед операцией изменения полей, будет выбрана строка, удовлетворяющая условию num = 2. Такая строка в таблице одна. В этой стоке цена и будет изменена на значение 150. В результате получим таблицу с измененной ценой товара.
Внесение изменений в несколько строк с условием отбора
Если вспомнить все многообразие условий в запросе, можно представить себе насколько разнообразными могут быть выборки. Поэтому и запросы на обновления могут выполняться либо с одной строкой, либо с группой строк, либо со всеми строками таблицы. Все зависит от стоящей перед вами задачи, а так же с какими строками таблицы нужно выполнять операции обновления.
Например, мы хотим уменьшить в два раза цену всех товаров, которые сейчас стоят от 100 и более. Запрос:
UPDATE goods SET price = price / 2 WHERE price >= 100
Условие WHERE здесь содержит правило, по которому будут выбраны только товары с ценой равной или более 100, а те товары, цена у которых ниже 100, затронуты запросом не будут.
price = price / 2 – формула, по которой будет вычисляться новая цена товаров. Новая цена будет записана равной старой цене поделенной на два.
В результате выполнения такого запроса получим таблицу с измененными записями:
num (номер товара) |
title (название) |
price (цена) |
1 | Чайник | 150 |
2 | Чашка | 50 |
3 | Ложка | 25 |
4 | Тарелка | 50 |
Обновление значений в нескольких полях строки
При необходимости обновлять сразу несколько полей, все поля с их значениями указываются после директивы SET через запятую. Например, нужно изменить название и цену товара с кодом 2 на «утюг», стоимостью 300:
UPDATE goods SET title = "утюг", price = 300 WHERE num = 2
Такой запрос каждому соответствующему полю в строке назначит его значение. А условие укажет, в какой именно строке будут выполнены изменения.
Выше приведены основные виды операций обновления. На их основе формируется запросы для решения большинства задач изменения данных в разработке с применением SQL.
Обновление данных в базах — один из ключевых элементов при работе в MySQL. Под обновлением подразумевается изменение значений в существующих записях таблицы. Обновление допускает различные варианты: как изменение значений полей в группе строк (в том числе и всех строк таблицы), так и корректировку значения поля отдельной строки.
Для полноценной работы как с локальными базами данных, так и с облачными базами данных timeweb.cloud, важно понимать синтаксис команд для обновления данных.
Ключевой командой для изменения записей в таблице базы данных в MySQL является UPDATE
. Обновление происходит последовательно, от первой до последней строки, по порядку. В зависимости от типа обновления в MySQL выделяется два синтаксиса для оператора UPDATE
.
В случае обновления одной таблицы синтаксис выглядит следующим образом:
UPDATE LOW_PRIORITY IGNORE table_reference
SET assignment_list
WHERE where_condition
ORDER BY ...
LIMIT row_count
Обязательный параметр:
SET assignment_list
— указывает, какие столбцы нужно изменить и каким образом (assignment_list — список столбцов и новых значений).
Необязательные параметры:
LOW_PRIORITY
— если указан этот параметр, выполнениеUPDATE
откладывается до тех пор, пока другой пользователь не решит просмотреть данные таблицы.IGNORE
— в этом сценарии выполнениеUPDATE
не прерывается, даже если в процессе возникают какие-либо ошибки. Если возникают дубликаты в столбце с уникальным ключом, то такие строки не обновляются.WHERE where_condition
— широко известный оператор задает условия, по которым отбираются строки для обновления (where_condition — список условий). Если параметрыWHERE
не указаны, обновятся все строки таблицы.ORDER BY
— если указан этот параметр, строки обновляются в заданном порядке.LIMIT row_count
— ограничение на количество обновляемых строк (row_count — некое число строк). Считаются строки, которые попадают под условиеWHERE
, независимо от того, изменились они или нет.
В случае обновления нескольких таблиц одновременно синтаксис будет следующим:
UPDATE LOW_PRIORITY IGNORE table_references
SET assignment_list
WHERE where_condition
table_references
— список таблиц, которые мы хотим изменить. Они изменятся таким образом, как указано в assignment_list.
При обновлении нескольких таблиц нельзя использовать параметр ORDER BY
или LIMIT
. Помимо этого, при обновлении нескольких таблиц нет гарантий, что они будут обновлены в указанном порядке.
Остальные параметры запроса (необязательные) — LOW_PRIORITY
, IGNORE
и WHERE
— работают так же, как в сценарии обновления одной таблицы.
Итак, давайте рассмотрим примеры использования оператора UPDATE в MySQL.
Для начала создадим базу данных для книжного магазина. В ней будет 4 таблицы: книги, жанры, писатели и покупки.
Воспользуемся операторами CREATE TABLE
и INSERT INTO
, чтобы создать таблицы author, genre, book и sales.
CREATE TABLE author (
id INT PRIMARY KEY AUTO_INCREMENT,
name_author VARCHAR(50) NOT NULL
);
INSERT INTO author (name_author)
VALUES ('Leo Tolstoy'),
('Franz Kafka'),
('Nikolai Gogol'),
('William Shakespeare'),
('Homer');
CREATE TABLE genre (
id INT PRIMARY KEY AUTO_INCREMENT,
name_genre VARCHAR(30) NOT NULL
);
INSERT INTO genre (name_genre)
VALUES ('Realist novel'),
('Dystopian novel'),
('Picaresque novel'),
('Epic poetry');
CREATE TABLE book (
book_id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(50),
author_id INT NOT NULL,
genre_id INT,
price DECIMAL(8,2) NOT NULL,
amount INT DEFAULT 0,
FOREIGN KEY (author_id) REFERENCES author (id),
FOREIGN KEY (genre_id) REFERENCES genre (id)
);
INSERT INTO book (title, author_id, genre_id, price, amount)
VALUES ('Anna Karenina', 1,1, 650.00, 15),
('The Castle', 2,2, 570.20, 6),
('Dead Souls', 3,3, 480, 2),
('Iliad', 5,4, 518.99, 4),
('Odyssey', 5,4, 518.99, 7);
CREATE TABLE sales (
id INT PRIMARY KEY AUTO_INCREMENT,
book_id INT NOT NULL,
count INT NOT NULL,
cost DECIMAL(8,2) NOT NULL,
FOREIGN KEY (book_id) REFERENCES book (book_id)
);
Получаем следующие таблицы. Таблица book:
Столбцы:
- book_id – уникальный идентификатор книги;
- title – название книги;
- author_id – идентификатор автора (внешний ключ);
- genre_id – идентификатор жанра (внешний ключ);
- price – цена книги за один экземпляр;
- amount – количество книг на складе.
Таблица genres:
Столбцы:
- id – уникальный идентификатор;
- name_genre – обозначение жанра.
Таблица author:
Столбцы:
- id – уникальный идентификатор;
- name_author – имя автора книги.
Таблица sales:
Столбцы:
- id – уникальный идентификатор операции;
- book_id – уникальный идентификатор книги из таблицы book (внешний ключ);
- count – количество купленных книг;
- cost – общая стоимость товаров.
Операции по обновлению данных
Теперь, создав образец базы данных, мы покажем выполнение различных операций по обновлению данных с использованием оператора UPDATE и других команд в MySQL.
1. Обновление всех строк
Если при использовании UPDATE
вы не используете задающий условия параметр WHERE
, то будут обновлены все строки в таблице. Предположим, в книжном магазине проходит акция «Всё по 500» — изменим цену всех книг на фиксированную 500 рублей:
UPDATE book
SET price=500;
В результате выполнения запроса мы получим такую табличку:
Если мы попробуем присвоить значение, которое уже находится в столбце, то MySQL заметит это и не обновит его.
Если мы захотим присвоить значение NULL столбцу, при создании которого было указано NOT NULL, то запрос вернет ошибку:
Column 'name_column' cannot be null
В то же время, если указать параметр IGNORE
, то значение будет изменено на значение по умолчанию для конкретного типа: 0 для числовых, “” для символьных и «нулевое» для дат. Например, 0000 для типа данных YEAR или 0000-00-00 00:00:00 для типа DATETIME.
2. Обновление строк с условием
Изменение всех строк таблицы требуется довольно редко. Гораздо чаще нам необходимо обновить значения для какой-то конкретной записи или для нескольких. Допустим, мы хотим изменить строки по какому-то условию. Например, устроим распродажу книг, которых осталось в наличии меньше 5 штук. Для этого в MySQL с командой UPDATE используем оператор WHERE:
UPDATE book
SET price=300
WHERE amount < 5;
Результат выполнения запроса:
Хорошо видно, что изменились только строки с книгами Dead Souls и Iliad, так как только они удовлетворяли прописанному в запросе условию.
3. Обновление значений с выражением
При обновлении мы можем задавать столбцу не только статичное значение, но и выражения. Предположим, в магазине проходит акция, и на книги русских писателей объявлена скидка в 15%:
UPDATE book
SET price=price * 0.85
WHERE author_id in (1,3);
В таблице author имеется только два русских писателя – Leo Tolstoy и Nikolai Gogol с author_id 1 и 3 соответственно.
Результат выполнения запроса:
Обновление значений происходит в определенном порядке: слева направо. Например, следующий запрос сначала увеличит значение amount на 1, а потом удвоит его:
UPDATE book
SET amount = amount + 1, amount =amount*2;
Результат выполнения запроса:
4. Обновление с DEFAULT
Также мы можем изменить значение строк на значения «по умолчанию» DEFAULT, которые задаются при создании или изменении таблицы. Для того чтобы узнать, какие значения в нашей таблице используются по умолчанию, выполним запрос:
DESC book
В результате получим следующую структуру нашей таблицы в MySQL:
Заменим значения столбца amount на значение DEFAULT. Так как по умолчанию значение для amount было 0, мы должны получить все 0:
UPDATE book
SET amount=DEFAULT;
Результат выполнения запроса соответствует ожиданиям:
5. Обновление нескольких столбцов
Используя один запрос, мы можем обновить сразу несколько столбцов. Например, изменим значения цены и количества у строк со значением book_id < 4:
UPDATE book
SET price=price*0.9,
amount = amount - 1
WHERE book_id < 4;
Результат выполнения запроса:
6. Использование LIMIT
Используя параметр LIMIT, мы можем ограничить количество записей, которые должны быть обновлены. Например, обновим только первую строку:
UPDATE book
SET price=100
WHERE genre_id = 4
LIMIT 1;
В таблице имеется две строки с genre_id равным 4, но, так как мы указали LIMIT 1, обновится только одна:
Также следует отметить, что LIMIT N вовсе не означает, что мы обновим N строк. В результате запроса произойдёт обработка первых N строк, подходящих под условие WHERE, независимо от того, обновились эти строки в итоге или нет.
7. Обновление нескольких таблиц
В MySQL мы можем обновить сразу несколько таблиц:
UPDATE book, author
SET amount=amount + 3,
author.name_author = '-'
WHERE book.book_id = 4 and author.id = 4;
Результат запроса в таблице book:
Результат запроса в таблице authors:
8. Обновление таблиц с объединением (INNER JOIN)
Во время обновления можно также объединять таблицы при помощи команды INNER JOIN.
UPDATE book b INNER JOIN author a
ON b.author_id = a.id
SET b.title = CONCAT(b.title, ' (', a.name_author,')');
Указывать INNER необязательно, так как этот тип объединения используется по умолчанию. Запрос можно переписать следующим образом, и мы получим такой же результат:
UPDATE book, author a
SET b.title = CONCAT(b.title, ' (', a.name_author,')')
WHERE b.author_id = a.id;
9. Обновление таблиц с объединением (LEFT JOIN)
Также мы можем использовать LEFT JOIN. В этом случае обязательно указывать, что мы используем именно левое объединение. Например, можно изменить на складе количество книг после их покупки. Добавим в таблицу sales две строки:
INSERT INTO sales (book_id, count, cost)
VALUES (1, 3, (SELECT price FROM book WHERE book_id = 1)*3),
(3, 1, (SELECT price FROM book WHERE book_id = 3)*1);
Магазин продал 3 книги Anna Karenina и 1 книгу Dead Souls. Выполним запрос:
UPDATE book LEFT JOIN sales on book.book_id = sales.book_id
SET amount = amount - count
WHERE sales.book_id is not NULL;
В итоге обновления видим, что количество книг на складе уменьшилось (для тех, которые мы продали):
Если мы попробуем не использовать LEFT JOIN, то получим ошибку «Out of range value for column ‘amount’ at row 3», т.к. amount не может быть отрицательным. Или, если добавить IGNORE, получим:
Как можно видеть в данном случае во всех строках количество уменьшилось на три книги, что нам не очень подходит.
10. Обновление с CASE, IF, IFNULL, COALESCE
При обновлении таблицы также возможно использовать условные операторы, такие как CASE, IF и т.д.
Функция CASE проверяет истинность набора условий и, в зависимости от результата, возвращает один из возможных результатов. Синтаксис при работе с UPDATE в MySQL для операторов CASE и WHEN будет следующий:
UPDATE book
SET price =
CASE genre_id
WHEN 1 THEN 100
WHEN 2 THEN 150
ELSE price
END;
В данном случае, если книга имеет жанр 1 мы устанавливаем стоимость 100, если жанр 2 – стоимость 150.
Результат выполнения запроса:
Функция IF в зависимости от результата условного выражения возвращает одно из двух значений. Если книга имеет жанр 4, то мы уменьшаем ее стоимость на 200, иначе оставляем стоимость прежней:
UPDATE book
SET price = IF (genre_id = 4, price-200, price);
Результат выполнения запроса:
Функция IFNULL проверяет значение выражения – если оно имеет значение NULL, то возвращается определенное значение, в противном случае возвращается само выражение. Пусть одно из значений amount оказалось NULL:
Проверим все значения в столбце amount, и если встретится NULL, заменим его на 0:
UPDATE book
SET amount = IFNULL(amount, 0);
Результат выполнения запроса:
Функция COALESCE довольна похожа на IFNULL. Основная особенность заключается в том, что данная функция может принимать сразу несколько значений (два и более). Как и IFNULL, возвращает первое не равное NULL.
Для того чтобы посмотреть, как работает этот вариант, создадим таблицу следующего вида:
И выполним запрос:
UPDATE test_table
SET col4 = COALESCE(col1, col2, col3, 'нет значения');
Результат выполнения запроса:
11. Обновление с сортировкой
Сортировка может помочь при обновлении поля с уникальным ключом. Если мы захотим сдвинуть наши id на 1, то, изменив первую строку, мы получим две строки, у которых id = 2, и возникнет ошибка. Но если добавить ORDER BY и начать обновлять с конца, то запрос успешно выполнится:
UPDATE book
SET book_id=book_id+1
Результат выполнения запроса:
12. Обновление на основе данных из других таблиц
Также в MySQL при работе с UPDATE в условии WHERE возможно использовать вложенные команды SELECT и FROM. В рассматриваемом примере мы сначала получаем идентификатор жанра ‘Epic poetry’, а потом на основе полученного значения отбираем строки для обновления таблицы.
UPDATE book
SET amount = 0
WHERE genre_id = (
SELECT id
FROM genre
Where name_genre = 'Epic poetry'
);
Как вариант, мы можем выбрать значения, которые нужно изменить, используя запрос:
UPDATE book
SET price = (
SELECT MIN (cost)
FROM sales)
WHERE amount < 5;
Мы изменяем значения price всех книг, у которых количество на складе меньше 5, на минимальную сумму продажи.
Минимальная сумма продаж у нас 480:
В этой ситуации невозможно обновить таблицу, выбрав значения из той же таблицы в подзапросе. Но есть вариант использовать небольшую хитрость – мы можем объединить таблицу с собой:
UPDATE book AS book_1
INNER JOIN(
SELECT genre_id, MIN(amount) AS min_amount
FROM book
GROUP BY genre_id
) AS book_2 ON book_1.genre_id = book_2.genre_id
SET book_1.amount = book_2.min_amount;
В данном случае подзапрос создает временную таблицу для присоединения и закрывает ее до того, как начнется выполнение UPDATE.
Подзапрос находит минимальное количество книг для каждого жанра, после чего используется для обновления столбца amount. В нашей таблице только у жанра 4 имеется больше одной строки. Значения в обеих строках должно замениться на минимальное для этого жанра – 4.
Результат выполнения запроса:
Есть еще один вариант обновления – использование SELECT FROM SELECT:
UPDATE book AS book_1
SET book_1.price = (SELECT MIN(price) AS min_price FROM (
SELECT price
FROM book) as book_2);
В данном случае также создается временная таблица. Однако в этом случае присваивается только одно значение всем строкам.
Заключение
Мы постарались максимально подробно раскрыть особенности применения оператора UPDATE в MySQL. Но, конечно, практическое применение может продемонстрировать немало других интересных вариантов.
Оператор UPDATE в SQL (Structured Query Language) позволяет изменять данные, хранящиеся в таблице базы данных. В данной документации мы рассмотрим, как использовать оператор UPDATE, а также предоставим примеры для лучшего понимания.
Синтаксис
Оператор UPDATE имеет следующий синтаксис:
UPDATE имя_таблицы SET столбец1 = значение1, столбец2 = значение2, ... WHERE условие;
- UPDATE имя_таблицы: Указывает таблицу, в которой необходимо изменить данные.
- SET столбец1 = значение1, столбец2 = значение2, …: Задает новые значения для указанных столбцов.
- WHERE условие: Опционально. Определяет условие, по которому будут выбраны строки для обновления. Если условие не указано, будут обновлены все строки.
Примеры
Предположим, у нас есть следующая таблица employees
:
id | first_name | last_name | salary |
---|---|---|---|
1 | Иван | Иванов | 50000 |
2 | Петр | Петров | 55000 |
3 | Сергей | Сергеев | 60000 |
4 | Андрей | Андреев | 65000 |
Пример 1: Обновление одного столбца
Допустим, мы хотим увеличить зарплату Ивана Иванова на 10%. Для этого используем следующий запрос:
UPDATE employees SET salary = salary * 1.1 WHERE id = 1;
Результат обновления:
id | first_name | last_name | salary |
---|---|---|---|
1 | Иван | Иванов | 55000 |
2 | Петр | Петров | 55000 |
3 | Сергей | Сергеев | 60000 |
4 | Андрей | Андреев | 65000 |
Пример 2: Обновление нескольких столбцов
Предположим, что мы хотим изменить имя и фамилию сотрудника с ID 4. Для этого используем следующий запрос:
UPDATE employees SET first_name = 'Алексей', last_name = 'Алексеев' WHERE id = 4;
Результат обновления:
id | first_name | last_name | salary |
---|---|---|---|
1 | Иван | Иванов | 55000 |
2 | Петр | Петров | 55000 |
3 | Сергей | Сергеев | 60000 |
4 | Алексей | Алексеев | 65000 |
Пример 3: Обновление всех строк таблицы
Предположим, что компания решила увеличить зарплату всем сотрудникам на 5%. Для этого используем следующий запрос:
UPDATE employees SET salary = salary * 1.05;
Результат обновления:
id | first_name | last_name | salary |
---|---|---|---|
1 | Иван | Иванов | 57750 |
2 | Петр | Петров | 57750 |
3 | Сергей | Сергеев | 63000 |
4 | Алексей | Алексеев | 68250 |
Пример 4: Обновление строк с использованием подзапросов
Допустим, мы хотим увеличить зарплату сотрудникам с зарплатой ниже средней. Сначала вычислим среднюю зарплату:
SELECT AVG(salary) FROM employees;
Предположим, что средняя зарплата равна 61625. Теперь увеличим зарплату на 10% для сотрудников с зарплатой ниже средней:
UPDATE employees SET salary = salary * 1.1 WHERE salary < (SELECT AVG(salary) FROM employees);
Результат обновления:
id | first_name | last_name | salary |
---|---|---|---|
1 | Иван | Иванов | 63525 |
2 | Петр | Петров | 63525 |
3 | Сергей | Сергеев | 63000 |
4 | Алексей | Алексеев | 68250 |
Более сложные примеры
Теперь давайте перейдем к более сложным примерам и функциям, которые помогут вам освоить оператор UPDATE на более глубоком уровне.
Обновление данных с подзапросами
Иногда необходимо обновить данные в одной таблице на основе данных из другой таблицы. В этом случае можно использовать оператор JOIN. Рассмотрим следующий пример.
Пример 1: Обновление данных с использованием подзапросов
Предположим, у нас есть две таблицы: employees
и departments
.
Таблица employees
:
id | first_name | last_name | department_id | salary |
---|---|---|---|---|
1 | Иван | Иванов | 1 | 50000 |
2 | Петр | Петров | 2 | 55000 |
3 | Сергей | Сергеев | 1 | 60000 |
4 | Андрей | Андреев | 3 | 65000 |
Таблица departments
:
id | department_name | bonus |
---|---|---|
1 | IT | 10 |
2 | HR | 5 |
3 | Marketing | 15 |
Теперь мы хотим увеличить зарплату каждому сотруднику на основе процентного бонуса их отдела. Для этого используем следующий запрос:
UPDATE employees SET salary = salary * (1 + (SELECT bonus FROM departments WHERE employees.department_id = departments.id) / 100);
Результат обновления:
id | first_name | last_name | department_id | salary |
---|---|---|---|---|
1 | Иван | Иванов | 1 | 55000 |
2 | Петр | Петров | 2 | 57750 |
3 | Сергей | Сергеев | 1 | 66000 |
4 | Андрей | Андреев | 3 | 74750 |
В этом примере мы использовали подзапрос SELECT
Обновление данных с использованием транзакций
Транзакции позволяют выполнять несколько операций обновления одновременно и гарантируют их атомарность. В случае ошибки транзакция откатывается, и все изменения отменяются.
Пример 2: Обновление данных с использованием транзакций
Допустим, мы хотим перевести 10000 единиц зарплаты от сотрудника с ID 1 к сотруднику с ID 2. Для этого используем транзакцию:
BEGIN TRANSACTION; UPDATE employees SET salary = salary - 10000 WHERE id = 1; UPDATE employees SET salary = salary + 10000 WHERE id = 2; COMMIT;
Если оба запроса UPDATE выполнены успешно, транзакция будет завершена командой COMMIT, и изменения станут видимыми для других пользователей. В случае ошибки в любом из запросов, транзакция откатится, и все изменения будут отменены.
Результат обновления:
id | first_name | last_name | department_id | salary |
---|---|---|---|---|
1 | Иван | Иванов | 1 | 45000 |
2 | Петр | Петров | 2 | 67750 |
3 | Сергей | Сергеев | 1 | 66000 |
4 | Андрей | Андреев | 3 | 74750 |
Обновление данных с использованием условных выражений
Условные выражения позволяют выполнять различные операции обновления в зависимости от определенных условий.
Пример 3: Обновление данных с использованием CASE
Допустим, мы хотим увеличить зарплату сотрудникам с зарплатой ниже 60000 на 10%, а сотрудникам с зарплатой выше или равной 60000 на 5%. Для этого используем выражение CASE:
UPDATE employees SET salary = CASE WHEN salary < 60000 THEN salary * 1.1 ELSE salary * 1.05 END;
Результат обновления:
id | first_name | last_name | department_id | salary |
---|---|---|---|---|
1 | Иван | Иванов | 1 | 49500 |
2 | Петр | Петров | 2 | 60500 |
3 | Сергей | Сергеев | 1 | 63000 |
4 | Андрей | Андреев | 3 | 68250 |
Обновление данных с использованием CTE (Common Table Expressions)
CTE предоставляют возможность создания временных таблиц для использования в одном запросе. Это позволяет упростить сложные запросы и улучшить их производительность.
Пример 1: Обновление данных с использованием CTE
Предположим, у нас есть таблица employees
:
id | first_name | last_name | department_id | salary |
---|---|---|---|---|
1 | Иван | Иванов | 1 | 50000 |
2 | Петр | Петров | 2 | 55000 |
3 | Сергей | Сергеев | 1 | 60000 |
4 | Андрей | Андреев | 3 | 65000 |
Мы хотим увеличить зарплату сотрудникам, имеющим зарплату ниже медианы. Сначала найдем медианное значение зарплаты с использованием CTE:
WITH salary_median AS ( SELECT AVG(salary) AS median FROM ( SELECT salary FROM employees ORDER BY salary LIMIT 2 OFFSET (SELECT COUNT(*) / 2 - 1 FROM employees) ) sub ) UPDATE employees SET salary = salary * 1.1 WHERE salary < (SELECT median FROM salary_median);
Результат обновления:
id | first_name | last_name | department_id | salary |
---|---|---|---|---|
1 | Иван | Иванов | 1 | 55000 |
2 | Петр | Петров | 2 | 60500 |
3 | Сергей | Сергеев | 1 | 60000 |
4 | Андрей | Андреев | 3 | 65000 |
Использование триггеров для контроля изменений
Триггеры позволяют выполнять определенные действия при изменении данных в таблице. Используя триггеры, можно логировать изменения или контролировать правила обновления.
Пример 2: Создание триггера для логирования изменений зарплаты
Предположим, мы хотим сохранять историю изменений зарплаты для каждого сотрудника. Сначала создадим таблицу salary_history
:
CREATE TABLE salary_history ( id SERIAL PRIMARY KEY, employee_id INTEGER, old_salary INTEGER, new_salary INTEGER, changed_at TIMESTAMP );
Теперь создадим триггер, который будет записывать изменения зарплаты в таблицу salary_history
:
CREATE OR REPLACE FUNCTION log_salary_update() RETURNS TRIGGER AS $$ BEGIN INSERT INTO salary_history (employee_id, old_salary, new_salary, changed_at) VALUES (OLD.id, OLD.salary, NEW.salary, NOW()); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER salary_update_trigger AFTER UPDATE OF salary ON employees FOR EACH ROW EXECUTE FUNCTION log_salary_update();
Теперь, когда мы обновим зарплату сотрудника, триггер автоматически добавит запись в таблицу salary_history
:
UPDATE employees SET salary = salary * 1.1 WHERE id = 1;
Таблица salary_history
после обновления:
id | employee_id | old_salary | new_salary | changed_at |
---|---|---|---|---|
1 | 1 | 50000 | 55000 | 2023-03-21 12:34:56 |
Оптимизация производительности при обновлении данных
При работе с большими объемами данных, производительность обновлений может стать критическим фактором. Важно минимизировать время блокировки таблиц и количество записей, которые обновляются.
Пример 3: Обновление данных с использованием индексов
Предположим, у нас есть таблица employees
с большим количеством записей, и мы хотим увеличить зарплату сотрудникам с определенным department_id
. В этом случае, индекс по department_id
может значительно ускорить операцию:
CREATE INDEX employees_department_id_index ON employees(department_id);
Теперь выполним запрос обновления:
UPDATE employees SET salary = salary * 1.1 WHERE department_id = 2;
Использование индекса позволяет быстрее найти записи, которые необходимо обновить, и сократить время выполнения запроса.
Мы рассмотрели использование оператора UPDATE с CTE, триггерами и оптимизацией производительности. Эти темы помогут вам использовать оператор UPDATE для решения сложных задач и сделать ваш код более эффективным.
Нашли опечатку или ошибку? Выделите её и нажмите Ctrl+Enter
Помогла ли Вам эта статья?
#статьи
- 14 июл 2023
-
0
Эти команды нужны разработчикам, аналитикам, маркетологам и всем, кто хочет выжимать из данных максимум пользы.
Иллюстрация: Оля Ежак для Skillbox Media
Любитель научной фантастики и технологического прогресса. Хорошо сочетает в себе заумного технаря и утончённого гуманитария. Пишет про IT и радуется этому.
SQL — это язык запросов для управления реляционными базами данных. «Реляционные» означает, что все данные хранятся в виде взаимосвязанных таблиц. А SQL как раз используют для того, чтобы как-то влиять на элементы внутри этих таблиц: добавлять, удалять, изменять и так далее.
Язык SQL лежит в основе систем управления реляционными базами данных, таких как MySQL, PostgreSQL, Oracle и т.д. Таким образом, чтобы работать, скажем, с базой данных MySQL, нужно сперва изучить язык запросов SQL.
По синтаксису SQL-запросы максимально похожи на обычные предложения:
SELECT (Name, Age) FROM Clients WHERE Age > 20
Если перевести на русский, получится что-то вроде:
Выбрать Имя и Возраст из Таблицы с клиентами, где Возраст больше 20
В этой статье мы научимся читать такие запросы, понимать, как они работают, а заодно попрактикуемся в создании собственных. В результате у нас получится простая база данных с котами и их владельцами.
Подробнее о языке SQL и принципах его работы мы рассказывали в одной из предыдущих статей. Если хотите чуть лучше разбираться в технических нюансах языка, можно начать с неё. Но это не обязательно
Перед тем как писать команды, разберёмся, какие есть виды запросов в SQL. Всего их четыре — DDL, DML, DCL и TCL. Каждый из них выполняет определённые действия — давайте разберём каждую категорию подробнее.
DDL, или data definition language, нужен, чтобы определять данные. Эти запросы позволяют настраивать базу данных — создавать с нуля и прописывать её структуру.
Примеры DDL-запросов: CREATE, DROP, RENAME, ALTER.
DML, или data manipulation language, нужен, чтобы управлять данными в таблицах. Эти запросы помогают добавлять, обновлять, удалять и выбирать данные.
Примеры DML-запросов: SELECT, UPDATE, DELETE, INSERT.
DCL, или data control language, нужен, чтобы выдавать или отзывать права доступа для пользователей.
Примеры DCL-запросов: GRANT, REVOKE, DENY.
TCL, или transaction control language, нужен, чтобы управлять транзакциями. Это могут быть запросы, связанные с подтверждением или откатом изменений в базе данных.
Примеры TCL-запросов: COMMIT, ROLLBACK, BEGIN.
Инфографика: Оля Ежак для Skillbox Media
Теперь перейдём к тому, как SQL-запросы составляются и из каких элементов состоят.
Перед вами — пример классического SQL-запроса, который состоит из шести самых популярных операторов: два из них обязательные, а другие четыре — используются по обстоятельствам. Вместе они выглядят так:
- SELECT — выбирает отдельные столбцы или всю таблицу целиком (обязательный);
- FROM — из какой таблицы получить данные (обязательный);
- WHERE — условие, по которому SQL выбирает данные;
- GROUP BY — столбец, по которому мы будут группироваться данные;
- HAVING — условие, по которому сгруппированные данные будут отфильтрованы;
- ORDER BY — столбец, по которому данные будут отсортированы;
Давайте разберём каждую из частей этого запроса по порядку.
Любая команда должна начинаться с ключевого слова — или действия, которое должно произойти. Например, выбрать строку, вставить новую, изменить старую или удалить таблицу целиком.
Одно из таких ключевых слов — SELECT. Оно выбирает отдельные столбцы или таблицу целиком, чтобы потом передать данные другим запросам на обработку.
В качестве примера выберем столбцы Name и Age из таблицы Clients:
SELECT (Name, Age) FROM Clients
На выходе будут все строки таблицы, принадлежащие столбцам Name и Age.
Эта часть ставится после SELECT и нужна затем, чтобы указать, из какой таблицы или источника данных приходит информация. Здесь прописывается имя таблицы, с которой мы хотим работать.
Например, ранее мы уже выбирали данные из таблицы Clients:
SELECT (Name, Age) FROM Clients
В SQL всё построено на таблицах. Поэтому, если нужно получить данные из другого места — указываем другую таблицу.
Если нужно отфильтровать данные, используем слово WHERE. После него указывается условие, которому должны удовлетворять строки, чтобы они попали в результат выполнения запроса.
Например, этот запрос вернёт все строки из таблицы, где значения Age больше 20:
SELECT (Name, Age) FROM Clients WHERE Age > 20
Этот оператор помогает нам сгруппировать данные по определённым столбцам. В результате получим новую таблицу, составленную на основе выбранных данных.
Например, сгруппируем результат предыдущего запроса по городам:
SELECT (Name, Age) FROM Clients WHERE Age > 20 GROUP BY City
Запрос вернёт клиентов старше 20 лет и сгруппирует их по городам. Главное — чтобы столбец City присутствовал в таблице.
Нужен, чтобы собирать группы по определённым условиям. Его обычно используют в паре с GROUP BY, а по своей функциональности он похож на WHERE.
Например, укажем, чтобы в группы добавлялись только клиенты с суммой заказа от 1000 рублей:
SELECT (Name, PaymentAmount, Age) FROM Clients WHERE Age > 20 GROUP BY City HAVING PaymentAmount > 1000
Так как наш запрос растёт, будем каждую его часть выносить на новую строку — чтобы не запутаться. На корректность запроса это не повлияет, а читать его станет куда удобнее.
Позволяет сортировать полученные строки по возрастанию или убыванию. Работает как с числами, так и с символами. В качестве параметра нужно указать столбец, по которому надо выполнить сортировку.
Допустим, если хотим отсортировать клиентов по возрасту — от младшего к старшему, — добавляем команду ORDER BY Age:
SELECT (Name, PaymentAmount, Age) FROM Clients WHERE Age > 20 GROUP BY City HAVING PaymentAmount > 1000 ORDER BY Age
А чтобы отсортировать по убыванию, просто добавляем слово DESC:
SELECT (Name, PaymentAmount, Age) FROM Clients WHERE Age > 20 GROUP BY City HAVING PaymentAmount > 1000 ORDER BY Age DESC
Кроме этих шести операторов есть масса дополнительных — например, VIEW, UNION, LIKE. Они уникальны для каждого запроса и используются в зависимости от ситуации. Конечно, в этой статье мы не успеем разобрать все — если вам нужен полный список, можно заглянуть в эту шпаргалку по SQL.
Со структурой запросов разобрались, пришло время посоздавать таблицы. В качестве примера будем наполнять базу данных с котами, живущими в разных городах России.
Первым делом создаём базу данных. Делается это с помощью команды CREATE DATABASE:
CREATE DATABASE CatsCatsCats;
Внутри пока ничего нет. Но это пока.
Запрос создаёт таблицу в базе данных. В общем виде команда выглядит так:
CREATE TABLE table_name ( column1 datatype, column2 datatype, column3 datatype );
Чтобы задать свои параметры таблицы, на месте table_name пишем название, а в скобках указываем названия колонок и типы данных, которые они будут содержать.
В SQL много типов данных. Вот примеры самых популярных:
- INT — целое число;
- DATETIME — дата;
- VARCHAR — строка;
- FLOAT — десятичное число.
В нашей таблице используется два типа: строки (VARCHAR) и целые числа (INT):
CREATE TABLE CatsAndOwners ( CatID int(6) NOT NULL, CatName varchar(255) NOT NULL, CatAge int(6) NOT NULL, CatColor varchar(255) NOT NULL, CatOwnerName varchar(255) NOT NULL );
В примере выше мы добавили пять столбцов: уникальный номер кота CatID, его имя CatName, возраст CatAge, цвет CatColor и имя владельца CatOwnerName. А ещё задали, чтобы ни одно из полей не было пустым — NOT NULL.
Цифры рядом с типами данных обозначают, сколько бит выделяется для поля. Например, varchar (255) значит, что строка может принимать размер от 0 до 255 бит — по объёму данных это приблизительно соответствует фразе «Я люблю язык SQL».
Созданная таблица пока выглядит пустовато. Читайте дальше, чтобы узнать, как наполнить её данными и научиться группировать их по своему усмотрению.
CatID | CatName | CatAge | CatColor | CatOwnerName |
---|---|---|---|---|
| | | | |
Если вдруг забыли добавить столбец во время создания таблицы — ничего страшного. Новые колонки можно добавлять с помощью команды ALTER TABLE. Давайте добавим город проживания кота:
ALTER TABLE CatsAndOwners ADD City varchar(255);
В запросе указываем, в какую таблицу хотим внести изменения, а затем с помощью ключевого слова ADD добавляем название столбца и его тип данных.
Теперь таблица выглядит так:
CatID | CatName | CatAge | CatColor | CatOwnerName | City |
---|---|---|---|---|---|
| | | | | |
Вообще, возможности команды ALTER TABLE немного шире, чем мы разобрали в этом примере. Она заточена не только на добавление новых колонок, но и на удаление и редактирование существующих. Подробнее об этом поговорим чуть дальше, а пока — продолжим наполнять таблицу.
Позволяет добавить новую строку в таблицу. Для этого нужно указать, какие столбцы мы хотим заполнить и передать значения для них с помощью команды VALUES. Добавим несколько котов:
INSERT INTO CatsAndOwners(CatID, CatName, CatAge, CatColor, CatOwnerName, City) VALUES (1, 'Мурка', 3, 'Чёрная', 'Дмитрий', 'Москва'); INSERT INTO CatsAndOwners(CatID, CatName, CatAge, CatColor, CatOwnerName, City) VALUES (2, 'Белла', 7, 'Белая', 'Максим', 'Саратов'); INSERT INTO CatsAndOwners(CatID, CatName, CatAge, CatColor, CatOwnerName, City) VALUES (3, 'Симба', 5, 'Рыжий', 'Екатерина', 'Санкт-Петербург'); INSERT INTO CatsAndOwners(CatID, CatName, CatAge, CatColor, CatOwnerName, City) VALUES (4, 'Лео', 2, 'Полосатый', 'Александр', 'Екатеринбург'); INSERT INTO CatsAndOwners(CatID, CatName, CatAge, CatColor, CatOwnerName, City) VALUES (5, 'Мася', 1, 'Серый', 'Анна', 'Москва');
Обратите внимание: строки указываются в одинарных кавычках, а числа — без них. И, к сожалению, нельзя добавить несколько строк одной командой.
Блеск! Таблица наконец-то обзавелась данными:
CatID | CatName | CatAge | CatColor | CatOwnerName | City |
---|---|---|---|---|---|
1 | Мурка | 3 | Чёрная | Дмитрий | Москва |
2 | Белла | 7 | Белая | Максим | Саратов |
3 | Симба | 5 | Рыжий | Екатерина | Санкт-Петербург |
4 | Лео | 2 | Полосатый | Александр | Екатеринбург |
5 | Мася | 1 | Серый | Анна | Москва |
Запрос нужен, чтобы доставать данные из таблицы. Ранее мы уже успели познакомиться с этой командой, — давайте немного освежим память. Достанем из таблицы список котов и их владельцев:
SELECT CatName, CatOwnerName FROM CatsAndOwners;
Результат:
CatName | CatOwnerName |
---|---|
Мурка | Дмитрий |
Белла | Максим |
Симба | Екатерина |
Лео | Александр |
Мася | Анна |
Если нужно выбрать все столбцы из таблицы, после слова SELECT добавим символ *. В этом случае на выходе получим всю таблицу целиком.
SELECT * FROM CatsAndOwners;
Нужен, чтобы задавать условия для фильтрации строк. Например, можем выбрать только те, у которых значение CatAge больше 5:
SELECT CatName, CatAge FROM CatsAndOwners WHERE CatAge > 5
Результатом будет одна строка с двумя столбцами:
Оператор WHERE интересен тем, что внутри него можно указывать условия — причём сразу несколько. Делается это с помощью логических конструкций AND, OR и BETWEEN.
AND — это логическое И. Оно означает, что должны выполняться оба условия запроса одновременно. Например, кошка должна быть чёрной И проживать в Москве.
SELECT CatName FROM CatsAndOwners WHERE CatColor = 'Чёрная' AND City = 'Москва'
Результат:
OR — это логическое ИЛИ. Оно означает, что должно выполниться или одно условие, или второе. Например, кошка должна быть ИЛИ старше пяти лет, ИЛИ быть чёрной.
SELECT CatName FROM CatsAndOwners WHERE CatAge > 5 OR CatColor = 'Чёрная'
Результат:
BETWEEN — это оператор, который выбирает все элементы внутри заданного диапазона. Например, можно запросить всех кошек в возрасте от двух до шести лет.
SELECT CatName, CatAge FROM CatsAndOwners WHERE CatAge BETWEEN 2 AND 6
Результат:
CatName | CatAge |
---|---|
Мурка | 3 |
Симба | 5 |
Лео | 2 |
Все вышеуказанные операторы можно использовать одним пакетом:
SELECT CatName, CatAge FROM CatsAndOwners WHERE CatAge BETWEEN 2 AND 8 AND (City = 'Саратов' OR City = 'Санкт-Петербург') OR CatName = 'Мурка'
Результат:
CatName | CatAge |
---|---|
Мурка | 3 |
Белла | 7 |
Симба | 5 |
Сортирует полученные строки в заданном столбце по убыванию или по возрастанию. Например, можем выбрать всех кошек и отсортировать их от самых старших к самым младшим:
SELECT CatName, CatAge FROM CatsAndOwners ORDER BY CatAge DESC
Результат:
CatName | CatAge |
---|---|
Белла | 7 |
Симба | 5 |
Мурка | 3 |
Лео | 2 |
Мася | 1 |
Чтобы отсортировать записи по возрастанию, нужно просто убрать из запроса параметр DESC:
SELECT CatName, CatAge FROM CatsAndOwners ORDER BY CatAge
Результат:
CatName | CatAge |
---|---|
Мася | 1 |
Лео | 2 |
Мурка | 3 |
Симба | 5 |
Белла | 7 |
Выбранные строки можно сгруппировать по столбцам. Например, можем посмотреть, сколько кошек живёт в разных городах.
SELECT City, COUNT(*) AS CatCount FROM CatsAndOwners GROUP BY City;
В этом примере мы применили агрегатную функцию COUNT, которая посчитала количество строк в каждой группе. К функциям-агрегаторам мы вернёмся позже, а пока — насладимся результатом:
CatName | CatCount |
---|---|
Москва | 2 |
Саратов | 1 |
Санкт-Петербург | 1 |
Екатеринбург | 1 |
Также мы использовали оператор AS, чтобы задать название для новой колонки, в которую мы и собрали количество котов в разных городах.
Запрос позволяет ограничить количество строк в финальной выдаче. Например, можем указать, чтобы выводились только первые две строки из таблицы:
SELECT * FROM CatsAndOwners LIMIT 2;
Результат:
CatID | CatName | CatAge | CatColor | CatOwnerName | City |
---|---|---|---|---|---|
1 | Мурка | 3 | Чёрная | Дмитрий | Москва |
2 | Белла | 7 | Белая | Максим | Саратов |
Позволяет изменить данные в таблице. Допустим, кошка Симба сходила в парикмахерскую для животных и сменила цвет шёрстки на пурпурный. Отражаем эти изменения в таблице с помощью такого кода:
UPDATE CatsAndOwners SET CatColor = 'Пурпурный' WHERE CatName = 'Симба';
Всё просто: рядом с командой UPDATE пишем название таблицы, которую нужно обновить, затем рядом с SET указываем, какой именно столбец меняем и на какое значение, а в конце — определяем конкретную ячейку.
Результат:
CatID | CatName | CatAge | CatColor | CatOwnerName | City |
---|---|---|---|---|---|
1 | Мурка | 3 | Чёрная | Дмитрий | Москва |
2 | Белла | 7 | Белая | Максим | Саратов |
3 | Симба | 5 | Пурпурный | Екатерина | Санкт-Петербург |
4 | Лео | 2 | Полосатый | Александр | Екатеринбург |
5 | Мася | 1 | Серый | Анна | Москва |
Удаляет строку. Например, можем удалить из таблицы всех кошек, которые живут в Саратове:
DELETE FROM CatsAndOwners WHERE City = 'Саратов';
Результат:
CatID | CatName | CatAge | CatColor | CatOwnerName | City |
---|---|---|---|---|---|
1 | Мурка | 3 | Чёрная | Дмитрий | Москва |
3 | Симба | 5 | Пурпурный | Екатерина | Санкт-Петербург |
4 | Лео | 2 | Полосатый | Александр | Екатеринбург |
5 | Мася | 1 | Серый | Анна | Москва |
Удаляет столбец. Например, можно удалить имена кошачьих хозяев:
ALTER TABLE CatsAndOwners DROP COLUMN CatOwnerName;
Заметьте, что сначала нужно применить команду ALTER TABLE. Как мы помним, она заточена на то, чтобы добавлять, менять или удалять колонки в таблице.
Результат:
CatID | CatName | CatAge | CatColor | City |
---|---|---|---|---|
1 | Мурка | 3 | Чёрная | Москва |
3 | Симба | 5 | Пурпурный | Санкт-Петербург |
4 | Лео | 2 | Полосатый | Екатеринбург |
5 | Мася | 1 | Серый | Москва |
Если таблица больше не нужна, можем удалить её. Сделать это просто:
DROP TABLE CatsAndOwners;
Применяйте команду на свой страх и риск. Предварительно советуем всё-таки сохранить таблицу — вдруг пригодится.
Агрегатные функции используют для того, чтобы производить вычисления с данными в таблице: считать количество строк, суммировать значения в столбце, найти среднее значение и так далее.
В SQL доступны пять агрегатных функций:
- COUNT — посчитать количество строк;
- SUM — посчитать сумму значений в столбце;
- AVG — получить среднее значение в столбце;
- MIN — получить минимальное значение в столбце;
- MAX — получить максимальное значение в столбце.
Попробуем вычислить совокупный возраст всех кошек:
SELECT SUM(CatAge) AS TotalAge FROM CatsAndOwners;
Результат:
Теперь найдём наименьший возраст кошки:
SELECT MIN(CatAge) AS MinAge FROM CatsAndOwners;
Результат:
А теперь высшая математика — вычислим средний возраст кошек для каждого города:
SELECT City, AVG(CatAge) AS AverageAge FROM CatsAndOwners GROUP BY City;
Результат:
City | AverageAgeCatCount |
---|---|
Москва | 2 |
Санкт-Петербург | 5 |
Екатеринбург | 2 |
Выделим важные пункты из этой статьи, которые стоит запомнить:
- SQL — это язык структурированных запросов. Он нужен, чтобы управлять информацией в реляционных базах данных — то есть тех, которые состоят из связанных между собой таблиц.
- Каждый запрос нацелен на то, чтобы совершать какое-то действие с данными в таблице: выводить на экран, добавлять новые, считать средние значения, удалять и так далее.
- Все запросы делятся на четыре группы: DDL, DML, DCL и TCL. DDL отвечает за определение данных. DML — за управление данными. DCL — за выдачу прав доступа. TCL — за управление транзакциями.
- Классический запрос состоит из шести операторов. Два из них обязательные: SELECT и FROM. Остальные четыре — используются в зависимости от задачи: WHERE, GROUP BY, HAVING и ORDER BY.
- Помимо базовых команд, в SQL существует множество дополнительных — изучить их можно, например, в шпаргалке от W3Schools. А ещё лучше — берите эти команды на вооружение и экспериментируйте, ведь теория без практики мертва.
Научитесь: Профессия Data Scientist
Узнать больше