Занятие №1
Реляционная алгебра
В дальнейшем в курсе пойдёт речь о работе с таблицами. В таблице мы можем хранить информацию.
Рассмотрим, например, такую таблицу с некоторой информацией про студентов:
StudentID | Name | Age | Major | GPA |
---|---|---|---|---|
1 | Иванов И.И. | 20 | Информатика | 3.8 |
2 | Петрова А.А. | 22 | Математика | 3.5 |
3 | Сидоров П.П. | 21 | Физика | 3.9 |
Каждая строка описывает некоторого студента.
Каждый столбец обозначает некоторое свойство - ФИО, возраст, средний балл.
В столбце со средним баллом ожидаем дробное число;
В столбце Major ожидаем название предмета.
Для формализации правил работы с таблицами вводится реляционная алгебра.
С некоторыми допущениями будем частично отождествлять понятия из реляционной алгебры и понятия, известные нам из работы с таблицами.
Основные понятия реляционной алгебры
Реляционная алгебра представляет собой теоретический язык для работы с отношениями в реляционных базах данных. Она основана на теории множеств и включает набор операций, позволяющих манипулировать данными. Ключевые понятия и операции реляционной алгебры включают следующие элементы:
Основные термины
-
Сущность: Объект предметной области, который моделируется в базе данных.
-
Кортеж: Экземпляр сущности, (строка в таблице, содержащая значения атрибутов).
-
Атрибут: Свойство сущности, отражающее характеристики (столбец).
-
Домен: Множество допустимых значений для атрибута.
-
Отношение: Таблица, состоящая из заголовка и множества кортежей (строк).
-
Заголовок отношения: Список атрибутов;
-
Тело отношения: Множество кортежей, входящих в состав отношения; или
-
Тело отношения: Подмножество декартова произведения доменов.
Опишите пример, используя новые термины:
StudentID | Name | Age | Major | GPA |
---|---|---|---|---|
1 | Иванов И.И. | 20 | Информатика | 3.8 |
2 | Петрова А.А. | 22 | Математика | 3.5 |
3 | Сидоров П.П. | 21 | Физика | 3.9 |
4 | Смирнова Е.Е. | 23 | Химия | 3.6 |
5 | Кузнецов В.В. | 20 | Биология | 3.7 |
Для атрибута Major доменом будет являться множество предметов:
{Информатика, Математика, Физика, Химия, Биология}.
Свойства отношений
-
Уникальность кортежей
-
Степень отношения (арность отношения): Степень отношения определяется количеством атрибутов (столбцов) в нем. Например, если отношение имеет три атрибута, его степень равна 3.
-
Мощность отношения (кардинальность отношения): количество кортежей в отношении.
-
Домен атрибутов: Каждый атрибут в отношении связан с определенным доменом, который представляет собой множество допустимых значений для этого атрибута. Это обеспечивает семантическую однозначность данных.
-
Замкнутость операций: Все операции реляционной алгебры над отношениями возвращают новое отношение, что позволяет комбинировать результаты различных операций и строить сложные запросы.
Эти свойства формируют основу для работы с данными в реляционных базах и обеспечивают их целостность и структурированность.
Операции реляционной алгебры
Реляционная алгебра включает восемь основных операций, предложенных Эдгаром Коддом:
- Объединение (Union): Возвращает отношение, содержащее все кортежи, которые принадлежат хотя бы одному из двух заданных отношений.
- Пересечение (Intersection): Возвращает отношение с кортежами, которые принадлежат обоим заданным отношениям.
- Разность (Set Difference): Возвращает отношение с кортежами, которые принадлежат первому отношению, но не принадлежат второму.
- Декартово произведение (Cartesian Product): Создает новое отношение, состоящее из всех возможных пар кортежей из двух заданных отношений.
- Выборка (Ограничение, Selection): Извлекает кортежи из отношения, удовлетворяющие определенному условию.
- Проекция (Projection): Извлекает определенные атрибуты из отношения, создавая новое отношение с выбранными атрибутами.
- Соединение (Join): Объединяет два отношения по общему атрибуту, создавая новое отношение с соответствующими кортежами.
- Деление (Division): Используется для получения кортежей из одного отношения, которые соответствуют всем значениям атрибутов другого отношения.
Примеры операций реляционной алгебры
Рассмотрим примеры для каждой из основных операций реляционной алгебры, используя две таблицы: Students
и Courses
.
Обсудите, какое отношение будет являться результатом для каждой операции.
Таблица: Students
StudentID | Name | Major |
---|---|---|
1 | Иванов И.И. | Информатика |
2 | Петрова А.А. | Математика |
3 | Сидоров П.П. | Физика |
Таблица: MoreStudents
StudentID | Name | Major |
---|---|---|
3 | Сидоров П.П. | Физика |
4 | Смирнова Е.Е. | Информатика |
Таблица: Courses
CourseID | CourseName | StudentID |
---|---|---|
C1 | Алгоритмы | 1 |
C2 | Линейная алгебра | 2 |
C3 | Физика | 3 |
C4 | Программирование | 1 |
1. Объединение (Union)
Объединение двух отношений с совпадающими заголовками.
Например, если у нас есть ещё одна таблица MoreStudents
, содержащая студентов, мы можем объединить их:
$$ Students \cup MoreStudents $$
Результат объединения
StudentID | Name | Major |
---|---|---|
1 | Иванов И.И. | Информатика |
2 | Петрова А.А. | Математика |
3 | Сидоров П.П. | Физика |
4 | Смирнова Е.Е. | Информатика |
2. Пересечение (Intersection)
Возвращает кортежи, которые присутствуют в обоих отношениях с совпадающими заголовками. Например: $$ Students \cap MoreStudents $$
Результат пересечения
StudentID | Name | Major |
---|---|---|
3 | Сидоров П.П. | Физика |
3. Разность (Set Difference)
Возвращает кортежи из первого отношения, которые отсутствуют во втором. У отношений должны совпадать заголовки.
$$ Students - MoreStudents $$
Результат разности
StudentID | Name | Major |
---|---|---|
1 | Иванов И.И. | Информатика |
2 | Петрова А.А. | Математика |
4. Декартово произведение (Cartesian Product)
Создает новое отношение, состоящее из всех возможных пар кортежей из двух отношений:
$$ Students \times Courses $$
Сколько кортежей будет в таком отношении?
Ответ
StudentID | Name | Major | CourseID | CourseName | StudentID |
---|---|---|---|---|---|
1 | Иванов И.И. | Информатика | C1 | Алгоритмы | 1 |
1 | Иванов И.И. | Информатика | C2 | Линейная алгебра | 2 |
1 | Иванов И.И. | Информатика | C3 | Физика | 3 |
1 | Иванов И.И. | Информатика | C4 | Программирование | 1 |
2 | Петрова А.А. | Математика | C1 | Алгоритмы | 1 |
2 | Петрова А.А. | Математика | C2 | Линейная алгебра | 2 |
2 | Петрова А.А. | Математика | C3 | Физика | 3 |
2 | Петрова А.А. | Математика | C4 | Программирование | 1 |
3 | Сидоров П.П. | Физика | C1 | Алгоритмы | 1 |
3 | Сидоров П.П. | Физика | C2 | Линейная алгебра | 2 |
3 | Сидоров П.П. | Физика | C3 | Физика | 3 |
3 | Сидоров П.П. | Физика | C4 | Программирование | 1 |
5. Выборка (Ограничение, Selection)
Извлекает кортежи из отношения, удовлетворяющие заданному условию. Например, чтобы выбрать студентов, которые изучают “Информатику”:
$$ \sigma_{Major=‘Информатика’}(Students) $$
Ответ
StudentID | Name | Major |
---|---|---|
1 | Иванов И.И. | Информатика |
6. Проекция (Projection)
Извлекает определенные атрибуты из отношения. Например, чтобы получить только имена студентов:
$$ \pi_{Name}(Students) $$
Ответ
Name |
---|
Иванов И.И. |
Петрова А.А. |
Сидоров П.П. |
7. Соединение (Join)
Объединяет два отношения по общему атрибуту. Например, чтобы получить список студентов и названий их курсов:
$$ Students \bowtie Courses $$
Упражнение: в данном примере выразить Join через декартово произведение, ограничение и проекцию.
Ответ
$\sigma_{Students.StudentID=Courses.StudentID}(Students \times Courses)$
(После чего убираем проекцией повторяющийся атрибут StudentID)
StudentID | Name | Major | CourseID | CourseName |
---|---|---|---|---|
1 | Иванов И.И. | Информатика | C1 | Алгоритмы |
2 | Петрова А.А. | Математика | C2 | Линейная алгебра |
3 | Сидоров П.П. | Физика | C3 | Физика |
1 | Иванов И.И. | Информатика | C4 | Программирование |
8. Деление (Division)
Используется для получения кортежей из одного отношения, которые соответствуют всем значениям атрибутов другого отношения. Например, если мы хотим найти студентов, которые изучают все курсы:
$$ Students \div Courses $$
Какой будет результат операции деления для отношений ниже?
Students
Name | Course |
---|---|
Иванов И.И. | Алгоритмы |
Иванов И.И. | Программирование |
Сидоров П.П. | Алгоритмы |
Courses
Course |
---|
Алгоритмы |
Программирование |
Ответ
Name |
---|
Иванов И.И. |
Схема и таблица в PostgreSQL
Схема
Схема в PostgreSQL представляет собой логическую группировку объектов базы данных, таких как таблицы, представления, индексы, функции и типы данных. Она служит пространством имен, позволяя организовать объекты и избегать конфликтов имен. В одной базе данных может быть несколько схем, и объекты с одинаковыми именами могут существовать в разных схемах.
Основные характеристики схемы:
- Создание схемы: Для создания схемы используется команда:
CREATE SCHEMA имя_схемы;
- Пространство имен: Схемы позволяют использовать одни и те же имена для объектов в разных схемах. Например, таблицы
schema1.table1
иschema2.table1
могут существовать одновременно. - Управление доступом: Схемы позволяют управлять правами доступа к объектам на уровне группы или пользователя, что упрощает безопасность и администрирование базы данных[1][5][6].
Таблица
Таблица в PostgreSQL — это основная структура хранения данных, представляющая собой набор строк и столбцов. Каждая таблица состоит из кортежей (строк), которые содержат данные, и атрибутов (столбцов), которые описывают характеристики этих данных.
Основные характеристики таблицы:
- Создание таблицы: Для создания таблицы используется команда:
CREATE TABLE имя_таблицы ( имя_столбца1 тип_данных1, имя_столбца2 тип_данных2, ... );
- Структура данных: Каждая таблица имеет определенные атрибуты с заданными типами данных (например,
INTEGER
,VARCHAR
,DATE
), что позволяет контролировать формат хранимых данных.
Пример использования
Для создания схемы и таблицы в PostgreSQL можно использовать следующий пример:
-- Создание схемы
CREATE SCHEMA school;
-- Создание таблицы в схеме school
CREATE TABLE school.students (
student_id SERIAL PRIMARY KEY,
name VARCHAR(100),
age INTEGER
);
В этом примере создается схема school
, которая содержит таблицу students
с тремя атрибутами: student_id
, name
и age
.
Общая структура SELECT-запроса и порядок выполнения запроса
Общая структура SELECT-запроса
Запросы на выборку данных в SQL начинаются с ключевого слова SELECT
, за которым следуют указания о том, какие данные необходимо извлечь. Основная структура запроса выглядит следующим образом:
SELECT [DISTINCT | ALL] column1, column2, ...
FROM table_name
[WHERE condition]
[GROUP BY column]
[HAVING condition]
[ORDER BY column [ASC | DESC]]
[LIMIT number];
Описание компонентов:
- SELECT: Указывает, какие столбцы нужно выбрать. Можно использовать
*
для выбора всех столбцов или перечислить конкретные столбцы. - FROM: Указывает таблицу (или несколько таблиц), из которой выбираются данные.
- WHERE: (необязательный) Фильтрует строки на основе заданного условия.
- GROUP BY: (необязательный) Группирует строки по указанным столбцам для агрегирования данных.
- HAVING: (необязательный) Фильтрует группы, созданные с помощью
GROUP BY
, на основе заданного условия. - ORDER BY: (необязательный) Указывает порядок сортировки результатов по одному или нескольким столбцам.
- LIMIT / OFFSET / FETCH: (необязательный) Ограничивает количество возвращаемых строк.
Порядок выполнения запроса
При выполнении SQL-запроса порядок обработки различных частей запроса не соответствует порядку их написания. Обычно порядок выполнения запросов можно представить следующим образом:
- FROM: Сначала определяется набор данных из указанных таблиц.
- WHERE: Применяются условия фильтрации к строкам из набора данных.
- GROUP BY: Строки группируются по указанным столбцам.
- HAVING: Применяются условия фильтрации к сгруппированным данным.
- SELECT: Выбираются указанные столбцы из оставшихся данных.
- ORDER BY: Результаты сортируются по указанным столбцам.
- LIMIT / OFFSET / FETCH: Ограничивается количество возвращаемых строк.
Этот порядок выполнения позволяет оптимизировать процесс обработки запросов и обеспечивает правильное извлечение данных в соответствии с заданными условиями и требованиями.
Пример таблицы в PostgreSQL и запросы SELECT
В качестве упражнения выполните следующие запросы устно и проверьте с использованием СУБД.
Создание таблицы
Рассмотрим простую таблицу employees
, которая будет хранить информацию о сотрудниках.
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name VARCHAR(50),
department VARCHAR(50),
salary NUMERIC,
age INTEGER
);
INSERT INTO employees (name, department, salary, age) VALUES
('Иванов И.И.', 'IT', 60000, 30),
('Петрова А.А.', 'HR', 55000, 28),
('Сидоров П.П.', 'IT', 70000, 35),
('Смирнова Е.Е.', 'Marketing', 55000, 32),
('Кузнецов В.В.', 'HR', 48000, 29);
Пример данных в таблице employees
Получим все записи в таблице.
SELECT *
FROM employees;
id | name | department | salary | age |
---|---|---|---|---|
1 | Иванов И.И. | IT | 60000 | 30 |
2 | Петрова А.А. | HR | 55000 | 28 |
3 | Сидоров П.П. | IT | 70000 | 35 |
4 | Смирнова Е.Е. | Marketing | 55000 | 32 |
5 | Кузнецов В.В. | HR | 48000 | 29 |
Примеры запросов SELECT
-
Запрос с подмножеством атрибутов (проекция)
SELECT name, department FROM employees;
-
Запрос с использованием WHERE (ограничение)
Получим сотрудников из отдела IT:
SELECT * FROM employees WHERE department = 'IT';
Символ
*
в SQL-запросеSELECT
используется для выбора всех столбцов из указанной таблицы. Например:SELECT * FROM employees;
Этот запрос вернет все строки и столбцы из таблицы
employees
. Использование*
удобно для быстрого получения всех данных, но в случае больших таблиц лучше указывать только необходимые столбцы для повышения производительности. -
Запрос с использованием GROUP BY
Получим среднюю зарплату по каждому отделу:
SELECT department, AVG(salary) AS average_salary FROM employees GROUP BY department;
При группировке в блоке
SELECT
могут встречаться либо атрибуты, по которым происходит группировка, либо атрибуты, которые подаются на вход агрегирующим функциям. В SQL есть 5 стандартных агрегирующих функций. При выполнении запроса функции не учитывается специальное значениеNULL
, которым обозначается отсутствующее значение.count()
– количество записей с известным значением. Если необходимо подсчитать количество уникальных значений, можно использоватьcount(DISTINCT field_nm)
max()
- наибольшее из всех выбранных значений поляmin()
- наименьшее из всех выбранных значений поляsum()
- сумма всех выбранных значений поляavg()
- среднее всех выбранных значений поля
-
Запрос с использованием HAVING
Получим отделы, где средняя зарплата превышает 50000:
SELECT department, AVG(salary) AS average_salary FROM employees GROUP BY department HAVING AVG(salary) > 50000;
-
Запрос с использованием ORDER BY
Получим всех сотрудников, отсортированных по зарплате в порядке убывания:
SELECT * FROM employees ORDER BY salary DESC;
-
Запрос с использованием FETCH
Получим трёх самых молодых сотрудников:
SELECT * FROM employees ORDER BY age ASC FETCH FIRST 3 ROWS ONLY;
Выполните следующий запрос. Сколько строк вернул этот запрос? Почему?
SELECT * FROM employees ORDER BY salary DESC FETCH FIRST 3 ROWS WITH TIES;
-
Запрос с использованием LIMIT
LIMIT
- сокращениеFETCH
Получим только двух самых высокооплачиваемых сотрудников:
SELECT * FROM employees ORDER BY salary DESC LIMIT 2;
-
Запрос с использованием OFFSET
Получим всех сотрудников кроме двух самых высокооплачиваемых сотрудников:
SELECT * FROM employees ORDER BY salary DESC OFFSET 2;
-
Запрос с использованием DISTINCT
Получим самого высокооплачиваемого сотрудника в каждом отделе:
SELECT DISTINCT ON (department) id, name, department, salary FROM employees ORDER BY department, salary DESC;
Получим количество отделов:
SELECT COUNT(DISTINCT department) FROM employees;
-
Запрос с использованием UNION и UNION ALL (объединение)
Важно: при использовании теоретико-множественных операций типы данных соответствующих полей должны быть совместимыми.
Чтобы продемонстрировать разницу между
UNION
иUNION ALL
, приведем пример с использованием двух наборов данных.Предположим, у нас есть две таблицы, которые содержат информацию о сотрудниках:
Создание временных таблиц
CREATE TEMP TABLE employees_a ( id SERIAL PRIMARY KEY, name VARCHAR(50), salary NUMERIC ); INSERT INTO employees_a (name, salary) VALUES ('Иванов И.И.', 60000), ('Петрова А.А.', 50000), ('Сидоров П.П.', 70000); CREATE TEMP TABLE employees_b ( id SERIAL PRIMARY KEY, name VARCHAR(50), salary NUMERIC ); INSERT INTO employees_b (name, salary) VALUES ('Смирнова Е.Е.', 55000), ('Кузнецов В.В.', 60000), ('Иванов И.И.', 60000);
Использование UNION
Теперь мы можем использовать
UNION
, чтобы объединить данные из обеих таблиц и удалить дубликаты:SELECT name, salary FROM employees_a UNION SELECT name, salary FROM employees_b;
Результат запроса с UNION:
name salary Иванов И.И. 60000 Петрова А.А. 50000 Сидоров П.П. 70000 Смирнова Е.Е. 55000 Кузнецов В.В. 60000 Использование UNION ALL
Теперь используем
UNION ALL
, чтобы объединить данные из обеих таблиц и сохранить все дубликаты:SELECT name, salary FROM employees_a UNION ALL SELECT name, salary FROM employees_b;
Результат запроса с UNION ALL:
name salary Иванов И.И. 60000 Петрова А.А. 50000 Сидоров П.П. 70000 Смирнова Е.Е. 55000 Кузнецов В.В. 60000 Иванов И.И. 60000 Выводы
UNION
: Удаляет дубликаты из результирующего набора, возвращая уникальные строки.UNION ALL
: Сохраняет все строки из обоих наборов данных, включая дубликаты.
Таким образом, использование
UNION
илиUNION ALL
зависит от ваших требований к обработке дубликатов в результирующем наборе данных.UNION
применяет к строкам результатаDISTINCT
, что требует дополнительных временных затрат. -
Использование INTERSECT (пересечение)
SELECT name, salary FROM employees_a INTERSECT SELECT name, salary FROM employees_b;
Результат запроса с INTERSECT:
name salary Иванов И.И. 60000 -
Использование EXCEPT (разность)
SELECT name, salary FROM employees_a EXCEPT SELECT name, salary FROM employees_b;
Результат запроса с EXCEPT:
name salary Сидоров П.П. 70000 Петрова А.А. 50000
Полезные функции
Функции GREATEST и LEAST
Функции GREATEST
и LEAST
позволяют находить максимальное и минимальное значение среди нескольких аргументов.
- GREATEST: Возвращает наибольшее значение из списка аргументов. Если все аргументы равны
NULL
, результат будетNULL
.
SELECT GREATEST(column1, column2, column3) AS max_value FROM table_name;
- LEAST: Возвращает наименьшее значение из списка аргументов. Аналогично, если все аргументы равны
NULL
, результат будетNULL
.
SELECT LEAST(column1, column2, column3) AS min_value FROM table_name;
Пример использования GREATEST и LEAST
Предположим, у нас есть таблица с оценками студентов:
CREATE TABLE grades (
student_id INT,
exam1 FLOAT,
exam2 FLOAT,
exam3 FLOAT
);
INSERT INTO grades (student_id, exam1, exam2, exam3) VALUES
(1, 85.0, NULL, 90.0),
(2, 78.0, 82.0, 88.0),
(3, NULL, NULL, 95.0);
Чтобы найти максимальную оценку для каждого студента:
SELECT student_id, GREATEST(exam1, exam2, exam3) AS max_grade
FROM grades;
Для нахождения минимальной оценки:
SELECT student_id, LEAST(exam1, exam2, exam3) AS min_grade
FROM grades;
Иногда бывает полезно использовать в запросе специальные функции:
IN
- принадлежность определенному набору значений:X IN (a1, a2, ..., an)
≣ X = a1 or X = a2 or … or X = anBETWEEN
- принадлежность определенному интервалу значений:X BETWEEN A AND B
≣ (A <= X <= B) or (B <= X <= A)LIKE
- удовлетворение текста паттерну:X LIKE '0%abc_0'
, где_
- ровно 1 символ, а%
- любая последовательность символов (в том числе нулевой длины).IF ... THEN ... [ELSIF ... THEN ... ELSE ...] END IF
- ветвления, пример:
SELECT
IF number = 0 THEN
'zero'
ELSIF number > 0 THEN
'positive'
ELSIF number < 0 THEN
'negative'
ELSE
'NULL'
END IF AS number_class
FROM
numbers
CASE [...] WHEN ... THEN ... ELSE ... END CASE
- еще один аналог ветвлений, пример:
SELECT
CASE
WHEN number = 0 THEN
'zero'
WHEN number > 0 THEN
'positive'
WHEN number < 0 THEN
'negative'
ELSE
'NULL'
END CASE AS number_class
FROM
numbers
DISTINCT ON
- исключает строки, совпадающие по всем указанным выражениям, пример:
-- вывести кол-во уникальных отделов
SELECT
count(DISTINCT ON department_nm)
FROM
salary;
Работа с NULL
В PostgreSQL значение NULL
используется для обозначения отсутствия данных. Это специальное значение, которое указывает на то, что ячейка таблицы не содержит данных. При работе с NULL
важно понимать, как он влияет на различные операции и запросы.
-
Создание таблицы с NULL: При создании таблицы можно указать, какие столбцы могут содержать
NULL
:CREATE TABLE COMPANY ( ID INT PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, AGE INT NOT NULL, ADDRESS CHAR(50), SALARY REAL );
В этом примере столбцы
ADDRESS
иSALARY
могут содержатьNULL
, так как они не имеют ограниченияNOT NULL
. -
Вставка значений NULL: Чтобы вставить значение
NULL
, можно просто пропустить его или явно указать:INSERT INTO COMPANY (NAME, AGE, ADDRESS, SALARY) VALUES ('Kim', 22, NULL, NULL);
-
Обновление значений на NULL: Используйте оператор
UPDATE
, чтобы установить значение столбца вNULL
:UPDATE COMPANY SET ADDRESS = NULL WHERE ID = 6;
-
Выборка значений с использованием IS NULL и IS NOT NULL: Для фильтрации записей по наличию или отсутствию значений
NULL
используются операторы:-- Выборка записей с ненулевыми зарплатами SELECT * FROM COMPANY WHERE SALARY IS NOT NULL; -- Выборка записей с нулевыми зарплатами SELECT * FROM COMPANY WHERE SALARY IS NULL;
-
Сравнение с NULL: Операции сравнения с
NULL
возвращают результатNULL
. Например:SELECT * FROM COMPANY WHERE SALARY = NULL; -- Не вернет никаких строк
Вместо этого следует использовать
IS NULL
. -
Использование функций для обработки NULL:
- COALESCE: Возвращает первое ненулевое значение из списка.
SELECT COALESCE(SALARY, 0) AS Salary FROM COMPANY;
- NULLIF: Возвращает
NULL
, если два аргумента равны.SELECT SALARY / NULLIF(AGE, 0) AS SalaryPerYear FROM COMPANY;
- COALESCE: Возвращает первое ненулевое значение из списка.
-
Агрегационные функции и NULL: Агрегационные функции игнорируют значения
NULL
. Например, при использованииSUM
илиCOUNT
значенияNULL
не учитываются в расчете.
Работа с NaN
В PostgreSQL значение NaN
(Not a Number) используется для обозначения неопределенных или некорректных результатов вычислений, особенно в контексте числовых типов данных. Вот основные аспекты работы с NaN
:
1. Основные характеристики NaN
- Представление:
NaN
может храниться в столбцах типаnumeric
,real
илиdouble precision
. При этомNaN
считается неравным любому другому значению, включая самого себя. - Сравнение: В PostgreSQL все значения
NaN
считаются равными друг другу, но больше любых других чисел, что позволяет использовать их в индексах и сортировках.
2. Операции с NaN
-
Арифметические операции: Любая операция с
NaN
возвращаетNaN
. Например:select 'NaN' + 0.5; select 'NaN' * 0.5; select 'NaN' / 0.0;
-
Возведение в степень: Есть исключение для возведения
NaN
в нулевую степень, которое возвращает 1:SELECT POWER('NaN', 0); -- Результат будет 1
3. Запись NaN в SQL
При вставке значения NaN
в таблицу его нужно заключать в апострофы:
INSERT INTO table_name (column_name) VALUES ('NaN'::numeric);
4. Примеры использования
-
Создание таблицы:
CREATE TABLE example ( id SERIAL PRIMARY KEY, value NUMERIC ); INSERT INTO example (value) VALUES ('NaN'::numeric);
-
Выборка значений:
SELECT * FROM example WHERE value = 'NaN'::numeric; -- Найдет записи с NaN
-
Обработка значений: Чтобы избежать проблем с
NaN
, можно использовать функции для обработки:SELECT COALESCE(value, '0'::numeric) FROM example; -- Заменяет NaN на 0
Основные типы данных
PostgreSQL поддерживает широкий набор типов данных, которые можно условно разделить на несколько категорий. Вот основные типы данных в PostgreSQL:
1. Числовые типы
- smallint: 2-байтовое целое число, диапазон от -32,768 до +32,767.
- integer: 4-байтовое целое число, диапазон от -2,147,483,648 до +2,147,483,647.
- bigint: 8-байтовое целое число, диапазон от -9,223,372,036,854,775,808 до +9,223,372,036,854,775,807.
- decimal (p,s) / numeric (p,s): Числа с фиксированной точностью и масштабом. Максимальная точность до 131072 цифр.
- real: 4-байтовое число с плавающей запятой (float4).
- double precision: 8-байтовое число с плавающей запятой (float8).
- serial: Автоинкрементирующееся 4-байтовое целое число.
- bigserial: Автоинкрементирующееся 8-байтовое целое число.
2. Символьные типы
- char(n): Фиксированная длина строки (n символов).
- varchar(n): Переменная длина строки с ограничением (максимум n символов).
- text: Строка переменной длины без ограничений.
3. Логический тип
- boolean: Хранит значения TRUE, FALSE или NULL.
4. Дата и время
- date: Дата (год, месяц, день).
- time [ (p) ]: Время без часового пояса.
- timestamp [ (p) ]: Дата и время без часового пояса.
- timestamptz: Дата и время с часовым поясом.
- interval: Интервал времени.
5. Бинарные типы
- bytea: Двоичные данные переменной длины.
6. Геометрические типы
- point: Точка в двумерном пространстве.
- line: Прямая в двумерном пространстве.
- lseg: Отрезок в двумерном пространстве.
- polygon: Многоугольник.
- circle: Окружность.
7. JSON и XML
- json: Хранит данные в формате JSON.
- jsonb: Хранит данные в бинарном формате JSON для более эффективного хранения и поиска.
- xml: Хранит данные в формате XML.
8. UUID
- uuid: Универсальный уникальный идентификатор.
9. Массивы
PostgreSQL поддерживает массивы для любого типа данных.
10. Диапазоны
PostgreSQL предоставляет типы для представления диапазонов значений:
- Например,
int4range
,numrange
,tsrange
, и другие.
Эти типы данных позволяют эффективно хранить и обрабатывать разнообразные данные в PostgreSQL. Выбор правильного типа данных важен для обеспечения согласованности и производительности базы данных.
Пользовательские типы данных в PostgreSQL
PostgreSQL предоставляет возможность создания пользовательских типов данных.
Пользовательские типы данных могут быть созданы с помощью команд CREATE TYPE
и CREATE DOMAIN
.
Основные виды пользовательских типов
-
Составные типы (Composite Types): Составные типы позволяют объединять несколько полей разных типов в один. Например, можно создать тип, который будет содержать имя и номер телефона сотрудника:
CREATE TYPE employee_data AS ( employee_name VARCHAR, contact_no VARCHAR );
-
Доменные типы (Domain Types): Доменные типы представляют собой ограничения на существующие типы данных. Они позволяют добавлять дополнительные проверки, такие как
NOT NULL
илиCHECK
. Например:CREATE DOMAIN phone_number AS VARCHAR CHECK (VALUE ~ '^\+?[0-9]*$');
Это создаст новый тип, который будет принимать только строки, соответствующие определенному шаблону.
Обработка пользовательских типов
Пользовательские типы должны иметь функции ввода и вывода, которые определяют, как они будут выглядеть в строковом виде при вводе и выводе.
Приведение типов (CAST) в PostgreSQL
Приведение типов (casting) в PostgreSQL — это процесс преобразования значения из одного типа данных в другой. Это важно для обеспечения совместимости типов данных при выполнении операций и вызове функций в SQL-запросах. PostgreSQL предоставляет два основных способа приведения типов: функцию CAST()
и оператор ::
.
Синтаксис
-
Использование функции CAST:
CAST (выражение AS целевой_тип_данных);
Здесь
выражение
может быть константой, именем столбца или любым выражением, которое возвращает значение.целевой_тип_данных
— это тип данных, к которому нужно преобразовать значение. -
Использование оператора ::
выражение::целевой_тип_данных
Этот оператор является более лаконичным способом записи и выполняет ту же задачу, что и функция
CAST()
. Однако оператор::
специфичен для PostgreSQL и не является частью стандарта SQL.
Примеры приведения типов
-
Преобразование строки в число:
SELECT CAST('069' AS INTEGER) AS salary_int;
Преобразует строку
'069'
в целое число. -
Преобразование строки в дату:
SELECT CAST('2015-01-01' AS DATE) AS date_value;
Преобразует строковое представление даты в формат даты.
-
Преобразование числа в строку:
SELECT CAST(123 AS VARCHAR) AS string_value;
Преобразует целое число в строковое представление.
-
Использование оператора :: для приведения типов:
SELECT '3.14'::NUMERIC AS numeric_value; SELECT 42::TEXT AS text_value;
Обработка ошибок
Если данные невозможно преобразовать к указанному типу, PostgreSQL выдаст ошибку. Например, попытка преобразовать строку, содержащую текст, в число вызовет ошибку:
SELECT CAST('abc' AS INTEGER);
-- Error: invalid input syntax for type integer: "abc"
Основные случаи использования приведения типов
- Совместимость данных: Когда необходимо выполнять операции с данными разных типов (например, сложение чисел, хранящихся как строки).
- Форматирование данных: Для приведения вывода к нужному формату (например, отображение дат или чисел как строки).
- Сохранение целостности данных: Для обеспечения соответствия данных типам, определённым в таблицах базы данных.
Работа с датами
Есть 4 основных способа хранения значений времени в PostgreSQL:
data type | description | example | output |
---|---|---|---|
TIMESTAMP | date and time | TIMESTAMP '2023-04-10 10:39:37' |
2023-04-10T10:39:37 |
DATE | date (no time) | DATE '2023-04-10 10:39:37' |
2023-04-10 |
TIME | time (no day) | TIME '2023-04-10 10:39:37' |
10:39:37 |
INTERVAL | interval between two date/times | TIME '2023-04-10 10:39:37' |
1 day, 2:00:10 |
Пример использования TIMESTAMP
вместе с INTERVAL
:
CREATE TABLE contests(
contest_id SERIAL PRIMARY KEY,
contest_title TEXT UNIQUE NOT NULL,
contest_start TIMESTAMP NOT NULL,
contest_length INTERVAL
);
INSERT INTO contests(contest_title, contest_start, contest_length)
VALUES
('Contest 1', '2025-01-09 05:00', '1 day'),
('Contest 4', '2025-01-09 15:30', '01:30'),
('Contest 5', '2024-10-30 18:00', '14 days'),
('Contest 6', '2024-11-18 20:00', '1 day');
SELECT contest_start, contest_length
FROM game_battle.contest;
contest_start | contest_length |
---|---|
2025-01-09 05:00:00.000 | 1 day |
2025-01-09 15:30:00.000 | 01:30:00 |
2024-10-30 18:00:00.000 | 14 days |
2024-11-18 20:00:00.000 | 1 day |
SELECT contest_start, contest_start + contest_length AS contest_end
FROM contests;
contest_start | contest_end |
---|---|
2025-01-09 05:00:00.000 | 2025-01-10 05:00:00.000 |
2025-01-09 15:30:00.000 | 2025-01-09 17:00:00.000 |
2024-10-30 18:00:00.000 | 2024-11-13 18:00:00.000 |
2024-11-18 20:00:00.000 | 2024-11-19 20:00:00.000 |
SELECT INTERVAL '1 year -5 days 1 hour';
SELECT NOW();
SELECT CURRENT_DATE;
SELECT LOCALTIME;
SELECT DATE_TRUNC('month', DATE '2023-04-10');
SELECT DATE_TRUNC('day', TIMESTAMP '2023-04-10 10:39:37');
SELECT TO_CHAR(DATE '2023-04-10', 'YY');
- Дату сегодня можно найти так:
NOW()
(timestamp),CURRENT_DATE
(date),LOCALTIME
(текущее время) DATE_TRUNC(‘[interval]’, time_column)
- позволяет округлить до месяца, года, числа и т.д.TO_CHAR([date type], [pattern])
- позволяет форматировать дату в строку по шаблону
Подробнее про to_char и виды шаблонов
Геометрические типы
Учимся пользоваться документацией postgresql.
Операции с геометрическими типами: ru / en
Упражнения
1. На операции реляционной алгебры
Создайте и заполните указанные таблицы, после чего напишите запрос для каждого пункта.
Задание в файле relalg-insert.sql.
Ответы в файле relalg-requests.sql.
2. На SELECT-запросы
Задание в файле select-insert.sql.
Ответы в файле select-requests.sql.
3. Другое (NULL, NaN, даты)
Задание в файле other-insert.sql.
Ответы в файле other-requests.sql.