diff options
author | pseudolukian <pseudolukian@yandex-team.com> | 2023-11-01 19:23:27 +0300 |
---|---|---|
committer | pseudolukian <pseudolukian@yandex-team.com> | 2023-11-01 20:07:08 +0300 |
commit | 419bbddb7f1e7587741e0cf4bddd26d2485656ae (patch) | |
tree | f7c51289c4145c55283548564cff2984b89a4cd6 | |
parent | 8156ba1fd618ef329fd4db57bcf47524b73be5b6 (diff) | |
download | ydb-419bbddb7f1e7587741e0cf4bddd26d2485656ae.tar.gz |
Remake PG statements part.
22 files changed, 675 insertions, 288 deletions
diff --git a/ydb/docs/ru/core/postgresql/_includes/alert_locks.md b/ydb/docs/ru/core/postgresql/_includes/alert_locks.md new file mode 100644 index 0000000000..355124cd94 --- /dev/null +++ b/ydb/docs/ru/core/postgresql/_includes/alert_locks.md @@ -0,0 +1,5 @@ +{% note info %} + +В отличии от PostgreSQL, в YDB с используются оптимистические блокировки. Это значит, что транзакции проверяют условия выполнения необходимых блокировок в конце своей работы, а не в начале. Если за время выполнения транзакции блокировка была нарушена – такая транзакция завершится ошибкой `Transaction locks invalidated`. В этом случае можно попробовать выполнить аналогичную транзакцию снова. + +{% endnote %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/_includes/alert_preview.md b/ydb/docs/ru/core/postgresql/_includes/alert_preview.md new file mode 100644 index 0000000000..8223725c00 --- /dev/null +++ b/ydb/docs/ru/core/postgresql/_includes/alert_preview.md @@ -0,0 +1,5 @@ +{% note warning %} + +На данный момент совместимость YDB с PostgreSQL **находится в разработке**, поэтому пока поддерживаются не все PostgreSQL конструкции и [функции](../functions.md). PostgreSQL совместимость доступна для тестирования в виде Docker-контейнера, который можно развернуть, следуя данной [инструкции](../docker-connect.md). + +{% endnote %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/_includes/statements/begin_commit_rollback.md b/ydb/docs/ru/core/postgresql/_includes/statements/begin_commit_rollback.md deleted file mode 100644 index fe127696f8..0000000000 --- a/ydb/docs/ru/core/postgresql/_includes/statements/begin_commit_rollback.md +++ /dev/null @@ -1,30 +0,0 @@ -## BEGIN, COMMIT, ROLLBACK (работа с транзакциями){#transactions} - -`BEGIN`, `COMMIT`, и `ROLLBACK` – это команды, которые используются для управления транзакциями. Транзакции – это способ группировки одной или нескольких операций с базой данных в единую единицу работы. Транзакция может состоять из одной или нескольких SQL-операций и использоваться для обеспечения согласованности данных. Транзакция обеспечивает гарантированное выполнение всех или ни одной SQL-операции в своих рамках. - -Помимо транзакции, существуют ещё сессии. Сессия — это одно соединение с базой данных, которое начинается при подключении к базе данных и завершается при её отключении. Именно в рамках сессии выполняется транзакция, которая начинается с команды `BEGIN` и завершается командой `COMMIT` (успешное завершение) или `ROLLBACK` (откат). В случае если сессия неожиданно прерывается, тогда все транзакции, которые были начаты в текущей сесcии – автоматически откатываются. - -Рассмотрим каждую из команд: -* `BEGIN` – инициирует новую транзакцию. После выполнения этой команды все последующие операции с базой данных будут выполняться в рамках этой транзакции. -* `COMMIT` – завершает транзакцию, применяя все её операции. Если все операции в транзакции были успешными, результаты этих операций фиксируются (становятся постоянными). Изменения становятся видны последующим транзакциям. -* `ROLLBACK` – откатывает транзакцию, отменяя все её операции, если в процессе выполнения транзакции возникли ошибки или отмена транзакции производится приложением исходя из внутренней логики работы. Когда вызывается `ROLLBACK`, только изменения, сделанные в рамках текущей транзакции отменяются. Изменения, сделанные другими транзакциями (даже если они были запущены и завершены во время выполнения текущей транзакции), остаются нетронутыми. В случае если в процессе выполнения транзакции произошла ошибка, то дальнейшая работа с такой транзакцией становится невозможна – нужно делать `ROLLBACK`, так как выполнение `COMMIT` вернет ошибку. Если произойдет разрыв сессии во время активной транзакции – автоматически будет выполнен `ROLLBACK`. Более подробную информацию про управление конкурентным доступом (mvcc) можно найти в [этой статье](https://ydb.tech/en/docs/concepts/mvcc). - -Предположим, нужно внести изменения в разные строчки таблицы для разных столбцов так, чтобы транзакция была объединена в одну рабочую единицу и имела гарантии ACID. Такая запись может выглядеть так: -```sql ---Начало транзакции -BEGIN; - --- Инструкция обновления данных -UPDATE movies -SET length = INTERVAL '02:15:00' -WHERE title = 'Star Wars: Episode I - The Phantom Menace'; - --- Инструкция обновления данных -UPDATE movies -SET star = 'Tom Hanks' -WHERE title = 'Indiana Jones and the Last Crusade'; -``` -Если все данные верны – нужно выполнить инструкцию подтверждения транзакции: -```sql -COMMIT; -```
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/_includes/statements/create_table.md b/ydb/docs/ru/core/postgresql/_includes/statements/create_table.md deleted file mode 100644 index dd3dba8d57..0000000000 --- a/ydb/docs/ru/core/postgresql/_includes/statements/create_table.md +++ /dev/null @@ -1,31 +0,0 @@ -## CREATE TABLE (создание таблицы) {#create} - -Инструкция `CREATE TABLE` предназначена для создания пустой таблицы в текущей базе данных. При создании таблицы можно указать: её название, типы данных столбцов, ограничения столбцов. - -В самом простом виде синтаксис `CREATE TABLE` может выглядеть так: -```sql -CREATE TABLE <имя_таблицы> ( - <имя_столбца_данных> <тип_данных> <ограничения_колонки>, - ... -); -``` -Обратите внимание, при создании таблицы всегда должен быть ключевой столбец – `<имя_столбца> PRIMARY KEY`. Приведём пример создания таблицы `movies` с шестью столбцами, заданными у них типами данных и первичным ключом: -```sql -CREATE TABLE movies ( - id serial PRIMARY KEY, - title text NOT NULL, - director text, - star text, - production_date date, - length interval HOUR TO MINUTE -); -``` - -В примере выше мы задаём столбцы таблицы со следующими свойствами: -1. `id` – уникальный идентификационный номер фильма в текущей таблице. Является первичным ключом (`PRIMARY KEY`). Для первичного ключа свойство `NOT NULL` применяется автоматически. Тип данных `serial`; -2. `title` – название фильма (может быть написано кириллицей или латиницей). Не должен быть пустым (`NOT NULL`); -3. Поля `director` и `star` также имеют тип данных `text`, но в отличие от `title` могут быть пустыми; -4. `production_date` — дата выпуска фильма, имеет тип данных `date`(4 байта, дата без времени суток). Дата хранится в формате целочисленного числа, а при её чтении она выводится в различных текстовых форматах, например: 1999-01-08 (ISO 8601); January 8, 1999; 1/8/1999; 1999-Jan-08 и т.д. Диапазон дат, которые можно хранить в БД: от 4713 года до н.э. до 5874897 года н.э. -5. `length` – время длительности фильма. Имеет тип данных `interval` – это временной интервал с заданным ограничением на допустимый диапазон значений. В нашем случае `HOUR TO MINUTE` – это значит, что интервал будет содержать только часы и минуты, исключая другие временные единицы, такие как дни или секунды. - -Тип данных `serial` не является настоящими типом, он представляет собой просто удобное средство для создания столбцов с инкрементом. В схеме данных таблицы `serial` приравнивается к `int4`.
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/_includes/statements/drop_table.md b/ydb/docs/ru/core/postgresql/_includes/statements/drop_table.md deleted file mode 100644 index 503fc23174..0000000000 --- a/ydb/docs/ru/core/postgresql/_includes/statements/drop_table.md +++ /dev/null @@ -1,11 +0,0 @@ -## DROP TABLE, DELETE FROM (удаление таблиц и строк){#delete} - -Для удаления таблиц целиком используется инструкция `DROP TABLE <название_таблицы>;`, а для удаления строки из таблицы по конкретному значению столбца используется конструкция `DELETE FROM <название_таблицы> WHERE <название_столбца>=<значение или диапозон_значений>`. - -{% note warning %} - -Использование оператора `WHERE ...` опционально, поэтому при работе с `DELETE FROM` очень важно случайно не выполнить команду раньше указания оператора `WHERE ...`. - -{% endnote %} - -Например, для удаления фильма с названием "USA Wall Art" из таблицы `movies` нужно выполнить следующую команду: `DELETE FROM movies WHERE title='USA Wall Art';`. Можно удалить все фильмы Джорджа Лукоса из таблицы `movies` снятые раньше 1980 года: `DELETE FROM movies WHERE director = 'George Lucas' AND production_date < '1980-01-01';`.
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/_includes/statements/insert_into.md b/ydb/docs/ru/core/postgresql/_includes/statements/insert_into.md deleted file mode 100644 index 6f8545e4e9..0000000000 --- a/ydb/docs/ru/core/postgresql/_includes/statements/insert_into.md +++ /dev/null @@ -1,42 +0,0 @@ -## INSERT INTO (вставка строк в таблицу){#insert} - -Инструкция `INSERT INTO` предназначена для добавления строк в таблицу. Она может добавить одну или несколько строк за одно исполнение. Данные для добавления могут быть указаны явно в виде непосредственных значений или сформированы выражениями. Синтаксис конструкции `INSERT INTO` выглядит следующим образом: -```sql -INSERT INTO <название таблицы> (<название_столбца_таблицы>, ...) -VALUES (<значение_столбца_таблицы>, ...); -``` - -Пример добавления одного фильма (мы намеренно используем ненастоящие названия фильмов) в таблицу `movies`, которая была [создана ранее](#create_table): -```sql -INSERT INTO movies (title, director, production_date, star, length) -VALUES ( - 'Space Battle: Episode X - No hope', - 'George Lucas', - CAST('1977-05-25' AS DATE), - 'Mark Hamill', - INTERVAL '2 hours 1 minute'); -``` - -В этой записи мы не указали столбец `id` и не задали ему значение – это сделано намеренно, так как в таблице `movies` у столбца `id` задан тип данных `serial`. При выполнении инструкции `INSERT INTO` значение столбца `id` будет присвоено автоматически с учетом предыдущих значений – будет выполнен инкремент текущего значения `id`. - - -С помощью `INSERT INTO` можно добавить сразу несколько строк в таблицу: -```sql -INSERT INTO movies (title, director, production_date, star, length) -VALUES -('Indiana Johns and the Final Quest', 'Steven Spielberg', CAST('1989-05-24' AS DATE), 'Harrison Ford', INTERVAL '2 hours 7 minutes'), -('USA Wall Art', 'George Lucas', CAST('1973-08-01' AS DATE), 'Richard Dreyfuss', INTERVAL '1 hour 50 minutes'), -('THZ 1139', 'George Lucas', CAST('1971-03-11' AS DATE), 'Robert Duvall', INTERVAL '1 hour 26 minutes'), -('Space Battles: Episode One - The Ghostly Threat', 'George Lucas', CAST('1999-05-19' AS DATE), 'Liam Neeson', INTERVAL '2 hours 16 minutes'), -('Space Battles: Episode Two - Onslaught of the Duplicates', 'George Lucas', CAST('2002-05-16' AS DATE), 'Ewan McGregor', INTERVAL '2 hours 22 minutes'), -('Space Battles: Episode Three - Retaliation of the Sifth', 'George Lucas', CAST('2005-05-19' AS DATE), 'Hayden Christensen', INTERVAL '2 hours 20 minutes'); -``` - -В обоих примерах для указания даты выпуска фильма, мы использовали функцию `CAST()`, которая используется для преобразования одного типа данных в другой. В данном случае мы с помощью ключевого слова `AS` и типа данных `DATE` явно указали, что хотим преобразовать строковое представление даты в формате [ISO8601](https://ru.wikipedia.org/wiki/ISO_8601) в тип данных `date`, который у нас заявлен у столбца `production_date`. - -Указать нужный тип данных, например, `DATE` можно и альтернативным способом с помощью оператора приведения типов `::`, который используется для явного приведения значения одного типа данных к другому. Пример использования оператора `::` может выглядеть так: -```sql -INSERT INTO movies (title, director, production_date, star, length) -VALUES -('Indiana Johns and the Next Quest', 'Steven Spielberg', '1990-05-24'::date, 'Harrison Ford', INTERVAL '2 hours 7 minutes'); -```
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/_includes/statements/select.md b/ydb/docs/ru/core/postgresql/_includes/statements/select.md deleted file mode 100644 index b3cb64b572..0000000000 --- a/ydb/docs/ru/core/postgresql/_includes/statements/select.md +++ /dev/null @@ -1,102 +0,0 @@ -## SELECT (Чтение строк из таблицы){#select} - -`SELECT` используется для возврата вычислений на клиентскую сторону, в случае если он вызван без дополнительных конструкций, так как `FROM ...`, `INSERT INTO ...` и т.д. - -Например, `SELECT` можно использовать для работы с датами, преобразования чисел или подсчета длины строки: -```sql -SELECT CURRENT_DATE + INTERVAL '1 day'; -- Возвращает завтрашнюю дату -SELECT LENGTH('Hello'); -- Возвращает длину строки 'Hello' -SELECT CAST('123' AS INTEGER); -- Преобразует строки в числа -``` - -Такое применение `SELECT` бывает полезно при тестировании, отладки выражений или SQL-функций без обращения к реальной таблице, но чаще `SELECT` используется для получения строк из одной или множества таблиц. В самом простом представлении `SELECT` можно записать так: `SELECT <название столбца/столбцов> FROM <название таблицы>` или `SELECT <название_функции(< название столбца>)> FROM <название таблицы>;`. Чтобы прочитать все данные из таблицы, например, таблицы `movies` – нужно выполнить команду `SELECT * FROM movies;`, где `*` – это оператор выбора данных по всем столбцам. При такой записи будут возвращены все строки из таблицы с данными по всем столбцам. Получить выборку строк таблицы по определенным столбцам можно перечислением названий столбцов после ключевого слова `SELECT`: `SELECT <название столбца>, <название столбца> FROM <название таблицы>;`. - -Вывести столбцы "title" и "director" для всех строк [таблицы](#create_table) "movies" можно так: `SELECT title, director FROM movies;`. Если в таблице много строк и нужно ограничить количество выводимых строк на печать – используется `LIMIT` с заданным количеством выводимых строк, который добавляется в конец инструкции `SELECT`. - -Например, можно вывести только 5 строк таблицы `movies`: -```sql -SELECT title,director FROM movies LIMIT 5; -``` - -Для выборки только части строк - используется оператор `WHERE` с условиями выборки: `SELECT <название столбца> FROM <название таблицы> WHERE <название столбца> <оператор условного сравнения> <значение столбца выборки>;` Например, можно выбрать все фильмы Джорджа Лукоса из нашей таблицы, созданные им после 1980 года: -```sql -SELECT * FROM movies WHERE director = 'George Lucas' AND production_date > '1980-01-01'; -``` - -Можно добавить еще одно условие выборки, предположим по времени длительности фильма менее 2 часов. Сделать это можно добавлением оператора `AND` с указанием второго условия выборки. Такая запись может выглядеть так: -```sql -SELECT * FROM movies -WHERE length < INTERVAL '2 hours' AND production_date < '1973-01-01'; -``` - - -По умолчанию база данных не гарантирует порядок возврата строк, и он может отличаться от запроса к запросу. Если требуется сохранить определенный порядок строк – используется инструкция `ORDER BY <название столбца для сортировки> <направление сортировки>`. Сортировка происходит по результатам, которые возвращает (`SELECT`), а не по исходным столбцам таблицы (`FROM`). Сортировать можно в прямом порядке – ASC (от меньшего к большему - вариант по умолчанию, можно не указывать) и в обратном – DESC (от большего к меньшему). Как сортировка будет выполняться, зависит от типа данных столбца. Например, строки хранятся в utf-8 и сравниваются по "unicode collate" (по кодам символов). - - -Отсортировать фильмы по убыванию даты производства от более новых, до более старых можно так: -```sql -SELECT title, director,production_date FROM movies -ORDER BY production_date DESC; -``` - -`SELECT` можно применять к нескольким таблицам с указанием типа соединения таблиц. Объединение таблиц задается через оператор `JOIN`, который бывает следующих типов: -1. `INNER JOIN` (или просто JOIN) – возвращает строки, когда есть соответствующие значения в обеих таблицах. Исключает из результатов те строки, для которых нет совпадений в соединяемых таблицах. -2. `LEFT JOIN` (или LEFT OUTER JOIN) – возвращает все строки из левой таблицы и соответствующие строки из правой таблицы. Если нет совпадений, возвращает `NULL` для всех колонок правой таблицы. -3. `RIGHT JOIN` (или RIGHT OUTER JOIN) – возвращает все строки из правой таблицы и соответствующие строки из левой таблицы. Если не существует совпадений, возвращает `NULL` для всех колонок левой таблицы. Этот тип `JOIN` редко используется, так как его функциональность можно заменить `LEFT JOIN`, меняя местами таблицы. -4. `FULL JOIN` (или FULL OUTER JOIN) – возвращает как совпавшие, так и не совпавшие строки в обеих таблицах, при этом возвращает `NULL` в колонках из таблицы, для которой не найдено совпадение. -5. `CROSS JOIN` – возвращает комбинированный результат каждой строки левой таблицы с каждой строкой правой таблицы. Обычно используется, когда необходимо получить все возможные комбинации строк из двух таблиц. - -Когда выполняется `JOIN` по определенному условию, например, по ключу, и в одной из таблиц есть несколько строк с одинаковым значением этого ключа, получается [декартово произведение](https://ru.wikipedia.org/wiki/Прямое_произведение). Это означает, что каждая строка из одной таблицы будет соединена с каждой соответствующей строкой из другой таблицы. Опишем работу `INNER JOIN` и `CROSS JOIN`. `CROSS JOIN` просто комбинирует каждую строку одной таблицы с каждой строкой другой. `INNER JOIN` работает похожим образом, но добавляет фильтрацию. Этот фильтр определяется в части `ON` запроса. Таким образом, из всего декартова произведения выбираются только строки, соответствующие заданному условию. - -Можно сказать, что `INNER JOIN` - это `CROSS JOIN`, но с дополнительной фильтрацией, или наоборот `CROSS JOIN` — это частный случай `INNER JOIN`, когда строки в обеих таблицах совпали. Если одна из таблиц пуста, результат объединения тоже будет пуст. `INNER JOIN` часто дает меньше строк на выходе, чем `CROSS JOIN`. `CROSS JOIN` объединяет строки без какого-либо условия, и поэтому в его синтаксисе отсутствуют ключевые слова `ON` или `USING`: `CROSS JOIN <название_таблицы> AS <алиас_таблицы>;`. В примере далее мы будем использовать `INNER JOIN`, синтаксис которого выглядит так: `INNER JOIN <название_таблицы> AS <алиас_таблицы> ON <алиас_первой_таблицы>.<имя_столбца> = <алиас_таблицы>.<соответствующее_имя_столбца>;`. - -Вместо ключевого слова `ON` в `INNER JOIN` может использоваться `USING`. Использовать `USING` удобно, когда имена столбцов, по которым происходит соединение, в обеих таблицах совпадают. Синтаксис становится короче и чище: `INNER JOIN <название_таблицы> AS <алиас_таблицы> USING (<имя_столбца>);`. В одном SQL-запросе может быть N количество `JOIN` разных типов. Последовательность выполнения `JOIN` определяется их порядком в запросе и логикой выполнения запроса оптимизатором базы данных. - -Мы уже до этого создали [таблицу](#create_table) "movies", создадим ещё одну таблицу "lucas_actors": -```sql -CREATE TABLE lucas_actors ( - id SERIAL PRIMARY KEY, - full_name TEXT NOT NULL, - film TEXT NOT NULL, - production_date DATE NOT NULL, - date_of_birth DATE, - achievements TEXT -); -``` - -Заполним таблицу "lucas_actors" данными: -```sql -INSERT INTO lucas_actors (full_name, film, production_date, date_of_birth, achievements) -VALUES -('Harrison Ford', 'Indiana Jones and the Last Crusade', CAST('1989-05-24' AS DATE), CAST('1942-07-13' AS DATE), 'Oscar Nominee'), -('Richard Dreyfuss', 'American Graffiti', CAST('1973-08-01' AS DATE), CAST('1947-10-29' AS DATE), 'Oscar Winner'), -('Robert Duvall', 'THX 1138', CAST('1971-03-11' AS DATE), CAST('1931-01-05' AS DATE), 'Oscar Winner'), -('Liam Neeson', 'Star Wars: Episode I - The Phantom Menace', CAST('1999-05-19' AS DATE), CAST('1952-06-07' AS DATE), 'Oscar Nominee'), -('Ewan McGregor', 'Star Wars: Episode II - Attack of the Clones', CAST('2002-05-16' AS DATE), CAST('1971-03-31' AS DATE), 'Golden Globe Winner'), -('Hayden Christensen', 'Star Wars: Episode III - Revenge of the Sith', CAST('2005-05-19' AS DATE), CAST('1981-04-19' AS DATE), NULL); -``` - -Теперь применим оператор `INNER JOIN` для вывода в терминал полного имени актера (`full_name`), дня его рождения (`date_of_birth`), названия фильма (`title`) и даты производства фильма (`production_date`)(таблицы "movies" и "lucas_actors" должны быть заполнены данными): -```sql -SELECT - la.full_name, - la.date_of_birth, - f.title, - f.production_date -FROM lucas_actors AS la -INNER JOIN movies AS f ON la.film = f.title; -``` - -Разберем подробнее как работает данный пример: -1. В строке `SELECT la.full_name, la.date_of_birth, f.title, f.production_date` производится выборка данных из двух таблиц представленных алиасами (псевдонимы): "f" – таблица "movies", "la" – таблица "lucas_actors"; -2. На строке `FROM lucas_actors AS la` задаются условия выборки строк из таблицы "lucas_actors" и задаётся алиас таблице конструкцией `AS la`. -3. На последней строчке `INNER JOIN movies AS f ON la.film = f.title;` с помощью оператора `INNER JOIN` производится соединение по столбцу "film" из таблицы "lucas_actors" и столбцу "title" таблицы "movies". - -В результате выполнения приведенного выше SQL-запроса будет получен следующий результат: -| full_name | date_of_birth | title | production_date | -|-----------------|---------------|-----------------------------------------------|------------------| -| Harrison Ford | 1942-07-13 | Indiana Jones and the Last Crusade | 1989-05-24 | -| Richard Dreyfuss| 1947-10-29 | American Graffiti | 1973-08-01 | -| Robert Duvall | 1931-01-05 | THX 1138 | 1971-03-11 | -| Liam Neeson | 1952-06-07 | Star Wars: Episode I - The Phantom Menace | 1999-05-19 | - diff --git a/ydb/docs/ru/core/postgresql/_includes/statements/update.md b/ydb/docs/ru/core/postgresql/_includes/statements/update.md deleted file mode 100644 index c4b0bb1ff5..0000000000 --- a/ydb/docs/ru/core/postgresql/_includes/statements/update.md +++ /dev/null @@ -1,25 +0,0 @@ -## UPDATE (изменения строк таблицы){#update} -Для изменения данных в определенных столбцах строки – используется инструкция `UPDATE `. Синтаксис `UPDATE` в самом простом виде может выглядеть так: -```sql -UPDATE <название_таблицы> SET <название_столбца> = <новое_значение> WHERE <название_столбца_для_поиска> = <искомое_значение>; -``` - -`UPDATE` работает так: сначала задаётся название таблицы, в которой будет произведено обновление данных. Затем указываются названия столбцов для обновления и их новые значения. Далее указывается оператор `WHERE` и после задаются условия поиска строки. Например, чтобы скорректировать длительность фильма "Space Battles: Episode One - The Ghostly Threat" нужно применить следующую запись: -```sql -UPDATE movies -SET length = INTERVAL '02:11:00' -WHERE title = 'Space Battles: Episode One - The Ghostly Threat'; -``` - -Для одновременного обновления разных значений в разных строках можно использовать инструкция `CASE ... END`, с вложенными условиями выборки данных `WHEN <название столбца> <оператор сравнения> THEN <новое значение>`. Далее следует конструкция `WHERE <название колонки> IN (<значение колонки>)`, которая позволяет задать список значений, по которым будет выполнено условие. - -Так, если нужно изменить длину двух фильмов – нужно сначала задать колонку, где будут меняться данные (для нас эта `length` колонка), далее указывается `CASE ... END`, в нём задается выборка строк для изменения значений столбца `length` по признаку соответствия названию фильма (столбец `title`) и завершается конструкция условным оператором `WHERE <назмание столбца> IN (<значение столбца>, <значение столбца>)`. Такая запись может выглядеть так: - -```sql -UPDATE movies -SET length = CASE - WHEN title = 'Indiana Johns and the Final Quest' THEN INTERVAL '2 hours 10 minutes' - WHEN title = 'Space Battles: Episode One - The Ghostly Threat' THEN INTERVAL '2 hours 19 minutes' - END -WHERE title IN ('Indiana Johns and the Final Quest', 'Space Battles: Episode One - The Ghostly Threat'); -``` diff --git a/ydb/docs/ru/core/postgresql/intro.md b/ydb/docs/ru/core/postgresql/intro.md index fb7d504ea7..5c3e4d1622 100644 --- a/ydb/docs/ru/core/postgresql/intro.md +++ b/ydb/docs/ru/core/postgresql/intro.md @@ -1,13 +1,10 @@ ## Введение -{% note warning %} -На данный момент PostgreSQL совместимость находится в разработке и доступна для тестирования в виде Docker-контейнера, который можно развернуть, следуя данной [инструкции](docker-connect.md). Поддерживаемый синтаксис PostgreSQL описан в разделе [{#T}](statements.md), а доступные для использования функции изложены в разделе [{#T}](functions.md). +{% include [./_includes/alert.md](./_includes/alert_preview.md) %} -{% endnote %} +[PostgreSQL](https://www.postgresql.org) совместимость – это механизм выполнения SQL запросов в PostgreSQL диалекте на инфраструктуре YDB с использованием сетевого протокола PostgreSQL. Благодаря этой возможности можно использовать привычные инструменты работы с PostgreSQL, такие, как [psql](https://www.postgresql.org/docs/14/app-psql.html) и драйвера (например, [pq](https://github.com/lib/pq) для Golang и [psycopg2](https://pypi.org/project/psycopg2/) для Python). Можно разрабатывать запросы на привычном PostgreSQL синтаксисе и получать такие преимущества YDB, как горизонтальная масштабируемость и отказоустойчивость. -[PostgreSQL](https://www.postgresql.org) совместимость – это механизм выполнения SQL запросов в PostgreSQL диалекте на инфраструктуре YDB с использованием сетевого протокола PostgreSQL. Благодаря этой возможности можно использовать привычные инструменты работы с PostgreSQL, такие, как [psql]( https://www.postgresql.org/docs/14/app-psql.html) и драйвера (например, [pq](https://github.com/lib/pq) для Golang и [psycopg2](https://pypi.org/project/psycopg2/) для Python). Можно разрабатывать запросы на привычном PostgreSQL синтаксисе и получать такие преимущества YDB, как горизонтальная масштабируемость и отказоустойчивость. - -PostgreSQL совместимость упрощает миграцию приложений, ранее работавших в экосистеме PostgreSQL. Сейчас поддерживается ограниченное количество [инструкций](statements.md) и функций PostgreSQL 14. PostgreSQL совместимость позволяет переключаться с PostgreSQL на YDB без изменения кода проекта (в случае полной поддержки совместимостью используемых в проекте SQL-конструкций), просто изменив параметры подключения. +PostgreSQL совместимость упрощает миграцию приложений, ранее работавших в экосистеме PostgreSQL. Сейчас поддерживается ограниченное количество инструкций и функций PostgreSQL 14. PostgreSQL совместимость позволяет переключаться с PostgreSQL на YDB без изменения кода проекта (в случае полной поддержки совместимостью используемых в проекте SQL-конструкций), просто изменив параметры подключения. Принцип работы PostgreSQL совместимости можно описать так: 1. Программа отправляет запросы в YDB, где их обрабатывает компонент под названием pgwire. Pgwire реализует [сетевой протокол](https://postgrespro.ru/docs/postgresql/14/protocol) PostgreSQL и передает команды в query processor. diff --git a/ydb/docs/ru/core/postgresql/mechanisms/locks.md b/ydb/docs/ru/core/postgresql/mechanisms/locks.md new file mode 100644 index 0000000000..8385e6594a --- /dev/null +++ b/ydb/docs/ru/core/postgresql/mechanisms/locks.md @@ -0,0 +1,33 @@ +# Блокировки + + +Блокировки используются, чтобы упорядочить одновременный (конкурентный) доступ нескольких процессов к одним и тем же ресурсам. Ресурсом может быть объект, с которым работает СУБД: +1. Списки первичных ключей, условия или даташард целиком (если блокировок становится очень много); +2. Структура в памяти, такая как хеш-таблица, буфер и т. п. (идентифицируется заранее присвоенным номером); +3. Абстрактные ресурсы, не имеющие никакого физического смысла (идентифицируются просто уникальным числом). + +Чтобы процесс мог обратиться к ресурсу – он обязан захватить (acquire) блокировку, ассоциированную с этим ресурсом. Блокировка – это участок разделяемой памяти, в котором хранится информация о том свободна ли блокировка или захвачена. Блокировка сама по себе тоже является ресурсом, к которому возможен конкурентный доступ. Для доступа к блокировкам используются специальные примитивы синхронизации: семафоры или мьютексы. Смысл их в том, чтобы код, обращающийся к разделяемому ресурсу, одновременно выполнялся только в одном процессе. Если ресурс занят и блокировка не возможна – процесс завершится ошибкой. + +Блокировки можно классифицировать по принципу их реализации: +- **Пессимистическая блокировка** до модификации данных накладывается блокировка на все потенциально затрагиваемые строки. Это исключает возможность их изменения другими сессиями до завершения текущей операции. После модификации гарантировано, что запись данных будет непротиворечивой; +- **Оптимистическая блокировка** не ограничивает доступ к данным в процессе работы, но использует специальный атрибут (например: `VERSION`) для контроля изменений. Атрибут - это поле из метаданных о строке, которое не видно пользователям, оно относится к деталям реализации механизма блокировок. Перед фиксацией изменений проверяется установленный атрибут. Если он не изменился – изменения зафиксируются (`COMMIT`), иначе транзакция будет откатана (`ROLLBACK`). + + +В совместимости YDB с PostgreSQL используются оптимистические блокировки – это значит, что транзакции в конце своей работы проверяют условия выполнения блокировок. Если за время выполнения транзакции блокировка была нарушена – такая транзакция завершится ошибкой: + +``` +Error: Transaction locks invalidated. Table: <table name>, code: 2001 +``` + +С ошибкой могут завершаться транзакции, в которых исполняются SQL-инструкции чтения и записи. Транзакции, где исполняются только SQL-инструкции чтения или записи завершаются корректно. Приведём пример транзакции, которая завершится с ошибкой в случае внесения изменений в данные таблице параллельной транзакцией: + +```sql +BEGIN; +SELECT * FROM people; +-- Если тут будет выполнен INSERT в другой транзакции, эта транзакция завершится ошибкой +UPDATE people SET age = 27 +WHERE name = 'JOHN'; +COMMIT; +``` + +В результате транзакция завершится ошибкой `Error: Transaction locks invalidated` и будет откачена (`ROLLBACK`). В случае ошибки `Error: Transaction locks invalidated` – можно попытаться выполнить транзакцию снова.
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/mechanisms/toc_m.yaml b/ydb/docs/ru/core/postgresql/mechanisms/toc_m.yaml new file mode 100644 index 0000000000..98f9e55dca --- /dev/null +++ b/ydb/docs/ru/core/postgresql/mechanisms/toc_m.yaml @@ -0,0 +1,4 @@ +items: +- name: Блокировки + href: locks.md + hidden: false
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/pg-dump.md b/ydb/docs/ru/core/postgresql/pg-dump.md index d15c05f129..089ea5df6a 100644 --- a/ydb/docs/ru/core/postgresql/pg-dump.md +++ b/ydb/docs/ru/core/postgresql/pg-dump.md @@ -5,8 +5,8 @@ Для этого нужно: 1. Сделать дамп данных через [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html) со следующими параметрами: - * `--inserts` — для добавления данных через команду [INSERT](statements.md#insert), вместо использования протокола [COPY](https://www.postgresql.org/docs/current/sql-copy.html). - * `--column-inserts` — для добавления данных через команду [INSERT](statements.md#insert) с именами колонок. + * `--inserts` — для добавления данных через команду [INSERT](./statements/insert_into.md), вместо использования протокола [COPY](https://www.postgresql.org/docs/current/sql-copy.html). + * `--column-inserts` — для добавления данных через команду [INSERT](./statements/insert_into.md) с именами колонок. * `--rows-per-insert=1000` — для вставки данных пачками и ускорения процесса. * `--encoding=utf_8` — YDB поддерживает строковые данные только в [UTF-8](https://ru.wikipedia.org/wiki/UTF-8). 2. Привести дамп к виду, который поддерживается YDB командой `ydb tools pg-convert` [YDB CLI](../reference/ydb-cli/index.md). @@ -18,7 +18,7 @@ `ydb tools pg-convert` выполняет следующие преобразования: -* Перенос создания первичного ключа в тело команды [CREATE TABLE](statements.md#create). +* Перенос создания первичного ключа в тело команды [CREATE TABLE](./statements/create_table.md). * Вырезание схемы `public` из имен таблиц. * Удаление секции `WITH (...)` в `CREATE TABLE` * Комментирование неподдерживаемых конструкций (опционально): diff --git a/ydb/docs/ru/core/postgresql/statements.md b/ydb/docs/ru/core/postgresql/statements.md deleted file mode 100644 index c8138964fc..0000000000 --- a/ydb/docs/ru/core/postgresql/statements.md +++ /dev/null @@ -1,37 +0,0 @@ -# Синтаксис PostgreSQL - -{% note warning %} - -На данный момент PostgreSQL совместимость находится в разработке и доступна для тестирования в виде Docker-контейнера, который можно развернуть, следуя данной [инструкции](docker-connect.md). Поддерживаемый синтаксис PostgreSQL описан в разделе [{#T}](statements.md), а доступные для использования функции изложены в разделе [{#T}](functions.md). - -{% endnote %} - -Для удобства навигации синтаксис PostgreSQL можно разделить на следующие категории: - -1. **Data Query Language (DQL)** – инструкции запроса данных: - * [SELECT](#select) – запрашивает данные из одной или нескольких таблиц. -2. **Data Modification Language (DML)** – инструкции, которые влияют на данные: - * [INSERT](#insert) – добавляет новые строки в таблицу или обновляет существующие с опцией `ON CONFLICT`; - * [UPDATE](#update) - изменяет существующие строки в таблице; - * [DELETE](#delete) - удаляет строки из таблицы. -3. **Data Definition Language (DDL)** – инструкции, которые определяют или изменяют структуру базы данных: - * [CREATE]({#create}) - создает новые объекты (такие, как таблицы); - * [DROP]({#drop}) – удаляет объекты. -4. **Transaction Control Statements (TCS)** – команды управления транзакциями: - * [BEGIN](#transactions) – начинает новую транзакцию; - * [COMMIT](#transactions) – подтверждает изменения, сделанные в рамках транзакции; - * [ROLLBACK](#transactions) – отменяет изменения, сделанные в рамках транзакции. - -В списке приведены только те инструкции использования систаксиса PostgreSQL, который сейчас реализованы в совместимости YDB с PostgreSQL. - -{% include [./_includes/statements/create_table.md](./_includes/statements/create_table.md) %} - -{% include [./_includes/statements/insert_into.md](./_includes/statements/insert_into.md) %} - -{% include [./_includes/statements/select.md](./_includes/statements/select.md) %} - -{% include [./_includes/statements/update.md](./_includes/statements/update.md) %} - -{% include [./_includes/statements/drop_table.md](./_includes/statements/drop_table.md) %} - -{% include [./_includes/statements/begin_commit_rollback.md](./_includes/statements/begin_commit_rollback.md) %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/statements/begin_commit_rollback.md b/ydb/docs/ru/core/postgresql/statements/begin_commit_rollback.md new file mode 100644 index 0000000000..857bf5fb66 --- /dev/null +++ b/ydb/docs/ru/core/postgresql/statements/begin_commit_rollback.md @@ -0,0 +1,34 @@ +# BEGIN, COMMIT, ROLLBACK (работа с транзакциями) + +{% include [../_includes/alert_preview.md)](../_includes/alert_preview.md) %} + +**Транзакции** – это способ группировки одной или нескольких операций с базой данных в единую единицу работы. Транзакция может состоять из одной или нескольких SQL-операций и использоваться для обеспечения согласованности данных. Транзакция обеспечивает гарантированное выполнение либо всех входящих в неё SQL-операций, либо ни одной. Транзакции управляются командами `BEGIN`, `COMMIT`, `ROLLBACK`. + +Транзакции выполняются внутри сессий. Сессия — это одно соединение с базой данных, которое начинается при подключении к базе данных и завершается при её отключении. Транзакция начинается с команды `BEGIN` и завершается командой `COMMIT` (успешное завершение) или `ROLLBACK` (откат). Указывать `BEGIN`, `COMMIT` и `ROLLBACK` не обязательно, часто их использование подразумевается неявно. В случае если сессия неожиданно прерывается, тогда все транзакции, которые были начаты в текущей сесcии – автоматически откатываются. + +Рассмотрим каждую из команд: +* `BEGIN` – инициирует новую транзакцию. После выполнения этой команды все последующие операции с базой данных будут выполняться в рамках этой транзакции. +* `COMMIT` – завершает текущую транзакцию, применяя все её операции. Если все операции в транзакции были успешными, результаты этих операций фиксируются (становятся постоянными). Изменения становятся видны последующим транзакциям. +* `ROLLBACK` – откатывает текущую транзакцию, отменяя все её операции, если в процессе выполнения транзакции возникли ошибки или отмена транзакции производится приложением исходя из внутренней логики работы. Когда вызывается `ROLLBACK`, только изменения, сделанные в рамках текущей транзакции отменяются. Изменения, сделанные другими транзакциями (даже если они были запущены и завершены во время выполнения текущей транзакции), остаются нетронутыми. В случае если в процессе выполнения транзакции произошла ошибка, то дальнейшая работа с такой транзакцией становится невозможна – нужно делать `ROLLBACK`, так как выполнение `COMMIT` вернет ошибку. Если произойдет разрыв сессии во время активной транзакции – автоматически будет выполнен `ROLLBACK`. Более подробную информацию про управление конкурентным доступом (MVCC) можно найти в [этой статье](../../concepts/mvcc.md). + +Предположим, нужно внести изменения в разные строки таблицы для разных столбцов так, чтобы транзакция была объединена в одну рабочую единицу и имела гарантии [ACID](https://ru.wikipedia.org/wiki/ACID). Такая запись может выглядеть так: +```sql +--Начало транзакции +BEGIN; + +-- Инструкция обновления данных +UPDATE people +SET name = 'Ivan' +WHERE id = 1; + +-- Инструкция обновления данных +UPDATE people +SET lastname = 'Gray' +WHERE id = 10; +``` +Если все данные верны – нужно выполнить инструкцию подтверждения транзакции: +```sql +COMMIT; +``` + +{% include [../_includes/alert_locks.md](../_includes/alert_locks.md) %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/statements/create_table.md b/ydb/docs/ru/core/postgresql/statements/create_table.md new file mode 100644 index 0000000000..4ec987fe2f --- /dev/null +++ b/ydb/docs/ru/core/postgresql/statements/create_table.md @@ -0,0 +1,128 @@ +# CREATE TABLE (создание таблицы) + +{% include [../_includes/alert_preview.md)](../_includes/alert_preview.md) %} + +Инструкция `CREATE TABLE` предназначена для создания пустой таблицы в текущей базе данных. Синтаксис команды: + +```sql +CREATE [TEMPORARY] TABLE <table name> ( + +<column name> <column data type> [COLLATE][PRIMARY KEY] + +[CONSTRAINT <constraint name> [PRIMARY KEY <column name>], +...] + +); +``` +При создании таблицы можно задать: +1. **Тип таблицы**: `TEMPORARY` (поддерживается не полностью и используется только в тестах) – временная таблица, которая автоматически удаляется в конце сеанса или в конце текущей транзакции. Если параметр не задан (оставлен пустым) – создается постоянная таблица; +2. **Имя таблицы**: `<table name>` – можно использовать английские буквы в нижнем регистре, цифры и нижнее подчёркивание. Например, название таблицы "People" будет сохранено как "people"; +3. **Имя столбца/колонки**: <column name> – действую такие же правила нейминга как и для имен таблиц; +4. **Тип данных**: <column data type> – указываются [стандартные типы](https://www.postgresql.org/docs/current/datatype.html) данных PostgreSQL; +5. **Правило сортировки**: `COLLATE` – [правила сортировки](https://www.postgresql.org/docs/current/collation.html) позволяют устанавливать порядок сортировки и особенности классификации символов в отдельных столбцах или даже при выполнении отдельных операций. К сортируемым типам относятся: `text`, `varchar` и `char`. Можно указать локализацию (`ru_RU`, `en_US`), используемую для определения правил сортировки и сравнения строк в указанных столбцах. +6. Первичный ключ таблицы: `PRIMARY KEY` – обязательное условие при создании таблицы в режиме совместимости YDB с PostgreSQL; +7. Ограничения на уровне таблицы (может быть множество, перечисляются через запятую): `CONSTRAINT` – данный тип ограничения используется как альтернативный синтаксис записи поколоночным ограничениям, или когда нужно задать одинаковые условия ограничения на несколько колонок. Для указания ограничения необходимо указать: + + Ключевое слово `CONSTRAINT`; + + Имя ограничения <constraint name>. Правила создания идентификатора для ограничения такие же, как у названия таблиц и названия колонок; + + Ограничение. Например, `PRIMARY KEY (<column name>)`. + + +## Создание двух таблиц с первичным ключом и автоинкрементом {#create_table_pk_serial} +#| +|| **Таблица people** | **Таблица social_card** || +|| +```sql +CREATE TABLE people ( + id Serial PRIMARY KEY, + name Text, + lastname Text, + age Int, + country Text, + state Text, + city Text, + birthday Date, + sex Text, + social_card_number Int +); +``` +| +```sql +CREATE TABLE social_card ( + id Serial PRIMARY KEY, + social_card_number Int, + card_holder_name Text, + card_holder_lastname Text, + issue Date, + expiry Date, + issuing_authority Text, + category Text +); +``` +|| +|# + + +В этом примере мы использовали псевдотип данных `Serial` – это удобный и простой способ создать автоинкремент, который автоматически увеличивается на 1 при добавлении новой строки в таблицу. + + +## Создание таблицы с ограничениями {#create_table_constraint_table} + +```sql +CREATE TABLE people ( + id Serial, + name Text NOT NULL, + lastname Text NOT NULL, + age Int, + country Text, + state Text, + city Text, + birthday Date, + sex Text NOT NULL, + social_card_number Int, + CONSTRAINT pk PRIMARY KEY(id) +); +``` + +В этом примере мы создали таблицу "people" с ограничением (блоком `CONSTRAINT`), в котором задали первичный ключ (`PRIMARY KEY`) для колонки "id". Альтернативная запись может выглядеть так: `PRIMARY KEY(id)` без указания ключевого слова `CONSTRAINT`. + + +## Создание временной таблицы {#create_table_temp_table} + + +{% note warning %} + +Функциональность временной таблицы реализована не полностью. + +{% endnote %} + + +```sql +CREATE TEMPORARY TABLE people ( + id serial PRIMARY KEY, + name TEXT NOT NULL +); +``` + +Временная таблица задается через ключевое слово `TEMPORARY`. Она существует до конца сеанса или до завершения транзакции, далее она автоматически удаляется. + + +## Создание таблицы с условиями сортировки {#create_table_collate} + +```sql +CREATE TABLE people ( + id Serial PRIMARY KEY, + name Text COLLATE "en_US", + lastname Text COLLATE "en_US", + age Int, + country Text, + state Text, + city Text, + birthday Date, + sex Text, + social_card_number Int +); +``` + +В этом примере колонки "name" и "lastname" используют сортировку с `en_US` локализацией. + +{% include [../_includes/alert_locks.md](../_includes/alert_locks.md) %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/statements/delete_from.md b/ydb/docs/ru/core/postgresql/statements/delete_from.md new file mode 100644 index 0000000000..438c5e136d --- /dev/null +++ b/ydb/docs/ru/core/postgresql/statements/delete_from.md @@ -0,0 +1,20 @@ +# DELETE FROM (удаление строк из таблицы) + +{% include [../_includes/alert_preview.md)](../_includes/alert_preview.md) %} + +Синтаксис инструкции `DELETE FROM`: + ```sql + DELETE FROM <table name> + WHERE <column name><condition><value/range>; + ``` +Для удаления строки из таблицы по конкретному значению столбца используется конструкция `DELETE FROM <table name> WHERE <column name><condition><value/range>`. + + +{% note warning %} + +Обратите внимание, что использование оператора `WHERE ...` опционально, поэтому при работе с `DELETE FROM` очень важно случайно не выполнить команду раньше указания оператора `WHERE ...`. + +{% endnote %} + + +{% include [../_includes/alert_locks.md](../_includes/alert_locks.md) %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/statements/drop_table.md b/ydb/docs/ru/core/postgresql/statements/drop_table.md new file mode 100644 index 0000000000..a3091e4998 --- /dev/null +++ b/ydb/docs/ru/core/postgresql/statements/drop_table.md @@ -0,0 +1,16 @@ +# DROP TABLE (удаление таблицы) + +{% include [../_includes/alert_preview.md)](../_includes/alert_preview.md) %} + +Синтаксис инструкции `DROP TABLE`: +```sql +DROP TABLE [IF EXISTS] <table name>; +``` +Инструкция `DROP TABLE <table name>;` предназначена для удаления таблицы. Например: `DROP TABLE people;`. Если удаляемая таблица отсутствует – будет выведено сообщение об ошибки: +``` +Error: Cannot find table '...' because it does not exist or you do not have access permissions. Please check correctness of table path and user permissions., code: 2003 +``` + +В ряде сценариев такое поведение не требуется. Например, если мы хотим гарантированно создать новую таблицу с удалением предыдущий в рамках одного SQL-скрипта или последовательности SQL-команд. В таких случаях применяется инструкция `DROP TABLE IF EXIST <table name>`. В случае отсутствия таблицы инструкция вернет сообщение `DROP TABLE`, а не ошибку. + +{% include [../_includes/alert_locks.md](../_includes/alert_locks.md) %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/statements/insert_into.md b/ydb/docs/ru/core/postgresql/statements/insert_into.md new file mode 100644 index 0000000000..6ae772dd62 --- /dev/null +++ b/ydb/docs/ru/core/postgresql/statements/insert_into.md @@ -0,0 +1,51 @@ +# INSERT INTO (вставка строк в таблицу) + +{% include [../_includes/alert_preview.md)](../_includes/alert_preview.md) %} + +Синтаксис инструкции `INSERT INTO`: +```sql +INSERT INTO <table name> (<column name>, ...) +VALUES (<value>); +``` + +Инструкция `INSERT INTO` предназначена для добавления строк в таблицу. Она может добавить одну или несколько строк за одно исполнение. Пример вставки одной строки в таблицу "people": +```sql +INSERT INTO people (name, lastname, age, country, state, city, birthday, sex) +VALUES ('John', 'Doe', 30, 'USA', 'California', 'Los Angeles', CAST('1992-01-15' AS Date), 'Male'); +``` + +В этой записи мы не указали столбец `id` и не задали ему значение – это сделано намеренно, так как в таблице "people" у столбца "id" задан тип данных `Serial`. При выполнении инструкции `INSERT INTO` значение столбца "id" будет присвоено автоматически с учетом предыдущих значений – будет выполнен инкремент текущего значения "id". + +Для множественной вставки строк в таблицу используется та же конструкция с перечислением групп данных для вставки через запятую: +```sql +INSERT INTO people (name, lastname, age, country, state, city, birthday, sex) +VALUES + ('Jane', 'Smith', 25, 'Canada', 'Ontario', 'Toronto', CAST('1997-08-23' AS Date), 'Female'), + ('Alice', 'Johnson', 28, 'UK', 'England', 'London', CAST('1994-05-05' AS Date), 'Female'), + ('Bob', 'Brown', 40, 'USA', 'Texas', 'Dallas', CAST('1982-12-10' AS Date), 'Male'), + ('Charlie', 'Davis', 35, 'Canada', 'Quebec', 'Montreal', CAST('1987-02-17' AS Date), 'Male'), + ('Eve', 'Martin', 29, 'UK', 'Scotland', 'Edinburgh', CAST('1993-11-21' AS Date), 'Female'), + ('Frank', 'White', 45, 'USA', 'Florida', 'Miami', CAST('1977-03-14' AS Date), 'Male'), + ('Grace', 'Clark', 50, 'Canada', 'British Columbia', 'Vancouver', CAST('1972-04-26' AS Date), 'Female'), + ('Hank', 'Miller', 33, 'UK', 'Wales', 'Cardiff', CAST('1989-07-30' AS Date), 'Male'), + ('Ivy', 'Garcia', 31, 'USA', 'Arizona', 'Phoenix', CAST('1991-09-05' AS Date), 'Female'), + ('Jack', 'Anderson', 22, 'Canada', 'Manitoba', 'Winnipeg', CAST('2000-06-13' AS Date), 'Male'), + ('Kara', 'Thompson', 19, 'UK', 'Northern Ireland', 'Belfast', CAST('2003-10-18' AS Date), 'Female'), + ('Liam', 'Martinez', 55, 'USA', 'New York', 'New York City', CAST('1967-01-29' AS Date), 'Male'), + ('Molly', 'Robinson', 40, 'Canada', 'Alberta', 'Calgary', CAST('1982-12-01' AS Date), 'Female'), + ('Noah', 'Lee', 47, 'UK', 'England', 'Liverpool', CAST('1975-05-20' AS Date), 'Male'), + ('Olivia', 'Gonzalez', 38, 'USA', 'Illinois', 'Chicago', CAST('1984-03-22' AS Date), 'Female'), + ('Paul', 'Harris', 23, 'Canada', 'Saskatchewan', 'Saskatoon', CAST('1999-08-19' AS Date), 'Male'), + ('Quinn', 'Lewis', 34, 'UK', 'England', 'Manchester', CAST('1988-07-25' AS DATE), 'Female'), + ('Rachel', 'Young', 42, 'USA', 'Ohio', 'Cleveland', CAST('1980-02-03' AS Date), 'Female'); +``` + +В обоих примерах для указания даты выпуска фильма, мы использовали функцию `CAST()`, которая используется для преобразования одного типа данных в другой. В данном случае мы с помощью ключевого слова `AS` и типа данных `Date` явно указали, что хотим преобразовать строковое представление даты в формате [ISO8601](https://ru.wikipedia.org/wiki/ISO_8601). + +Указать нужный тип данных, например, `DATE` можно и альтернативным способом с помощью оператора приведения типов `::`, который используется для явного приведения значения одного типа данных к другому. Пример использования оператора `::` может выглядеть так: +```sql +INSERT INTO people (name, lastname, age, country, state, city, birthday, sex) +VALUES ('Sam', 'Walker', 60, 'Canada', 'Nova Scotia', 'Halifax', '1962-04-15'::Date, 'Male'); +``` + +{% include [../_includes/alert_locks.md](../_includes/alert_locks.md) %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/statements/select.md b/ydb/docs/ru/core/postgresql/statements/select.md new file mode 100644 index 0000000000..d44b324dec --- /dev/null +++ b/ydb/docs/ru/core/postgresql/statements/select.md @@ -0,0 +1,262 @@ +# SELECT (Чтение строк из таблицы) + +{% include [../_includes/alert_preview.md)](../_includes/alert_preview.md) %} + +Синтаксис инструкции `SELECT`: +```sql +SELECT [<table column>, ... | *] +FROM [<table name> | <sub query>] AS <table name alias> +LEFT | RIGHT | CROSS | INNER JOIN <another table> AS <table name alias> ON <join condition> +WHERE <condition> +GROUP BY <table column> +HAVING <condition> +UNION | UNION ALL | EXCEPT | INTERSECT +ORDER BY <table column> [ASC | DESC] +LIMIT [<limit value>] +OFFSET <offset number> +``` + + +## Вызов SELECT без указания целевой таблицы {#select_func} +`SELECT` используется для возврата вычислений на клиентскую сторону, в случае если он вызван без дополнительных конструкций, так как `FROM ...`, `INSERT INTO ...` и т.д. Например, `SELECT` можно использовать для работы с датами, преобразования чисел или подсчета длины строки: +```sql +SELECT CURRENT_DATE + INTERVAL '1 day'; -- Возвращает завтрашнюю дату +SELECT LENGTH('Hello'); -- Возвращает длину строки 'Hello' +SELECT CAST('123' AS INTEGER); -- Преобразует строки в числа +``` + +Такое применение `SELECT` бывает полезно при тестировании, отладки выражений или SQL-функций без обращения к реальной таблице, но чаще `SELECT` используется для получения строк из одной или множества таблиц. + + +## Выборка значений из одного или нескольких столбцов {#select_from} +Для возвращения значений из одного или нескольких столбцов таблицы применяется `SELECT` в следующем виде: +```sql +SELECT <column name> , <column name> +FROM <table name>; +``` + +Чтобы прочитать все данные из таблицы, например, таблицы `people` – нужно выполнить команду `SELECT * FROM people;`, где `*` – это оператор выбора данных по всем столбцам. При такой записи будут возвращены все строки из таблицы с данными по всем столбцам. + +Вывести столбцы "id", "name" и "lastname" для всех строк таблицы `people` можно так: +```sql +SELECT id, name, lastname +FROM people; +``` + + +## Ограничение получаемых результатов выборки с помощью WHERE {#select_from_where} +Для выборки только части строк - используется оператор `WHERE` с условиями выборки: `WHERE <column name> <condition> <column value>;`: +```sql +SELECT id, name, lastname +FROM people +WHERE age > 30; +``` + +`WHERE` позволяет использовать несколько операторов условного выбора (`AND` (И), `OR`(ИЛИ)) для создания сложных условий выборок, например, диапазонов: +```sql +SELECT id, name, lastname +FROM people +WHERE age > 30 AND age < 45; +``` + + +## Получение части строк по условиям LIMIT и OFFSET {#select_from_where_limit} +Для ограничения количества строк в результатах выборки используется `LIMIT` с указанием количества строк: +```sql +SELECT id, name, lastname +FROM people +WHERE age > 30 AND age < 45 +LIMIT 5; +``` + +Так на печать будет выведено 5 первых строк из выборки. С `OFFSET` можно указать сколько нужно пропустить строк, прежде чем начать выдавать строки на печать: +```sql +SELECT id, name, lastname +FROM people +WHERE age > 30 AND age < 45 +OFFSET 3 +LIMIT 5; +``` + +При указании `OFFSET 3` первые 3 строки результирующей выборки из таблицы `people` будут пропущены. + + +## Сортировка результатов выборки с помощью ORDER BY {#select_from_where_order_by} +По умолчанию база данных не гарантирует порядок возврата строк, и он может отличаться от запроса к запросу. Если требуется сохранить определенный порядок строк – используется инструкция `ORDER BY` с указанием столбца для сортировки и направлением сортировки: +```sql +SELECT id, name, lastname, age +FROM people +WHERE age > 30 AND age < 45 +ORDER BY age DESC; +``` +Сортировка происходит по результатам, которые возвращает (`SELECT`), а не по исходным столбцам таблицы (`FROM`). Сортировать можно в прямом порядке – `ASC` (от меньшего к большему - вариант по умолчанию, можно не указывать) и в обратном – `DESC` (от большего к меньшему). Как сортировка будет выполняться, зависит от типа данных столбца. Например, строки хранятся в utf-8 и сравниваются по "unicode collate" (по кодам символов). + + +## Группировка результатов выборки из одной или нескольких таблиц с помощью GROUP BY {#select_from_where_group_by} +`GROUP BY` используется для сбора данных по нескольким записям и группировки результатов по одному или нескольким столбцам. Синтаксис использования `GROUP BY`: +```sql +SELECT <column name>, <column name>, ... +FROM <table name> +[WHERE <column name> = <value>] +GROUP BY <column name>, <column name>, ...; +[HAVING <column name> = <limit column value>] +[LIMIT <value>] +[OFFSET <value>] +``` +Пример группировки данных из таблицы "people" по полу ("sex") и возрасту ("age") с ограничением выборки (`WHERE`) по возрасту: +```sql +SELECT sex, age +FROM people +WHERE age > 40 +GROUP BY sex, age; +``` + +В предыдущем примере мы использовали `WHERE` – необязательный параметр фильтрации результата, который фильтрует отдельные строки до применения `GROUP BY`. В следующем примере мы используем `HAVING` для исключения из результата строки групп, не удовлетворяющих условию. `HAVING` фильтрует строки групп, созданных `GROUP BY`. При использовании `HAVING` запрос превращается в группируемый, даже если `GROUP BY` отсутствует. Все выбранные строки считаются формирующими одну группу, а в списке SELECT и предложении HAVING можно обращаться к столбцам таблицы только из агрегатных функций. Такой запрос будет выдавать единственную строку, если результат условия HAVING — true, и ноль строк в противном случае. + +**Примеры использования `HAVING`**: + +#| +|| **`HAVING` + `GROUP BY`** | **`HAVING` + `WHERE` + `GROUP BY`** || +|| +```sql +SELECT sex, country, age +FROM people +GROUP BY sex, country, age +HAVING sex = 'Female'; +``` +| +```sql +SELECT sex, name,age +FROM people +WHERE age > 40 +GROUP BY sex,name,age +HAVING sex = 'Female'; +``` +|| +|# + + +## Объединение таблиц с помощью оператора JOIN {#select_from_join_on} +`SELECT` можно применять к нескольким таблицам с указанием типа соединения таблиц. Объединение таблиц задается через оператор `JOIN`, который бывает пяти типов: `LEFT JOIN`, `RIGHT JOIN`, `INNER JOIN`, `CROSS JOIN`, `FULL JOIN`. Когда выполняется `JOIN` по определенному условию, например, по ключу, и в одной из таблиц есть несколько строк с одинаковым значением этого ключа, получается [декартово произведение](https://ru.wikipedia.org/wiki/Прямое_произведение). Это означает, что каждая строка из одной таблицы будет соединена с каждой соответствующей строкой из другой таблицы. + +### Объединение таблиц с помощью LEFT JOIN, RIGHT JOIN или INNER JOIN {#select_from_left_right__inner_join_on} +Синтаксис `SELECT` с использованием `LEFT JOIN`, `RIGHT JOIN`, `INNER JOIN`, `FULL JOIN` одинаков: +```sql +SELECT <table name left>.<column name>, ... , +FROM <table name left> +LEFT | RIGHT | INNER | FULL JOIN <table name right> AS <table name right alias> +ON <table name left>.<column name> = <table name right>.<column name>; +``` + +Все операторы `JOIN`, кроме `CROSS JOIN` использую для присоединения таблиц ключевое слово `ON`. В случае `CROSS JOIN`, синтаксис его использования будет следующем: `CROSS JOIN <table name> AS <table name alias>;`. Рассмотрим пример использования каждого оператора `JOIN` в отдельности. + +**LEFT JOIN** (или LEFT OUTER JOIN) +Возвращает все строки из левой таблицы и соответствующие строки из правой таблицы. Если нет совпадений, возвращает `NULL` (в выводе будет пустота) для всех колонок правой таблицы. Пример использования `LEFT JOIN`: +```sql +SELECT people.name, people.lastname, card.social_card_number +FROM people +LEFT JOIN social_card AS card +ON people.name = card.card_holder_name AND people.lastname = card.card_holder_lastname; +``` + +Результат выполнения SQL запроса с использованием `LEFT JOIN` без одной записи в правой таблице `social_card`: +``` + name | lastname | social_card_number +---------+----------+-------------------- + John | Doe | 123456789 + Jane | Smith | 223456789 + Alice | Johnson | 323456789 + Bob | Brown | 423456789 + Charlie | Davis | 523456789 + Eve | Martin | 623456789 + Frank | White | +``` + +**RIGHT JOIN** (или RIGHT OUTER JOIN) +Возвращает все строки из правой таблицы и соответствующие строки из левой таблицы. Если не существует совпадений, возвращает `NULL` для всех колонок левой таблицы. Этот тип `JOIN` редко используется, так как его функциональность можно заменить `LEFT JOIN`, меняя местами таблицы. Пример использования `RIGHT JOIN`: +```sql +SELECT people.name, people.lastname, card.social_card_number +FROM people +RIGHT JOIN social_card AS card +ON people.name = card.card_holder_name AND people.lastname = card.card_holder_lastname; +``` + +Результат выполнения SQL запроса с использованием `RIGHT JOIN` без одной записи в левой таблице `people`: +``` + name | lastname | social_card_number +---------+----------+-------------------- +John | Doe | 123456789 +Jane | Smith | 223456789 +Alice | Johnson | 323456789 +Bob | Brown | 423456789 +Charlie | Davis | 523456789 +Eve | Martin | 623456789 + | | 723456789 +``` + +**INNER JOIN** (или просто JOIN) +Возвращает строки, когда есть соответствующие значения в обеих таблицах. Исключает из результатов те строки, для которых нет совпадений в соединяемых таблицах. Пример использования `INNER JOIN`: +```sql +SELECT people.name, people.lastname, card.social_card_number +FROM people +RIGHT JOIN social_card AS card +ON people.name = card.card_holder_name AND people.lastname = card.card_holder_lastname; +``` + +Такой SQL запрос вернет только те строки, для которых есть совпадения в обеих таблицах: +``` + name | lastname | social_card_number +---------+----------+-------------------- +John | Doe | 123456789 +Jane | Smith | 223456789 +Alice | Johnson | 323456789 +Bob | Brown | 423456789 +Charlie | Davis | 523456789 +Eve | Martin | 623456789 +``` + +**CROSS JOIN** +Возвращает комбинированный результат каждой строки левой таблицы с каждой строкой правой таблицы. Обычно `CROSS JOIN` используется, когда необходимо получить все возможные комбинации строк из двух таблиц. `CROSS JOIN` просто комбинирует каждую строку одной таблицы с каждой строкой другой без какого-либо условия, поэтому в его синтаксисе отсутствуют ключевые слова `ON` или: `CROSS JOIN <table name> AS <table name alias>;`. + +Пример использования `CROSS JOIN` с ограничением вывода результата `LIMIT 5`: +```sql +SELECT people.name, people.lastname, card.social_card_number +FROM people +CROSS JOIN social_card AS card +LIMIT 5; +``` + +Пример выше вернет все возможные комбинации столбцов, участвующих в выборке из двух таблиц: +``` +name | lastname | social_card_number +------+----------+-------------------- + John | Doe | 123456789 + John | Doe | 223456789 + John | Doe | 323456789 + John | Doe | 423456789 + John | Doe | 523456789 +``` + +**FULL JOIN** (или FULL OUTER JOIN) +Возвращает как совпавшие, так и не совпавшие строки в обеих таблицах, при этом возвращает `NULL` в колонках из таблицы, для которой не найдено совпадение. Пример выполнения SQL запроса с использованием `FULL JOIN`: +```sql +SELECT people.name, people.lastname, card.social_card_number +FROM people +FULL JOIN social_card AS card +ON people.name = card.card_holder_name AND people.lastname = card.card_holder_lastname; +``` + +В результате выполнения SQL запроса будет возвращен следующей вывод: +``` + name | lastname | social_card_number +---------+----------+-------------------- + Liam | Martinez | 1323456789 + Eve | Martin | 623456789 + Hank | Miller | 923456789 + Molly | Robinson | 1423456789 + Sam | Walker | + Paul | Harris | 1723456789 + Kara | Thompson | 1223456789 + | | 1923456789 +... +```
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/statements/toc_m.yaml b/ydb/docs/ru/core/postgresql/statements/toc_m.yaml new file mode 100644 index 0000000000..ac797a4028 --- /dev/null +++ b/ydb/docs/ru/core/postgresql/statements/toc_m.yaml @@ -0,0 +1,22 @@ +items: +- name: CREATE TABLE + href: create_table.md + hidden: false +- name: DROP TABLE + href: drop_table.md + hidden: false +- name: DELETE FROM + href: delete_from.md + hidden: false +- name: INSERT INTO + href: insert_into.md + hidden: false +- name: SELECT + href: select.md + hidden: false +- name: UPDATE + href: update.md + hidden: false +- name: TRANSACTIONS + href: begin_commit_rollback.md + hidden: false diff --git a/ydb/docs/ru/core/postgresql/statements/update.md b/ydb/docs/ru/core/postgresql/statements/update.md new file mode 100644 index 0000000000..b5d352bd9a --- /dev/null +++ b/ydb/docs/ru/core/postgresql/statements/update.md @@ -0,0 +1,85 @@ +# UPDATE (изменения строк таблицы) + +{% include [../_includes/alert_preview.md)](../_includes/alert_preview.md) %} + +Синтаксис инструкции `UPDATE`: +```sql +UPDATE <table name> +SET <column name> = [<new value>, CASE ... END] +WHERE <search column name> = [<search value>, IN] +``` + +Конструкция `UPDATE ... SET ... WHERE` работает так: +1. **Задаётся название таблицы** – `UPDATE`` `<table name>`, в которой будет произведено обновление данных; +2. **Указывается название столбца** – `SET` `<column name>`, где следует обновить данные. Может применяться конструкция для указания набора данных `CASE ... END`; +3. **Задаётся новое значение** – `<new value>`; +4. **Указываются критерии поиска** – `WHERE` с указанием колонки для поиска `<search column name>` и значения, которому должен соответствовать критерий поиска <search value>. Если применяется `CASE`, тогда указывается оператор `IN` с перечислением значений <column name>. + +## Обновление одной строки в таблице с условиями + +#| +|| **Обновление без условий** | **Обновление с условиями** || +|| +```sql +UPDATE people +SET name = 'Alexander' +WHERE lastname = 'Doe'; +``` +| +```sql +UPDATE people +SET age = 31 +WHERE country = 'USA' AND city = 'Los Angeles'; +``` +|| +|# + +В примере "Обновление с условиями" используется оператор объединения условий `AND` (`И`) – условие будет выполнено только тогда, когда обе его части будут отвечать условиям истины. Также может использоваться оператор `OR`(`ИЛИ`) – условие будет выполнено, если хотя бы одна из его частей будет отвечать условиям истины. Оператор и условий может быть множество: +```sql +... +WHERE country = 'USA' AND city = 'Los Angeles' OR city = 'Florida'; +``` + +## Обновление одной записи в таблице с использованием выражений или функций {#update_set_func_where} +Часто при обновление данные нужно произвести с ними математические действия видоизменить с помощью функции. + +#| +|| **Обновление с применением выражений** | **Обновление с применением функций** || +|| +```sql +UPDATE people +SET age = age + 1 +WHERE country = 'Canada'; +``` +| +```sql +UPDATE people +SET name = UPPER(name) +WHERE country = 'USA'; +``` +|| +|# + + +## Обновление нескольких полей строки таблице {#update_set_where} +Обновить данные можно в нескольких колонках одновременно. Для этого делается перечисление <column name> = <column new value> после ключевого слова `SET`: +```sql +UPDATE people +SET country = 'Russia', city = 'Moscow' +WHERE lastname = 'Smith'; +``` + +## Обновление нескольких строк в таблицы с применением конструкции CASE ... END {#update_set_case_end_where} +Для одновременного обновления разных значений в разных строках можно использовать инструкцию `CASE ... END`, с вложенными условиями выборки данных `WHEN <column name> <condition> (=,>,<) THEN <new value>`. Далее следует конструкция `WHERE <column name> IN (<column value>, ...)`, которая позволяет задать список значений, по которым будет выполнено условие. + +Пример, где изменяется возраст (`age`) людей (`people`) в зависимости от их имен: + +```sql +UPDATE people +SET age = CASE + WHEN name = 'John' THEN 32 + WHEN name = 'Jane' THEN 26 + END +WHERE name IN ('John', 'Jane'); +``` +{% include [../_includes/alert_locks.md](../_includes/alert_locks.md) %}
\ No newline at end of file diff --git a/ydb/docs/ru/core/postgresql/toc_i.yaml b/ydb/docs/ru/core/postgresql/toc_i.yaml index 6e9467ecc7..9e92f836df 100644 --- a/ydb/docs/ru/core/postgresql/toc_i.yaml +++ b/ydb/docs/ru/core/postgresql/toc_i.yaml @@ -6,8 +6,11 @@ items: href: docker-connect.md hidden: false - name: Синтаксис PostgreSQL - href: statements.md + include: { mode: link, path: ./statements/toc_m.yaml } hidden: false +- name: Механизмы PostgreSQL + include: { mode: link, path: ./mechanisms/toc_m.yaml } + hidden: true - name: Функции PostgreSQL href: functions.md hidden: false |