Базы данных | Задания для практического занятия 8
Создание запросов с использованием стандартных функций в PostgreSQL.
Вариант 1: Система Управления Библиотекой
Сценарий: Вы управляете базой данных для местной библиотеки. Вам нужно выполнить различные запросы, связанные с читателями, книгами и выдачами.
Схема Базы Данных:
-- Drop tables if they exist (optional)
-- DROP TABLE IF EXISTS loans;
-- DROP TABLE IF EXISTS books;
-- DROP TABLE IF EXISTS members;
-- 1. Create the 'members' table
CREATE TABLE members (
member_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE, -- For LOWER() and UNIQUE practice
join_date DATE NOT NULL,
membership_level VARCHAR(10) DEFAULT 'Bronze', -- For CASE or NULLIF
postal_code VARCHAR(10) -- Might have extra spaces, for TRIM()
);
-- 2. Create the 'books' table
CREATE TABLE books (
book_id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
author VARCHAR(100),
isbn VARCHAR(20) UNIQUE, -- May have hyphens/spaces, for REPLACE()
publication_year INTEGER, -- For EXTRACT() or CAST()
list_price NUMERIC(7, 2) -- For ROUND(), CEIL(), FLOOR(), ABS()
);
-- 3. Create the 'loans' table
CREATE TABLE loans (
loan_id SERIAL PRIMARY KEY,
book_id INTEGER REFERENCES books(book_id),
member_id INTEGER REFERENCES members(member_id),
loan_date DATE NOT NULL DEFAULT CURRENT_DATE,
due_date DATE NOT NULL,
return_date DATE -- NULL if not returned, for COALESCE(), AGE()
);
-- Sample Data Insertion --
INSERT INTO members (first_name, last_name, email, join_date, membership_level, postal_code) VALUES
('Arthur', 'Dent', 'a.dent@galaxy.net', '2021-03-15', 'Silver', ' SW1A0AA'),
('Ford', 'Prefect', 'ford.p@betelgeuse.com', '2021-03-15', 'Gold', 'BG5-XQ1 '),
('Zaphod', 'Beeblebrox', 'z.beeblebrox@president.gov', '2022-11-01', NULL, 'HHGTTG'), -- NULL level
('Trillian', 'Astra', 'trillian@heartofgold.spc', '2020-08-25', 'Gold', ' E1 6AN'),
('Marvin', 'Android', 'paranoid.android@sirius.cyb', '2023-01-10', 'Bronze', ' ROBOT01');
INSERT INTO books (title, author, isbn, publication_year, list_price) VALUES
('The Hitchhiker''s Guide', 'Douglas Adams', '0-345-39180-2', 1979, 15.99),
('Dirk Gently''s Holistic Detective Agency', 'Douglas Adams', ' 0-671-69464-4', 1987, 18.50), -- Leading space ISBN
('Good Omens', 'Terry Pratchett & Neil Gaiman', '0-575-04800-X ', 1990, 22.00), -- Trailing space ISBN
('Stardust', 'Neil Gaiman', '0-380-97728-1', 1999, 14.75),
('Hyperion', 'Dan Simmons', '978-0553283686', 1989, 19.95);
INSERT INTO loans (book_id, member_id, loan_date, due_date, return_date) VALUES
(1, 1, '2023-10-01', '2023-10-15', '2023-10-14'),
(2, 2, '2023-10-05', '2023-10-26', NULL), -- Overdue
(3, 1, '2023-10-10', '2023-10-31', NULL), -- Not yet due (assume today is Oct 26th)
(4, 3, '2023-09-15', '2023-10-06', '2023-10-10'), -- Returned late
(5, 4, '2023-10-20', '2023-11-10', NULL),
(1, 5, '2023-08-01', '2023-08-22', NULL); -- Very overdue
Задачи для Варианта 1:
- Полные Имена Читателей: Выберите
member_id
и сгенерируйте строку с полным именем для каждого читателя, объединив ихfirst_name
иlast_name
, разделенные пробелом. Назовите этот столбецfull_name
. - Очищенные ISBN: Отобразите
title
иisbn
для всех книг. Очиститеisbn
, удалив как начальные/конечные пробелы, так и любые дефисы (‘-‘). Назовите очищенный столбецcleaned_isbn
. (Подсказка: Вам могут понадобитьсяTRIM
иREPLACE
). - Продолжительность Членства: Вычислите, как долго каждый читатель является частью библиотеки по состоянию на
CURRENT_DATE
. Отобразитеfirst_name
читателя,join_date
и вычисленную продолжительность, используяAGE()
. Назовите столбец продолжительностиmembership_duration
. - Статус Выдачи: Для всех выдач отобразите
loan_id
,due_date
и вычисленныйstatus
. Статус должен быть ‘Overdue’, еслиreturn_date
имеет значение NULL Иdue_date
раньшеCURRENT_DATE
. Статус должен быть ‘Returned’, еслиreturn_date
не NULL. В противном случае статус должен быть ‘On Loan’. (Подсказка: ИспользуйтеCASE
и проверьте наNULL
). - Категории Цен Книг: Покажите
title
,list_price
иprice_category
для каждой книги. Разделите на категории как ‘Budget’, если цена < 15,00 долларов США, ‘Standard’, если цена находится в диапазоне от 15,00 до 19,99 долларов США (включительно), и ‘Premium’, если 20,00 долларов США или больше. - Нижний Регистр Email Читателя: Отобразите
first_name
,last_name
иemail
адрес для всех читателей, убедившись, что адрес электронной почты полностью в нижнем регистре. Назовите столбец email в нижнем регистреlower_email
. - Сокращение Названия Книги: Покажите
book_id
и первые 15 символовtitle
каждой книги. Если название длиннее 15 символов, добавьте ‘…’. Назовите этоshort_title
. (Подсказка: ИспользуйтеSUBSTRING
и, возможно,LENGTH
иCONCAT
/||
). - Период Выдачи: Вычислите количество дней между
loan_date
иdue_date
для каждой выдачи. Отобразитеloan_id
и вычисленное количество дней какloan_period_days
. (Подсказка: Вычитание дат дает целое число дней). - Цена Округлена Вверх: Отобразите
title
иlist_price
для каждой книги вместе с ценой, округленной ВВЕРХ до ближайшей целой суммы в долларах. Назовите этоprice_ceil
. - Отображение Уровня Членства: Покажите
member_id
иfirst_name
. Также отобразитеmembership_level
. Еслиmembership_level
имеет значение NULL, отобразите ‘Standard’ вместо этого. Назовите этот столбецeffective_level
. (Подсказка: ИспользуйтеCOALESCE
). - Извлечение Квартала Присоединения: Отобразите
first_name
иjoin_date
для каждого читателя. Также извлеките календарный квартал (1, 2, 3 или 4) из ихjoin_date
. Назовите этоjoin_quarter
. (Подсказка: ИспользуйтеEXTRACT(QUARTER FROM ...)
). - Очистка Почтового Индекса: Отобразите
member_id
иpostal_code
для каждого читателя, удалив любые начальные или конечные пробелы. Назовите очищенный столбецtrimmed_postal_code
. - Абсолютная Разница Цен: Вычислите абсолютную разницу между
list_price
каждой книги и целевой ценой в 18,00 долларов США. Отобразитеtitle
,list_price
и вычисленнуюabsolute_difference
. - Проверка Числового ISBN (Концептуально): Определите книги, у которых
cleaned_isbn
(из логики Задачи 2) содержит нечисловые символы (исключая потенциальный ‘X’ в конце, обычный для ISBN-10). Это более сложно; для этого задания просто проверьте, приводит лиREPLACE(TRIM(isbn), '-', '')
к NULL при попытке преобразования к типу NUMERIC (используйтеNULLIF
в сочетании с проверкой или более продвинутой техникой, если она известна, в противном случае опишите логику). Для более простой версии: верните NULL с помощьюNULLIF
, еслиpublication_year
равен ровно1990
. Назовите этоnull_if_1990_pub
. - Заполнение ID Читателя: Отобразите
member_id
для всех читателей, отформатированный как 5-значную строку с ведущими нулями (например, 1 становится ‘00001’). Назовите этоformatted_member_id
. (Подсказка: ИспользуйтеLPAD
после приведения типа).
Вариант 2: Запись на курсы в университете
Описание: Вы управляете базой данных для записи на курсы в университете, отслеживая студентов, курсы и их оценки.
Схема базы данных:
-- Drop tables if they exist (optional)
-- Удалить таблицы, если они существуют (необязательно)
-- DROP TABLE IF EXISTS enrollments;
-- DROP TABLE IF EXISTS courses;
-- DROP TABLE IF EXISTS students;
-- 1. Create the 'students' table
-- 1. Создать таблицу 'students' (студенты)
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
middle_name VARCHAR(50), -- Allows NULLs, for COALESCE
-- Допускает NULL, для COALESCE
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL, -- For LOWER(), UNIQUE
-- Для LOWER(), UNIQUE
date_of_birth DATE, -- For AGE(), EXTRACT()
-- Для AGE(), EXTRACT()
major VARCHAR(50) -- For CASE, NULLIF
-- Для CASE, NULLIF
);
-- 2. Create the 'courses' table
-- 2. Создать таблицу 'courses' (курсы)
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
course_code VARCHAR(15) UNIQUE NOT NULL, -- e.g., ' CS 101 ', for TRIM()
-- например, ' CS 101 ', для TRIM()
course_name VARCHAR(100) NOT NULL, -- For UPPER(), SUBSTRING()
-- Для UPPER(), SUBSTRING()
credits NUMERIC(3, 1), -- e.g., 3.0, 1.5. For ROUND(), ABS()
-- например, 3.0, 1.5. Для ROUND(), ABS()
department VARCHAR(50) -- For general queries
-- Для общих запросов
);
-- 3. Create the 'enrollments' table
-- 3. Создать таблицу 'enrollments' (записи на курсы)
CREATE TABLE enrollments (
enrollment_id SERIAL PRIMARY KEY,
student_id INTEGER REFERENCES students(student_id),
course_id INTEGER REFERENCES courses(course_id),
enrollment_date DATE DEFAULT CURRENT_DATE, -- For EXTRACT(), INTERVAL
-- Для EXTRACT(), INTERVAL
grade NUMERIC(4, 1) -- e.g. 85.5, 92.0. Allows NULL if not graded. For CEIL(), FLOOR(), CASE
-- например, 85.5, 92.0. Допускает NULL, если оценка не выставлена. Для CEIL(), FLOOR(), CASE
);
-- Sample Data Insertion --
-- Вставка образцовых данных --
INSERT INTO students (first_name, middle_name, last_name, email, date_of_birth, major) VALUES
('Alice', 'Marie', 'Wonder', 'alice.wonder@uni.edu', '2003-04-10', 'Literature'),
('Bob', NULL, 'Builder', 'bob.the.builder@uni.edu', '2002-08-20', 'Engineering'),
('Charlie', 'Chaplin', 'Jr', 'charlie.jr@uni.edu', '2004-01-05', NULL), -- NULL Major
-- NULL специальность
('Dorothy', 'Gale', 'Oz', 'dorothy.oz@uni.edu', '2003-11-11', 'Meteorology'),
('Eve', 'Ada', 'Lovelace', 'eve.lovelace@uni.edu', '2002-12-15', 'Computer Science');
INSERT INTO courses (course_code, course_name, credits, department) VALUES
(' CS 101 ', 'Introduction to Programming', 3.0, 'Computer Science'), -- Spaces in code
-- Пробелы в коде
('LIT 205', 'Modernist Poetry', 3.0, 'Literature'),
(' ENG 310', 'Structural Analysis', 4.0, 'Engineering'), -- Leading space
-- Пробел в начале
('MATH 150 ', 'Calculus I', 4.5, 'Mathematics'), -- Trailing space
-- Пробел в конце
('CS 336', 'Database Systems', 3.0, 'Computer Science');
INSERT INTO enrollments (student_id, course_id, enrollment_date, grade) VALUES
(1, 2, '2023-09-05', 88.5),
(2, 3, '2023-09-05', 92.0),
(1, 4, '2023-09-06', 75.0),
(3, 1, '2023-09-07', NULL), -- Not graded yet
-- Еще не выставлена оценка
(4, 4, '2023-09-06', 65.5),
(5, 1, '2023-09-07', 95.0),
(5, 5, '2023-09-08', NULL); -- Not graded yet
-- Еще не выставлена оценка
Задачи для Варианта 2:
- Инициалы студента и полное имя: Отобразите
student_id
. Создайтеfull_name
(Имя Фамилия). Создайте строкуinitials
, используя первую буквуfirst_name
и первую буквуlast_name
в верхнем регистре (например, ‘AW’). Еслиmiddle_name
существует, отобразите его, используяCOALESCE
(покажите ‘N/A’, если NULL), в противном случае пропустите отображениеmiddle_name
для этой задачи. - Очищенные коды курсов: Покажите
course_name
иcourse_code
после удаления любых начальных или конечных пробелов. Присвойте очищенному коду псевдонимclean_code
. - Расчет возраста студента: Рассчитайте текущий возраст каждого студента на основе их
date_of_birth
наCURRENT_DATE
. Отобразитеfirst_name
,last_name
,date_of_birth
и рассчитанныйage
. - Статус оценки за курс: Отобразите
enrollment_id
,student_id
,course_id
и рассчитанныйgrade_status
. Статус должен быть ‘Passed’, еслиgrade
>= 60, ‘Failed’, еслиgrade
< 60, и ‘Pending’, еслиgrade
равен NULL. - Категории кредитов курса: Отобразите
course_name
,credits
иcredit_category
. Классифицируйте как ‘Low’, если credits < 3.0, ‘Standard’, если credits равны 3.0 или 3.5, и ‘High’, если credits > 3.5. - Стандартизированные электронные письма студентов: Покажите
student_id
,first_name
иemail
, убедившись, чтоemail
полностью в нижнем регистре. Присвойте этому псевдонимstandard_email
. - Аббревиатура названия курса: Отобразите
course_id
и первые 20 символовcourse_name
. Присвойте этому псевдонимshort_course_name
. - Семестр зачисления: Отобразите
enrollment_id
иenrollment_date
. Определите семестр зачисления на основе месяца: Месяц 1-5 = ‘Spring’, Месяц 6-8 = ‘Summer’, Месяц 9-12 = ‘Fall’. Присвойте этому псевдонимenrollment_semester
. (Подсказка: используйтеEXTRACT
иCASE
). - Оценка, округленная в меньшую сторону: Отобразите
enrollment_id
иgrade
. Также покажитеgrade
, округленную ВНИЗ до ближайшего целого числа. Присвойте этому псевдонимgrade_floor
. Обработайте случаи, когда оценка может быть NULL (она, вероятно, должна оставаться NULL). - Отображение специальности: Отобразите
student_id
иfirst_name
. ИспользуйтеCOALESCE
, чтобы показатьmajor
студента; еслиmajor
равен NULL, отобразите ‘Undeclared’. Присвойте этому псевдонимdeclared_major
. - Лет с года рождения: Извлеките год рождения каждого студента. Рассчитайте количество полных лет, прошедших между годом их рождения и текущим годом. Отобразите
first_name
,date_of_birth
иyears_passed
. (Подсказка:EXTRACT(YEAR FROM CURRENT_DATE) - EXTRACT(YEAR FROM date_of_birth)
). - Абсолютная разница оценки от среднего: Рассчитайте абсолютную разницу между оценкой каждого студента по ‘Calculus I’ (Course ID 4) и средней оценкой по этому курсу (предположим, что среднее значение составляет 70.0 для этой задачи). Отобразите
student_id
,grade
иabs_diff_from_avg
. Включите только записи для Course ID 4 с ненулевыми оценками. - Поиск нулевых специальностей: Используйте
NULLIF
, чтобы вернуть NULL, если специальность студента - ‘Literature’. В противном случае верните специальность. Отобразитеstudent_id
,first_name
,major
и результат какnull_if_literature
. - Проверка четности идентификатора студента: Определите, является ли
student_id
нечетным или четным. Отобразитеstudent_id
и ‘Even’ или ‘Odd’ какid_parity
. (Подсказка: используйтеMOD
или%
). - Заполнение кода курса: Отобразите
course_id
иclean_code
(из логики задачи 2). Создайтеpadded_code
, заполнивclean_code
справа пробелами до общей длины 10 символов. (Подсказка: используйтеRPAD
).
Вариант 3: Управление Проектами и Задачами
Сценарий: Вы управляете базой данных для отслеживания проектов, задач, назначенных сотрудникам, и их прогресса.
Схема Базы Данных:
-- Удалить таблицы, если они существуют (опционально)
-- DROP TABLE IF EXISTS tasks;
-- DROP TABLE IF EXISTS projects;
-- DROP TABLE IF EXISTS employees;
-- 1. Создать таблицу 'employees' (сотрудники)
CREATE TABLE employees (
emp_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
emp_code VARCHAR(10) UNIQUE, -- Например, 'EMP001', для SUBSTRING, CAST
hire_date DATE NOT NULL, -- Для AGE(), EXTRACT()
hourly_rate NUMERIC(6, 2), -- Для ROUND(), числовых операций
department VARCHAR(50) -- Для общих запросов, NULLIF
);
-- 2. Создать таблицу 'projects' (проекты)
CREATE TABLE projects (
project_id SERIAL PRIMARY KEY,
project_name VARCHAR(100) NOT NULL UNIQUE, -- Для UPPER(), LENGTH()
client_name VARCHAR(100),
start_date DATE NOT NULL,
deadline_date DATE, -- Допускает NULL, для COALESCE, CASE
budget NUMERIC(12, 2) -- Для ABS(), CEIL()
);
-- 3. Создать таблицу 'tasks' (задачи)
CREATE TABLE tasks (
task_id SERIAL PRIMARY KEY,
project_id INTEGER REFERENCES projects(project_id),
assigned_to_emp_id INTEGER REFERENCES employees(emp_id), -- Допускает NULL
task_name VARCHAR(255) NOT NULL,
estimated_hours NUMERIC(5, 1), -- Например, 8.0, 2.5. Для ROUND()
creation_date TIMESTAMP DEFAULT NOW(), -- Для функций даты/времени
completion_date DATE -- NULL, если не завершена. Для CASE, AGE()
);
-- Вставка Примерных Данных --
INSERT INTO employees (first_name, last_name, emp_code, hire_date, hourly_rate, department) VALUES
('Peter', 'Gibbons', 'EMP001', '2019-02-15', 35.00, 'Software'),
('Michael', 'Bolton', 'EMP002', '2018-07-01', 40.50, NULL), -- NULL Dept
('Samir', 'Nagheenanajar', 'EMP003', '2019-02-15', 38.75, 'Software'),
('Joanna', 'Planter', 'EMP004', '2020-11-20', 45.00, 'Management'),
('Bill', 'Lumbergh', 'EMP005', '2015-03-10', 75.00, 'Management');
INSERT INTO projects (project_name, client_name, start_date, deadline_date, budget) VALUES
('TPS Reports Automation', 'Initech', '2023-01-10', '2023-06-30', 50000.00),
('Website Redesign', 'Globex Corp', '2023-03-01', '2023-09-15', 75000.50),
('New Feature X', 'Initech', '2023-05-15', NULL, 30000.00), -- NULL Deadline
('Server Migration', 'Stark Industries', '2023-08-01', '2023-12-20', 120000.00);
INSERT INTO tasks (project_id, assigned_to_emp_id, task_name, estimated_hours, creation_date, completion_date) VALUES
(1, 1, 'Analyze current TPS report process', 8.0, '2023-01-12 10:00:00', '2023-01-20'),
(1, 3, 'Develop script for data extraction', 24.5, '2023-02-01 11:30:00', '2023-03-15'),
(2, 4, 'Create wireframes for new website', 16.0, '2023-03-05 09:00:00', NULL), -- Не завершена
(2, NULL, 'Content population', 40.0, '2023-06-01 14:00:00', NULL), -- Не назначена
(3, 1, 'Define requirements for Feature X', 4.0, '2023-05-16 15:00:00', '2023-05-25'),
(4, 5, 'Plan migration strategy', 12.0, '2023-08-02 16:20:00', NULL),
(1, 5, 'Oversee TPS report testing', 6.5, '2023-04-01 08:00:00', '2023-06-10');
Задачи для Варианта 3:
- Полное Имя и Код Сотрудника: Отобразите
emp_id
. Объединитеfirst_name
иlast_name
вfull_name
. Также отобразитеemp_code
. - Название Проекта в Верхнем Регистре: Покажите
project_id
иproject_name
полностью в верхнем регистре, под псевдонимомupper_project_name
. - Стаж Сотрудника: Вычислите продолжительность работы каждого сотрудника в компании на
CURRENT_DATE
. Отобразитеemp_code
,hire_date
и вычисленныйtenure
, используяAGE()
. - Определение Статуса Задачи: Отобразите
task_id
,task_name
,deadline_date
(из соответствующего проекта - требуется JOIN, предположим, что вы можете посмотреть срок проекта вручную или просто использоватьcompletion_date
задачи). Предоставьтеstatus
: ‘Completed’, еслиcompletion_date
NOT NULL, ‘Overdue’, еслиcompletion_date
IS NULL Иdeadline_date
проекта раньшеCURRENT_DATE
(если срок существует), ‘In Progress’ в противном случае. (Упрощено для задания: Используйте толькоcompletion_date
. ‘Completed’, если NOT NULL, ‘Pending’, если NULL). - Категории Бюджета Проекта: Отобразите
project_name
,budget
. Категоризируйте проекты на основеbudget
: ‘Small’, если budget < 40000, ‘Medium’, если budget находится между 40000 и 80000 (включительно), ‘Large’, если budget > 80000. Используйте псевдонимbudget_category
. - Оценка Времени в Часах Округлена: Покажите
task_id
,task_name
иestimated_hours
. Также отобразитеestimated_hours
, округленное до ближайшего целого числа. Используйте псевдонимrounded_hours
. - Числовая Часть Кода Сотрудника: Извлеките числовую часть из
emp_code
(предполагая формат ‘EMP’, за которым следуют цифры). Отобразитеemp_id
,emp_code
и извлеченное число какemp_number
. (Подсказка: используйтеSUBSTRING
и, возможно,CAST
). - Дней До Срока Окончания Проекта: Для проектов, у которых есть
deadline_date
, вычислите количество дней, оставшихся отCURRENT_DATE
до крайнего срока. Отобразитеproject_name
,deadline_date
иdays_remaining
. Обработайте случаи, когда срок может быть в прошлом (результат будет отрицательным). - Бюджет Округлен Вверх: Отобразите
project_name
иbudget
. Также покажитеbudget
, округленный ВВЕРХ до ближайшей 1000 долларов. Используйте псевдонимbudget_ceil_k
. (Подсказка: используйтеCEIL
осторожно, возможно, разделите, округлите вверх, затем умножьте, или используйтеROUND
с соответствующей отрицательной точностью, если цель - ближайшая 1000, используйтеCEIL
, если строго ВВЕРХ). Будем придерживатьсяCEIL
для концепции обучения: отобразитеCEIL(budget)
какbudget_ceil_dollar
. - Отображение Назначенного Сотрудника: Отобразите
task_id
иtask_name
. ИспользуйтеCOALESCE
, чтобы показатьassigned_to_emp_id
. Если он NULL, отобразите 0 вместо этого. Используйте псевдонимassigned_emp
. - Месяц и Год Начала Проекта: Извлеките месяц и год из
start_date
для каждого проекта. Отобразитеproject_name
,start_date
,start_month
иstart_year
. - Абсолютное Отклонение Бюджета: Вычислите абсолютную разницу между
budget
каждого проекта и стандартным бюджетом в размере 60 000 долларов. Отобразитеproject_name
,budget
иabs_budget_deviation
. - Час Создания Задачи: Извлеките час (0-23) из отметки времени
creation_date
для каждой задачи. Отобразитеtask_id
,creation_date
иcreation_hour
. - Найти Сотрудников Не-Программистов: Используйте
NULLIF
для возврата NULL, если отдел сотрудника - ‘Software’. В противном случае верните отдел. Отобразитеemp_id
,first_name
,department
и результат какnull_if_software
. - Форматирование Почасовой Ставки: Отобразите
emp_id
,first_name
иhourly_rate
. Создайте новый строковый столбец с именемformatted_rate
, который показываетhourly_rate
с префиксом знака доллара (‘$’). (Подсказка: Используйте оператор конкатенации||
и приведитеhourly_rate
кVARCHAR
).
Вариант 4: Система заказов для электронной коммерции
Сценарий: Вы управляете базой данных для интернет-магазина. Вам нужно запрашивать информацию о клиентах, сведения о товарах, заказах и элементах в этих заказах.
Схема базы данных:
-- Удалить таблицы, если они существуют (необязательно)
-- DROP TABLE IF EXISTS order_items;
-- DROP TABLE IF EXISTS orders;
-- DROP TABLE IF EXISTS products;
-- DROP TABLE IF EXISTS customers;
-- 1. Создать таблицу 'customers'
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL, -- Для LOWER(), UNIQUE
registration_date DATE NOT NULL DEFAULT CURRENT_DATE, -- Для AGE(), EXTRACT()
address_line1 VARCHAR(255),
city VARCHAR(100),
postal_code VARCHAR(20) -- Может содержать пробелы, для TRIM()
);
-- 2. Создать таблицу 'products' (отличается от структуры в учебнике)
CREATE TABLE products (
product_sku VARCHAR(50) PRIMARY KEY, -- Например, 'ELEC-LAP-1001', 'BOOK-FIC-205A'
product_name VARCHAR(150) NOT NULL, -- Для SUBSTRING(), UPPER()
description TEXT, -- Для LENGTH() (на фрагменте)
unit_price NUMERIC(10, 2) NOT NULL CHECK (unit_price > 0), -- Для ROUND(), CEIL(), FLOOR(), ABS()
category VARCHAR(50), -- Для CASE, NULLIF
stock_added_date DATE -- Для вычисления INTERVAL
);
-- 3. Создать таблицу 'orders'
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(customer_id),
order_date TIMESTAMP NOT NULL DEFAULT NOW(), -- Для EXTRACT(), AGE()
shipping_address VARCHAR(500), -- Может отличаться от адреса клиента, возможно NULL
order_status VARCHAR(20) DEFAULT 'Pending', -- Например, 'Pending', 'Shipped', 'Delivered', 'Cancelled'
-- total_amount NUMERIC(12, 2) -- Обычно вычисляется, но может храниться
discount_code VARCHAR(15) NULL -- Для COALESCE
);
-- 4. Создать таблицу 'order_items' (связывает заказы и товары)
CREATE TABLE order_items (
item_id SERIAL PRIMARY KEY,
order_id INTEGER NOT NULL REFERENCES orders(order_id),
product_sku VARCHAR(50) NOT NULL REFERENCES products(product_sku),
quantity INTEGER NOT NULL CHECK (quantity > 0),
price_per_unit NUMERIC(10, 2) NOT NULL -- Цена на момент заказа
);
-- Вставка примерных данных --
INSERT INTO customers (first_name, last_name, email, registration_date, postal_code) VALUES
('Jane', 'Doe', 'jane.d@email.com', '2022-01-15', ' 12345 '),
('John', 'Smith', 'J.Smith@email.com', '2021-11-30', '98765'),
('Peter', 'Jones', 'peterjones@email.com', '2023-05-20', ' SW1A 0AA'),
('Mary', 'Brown', 'mary.b@email.com', '2022-01-15', NULL); -- NULL postal code
INSERT INTO products (product_sku, product_name, description, unit_price, category, stock_added_date) VALUES
('ELEC-LAP-1001', 'UltraBook X1', 'A thin and light laptop.', 1299.99, 'Electronics', '2023-01-10'),
('BOOK-FIC-205A', 'The Forgotten Realm', 'A fantasy novel.', 19.95, 'Books', '2023-02-15'),
('HOME-KIT-050', 'Smart Coffee Maker', 'Brews coffee remotely.', 89.50, 'Home Goods', '2023-03-01'),
('ELEC-CAM-300', 'Action Camera Pro', NULL, 249.00, 'Electronics', '2023-01-10'), -- NULL description
('BOOK-NF-110B', 'History of Computing', 'Covers major milestones.', 35.00, 'Books', '2022-12-01');
INSERT INTO orders (customer_id, order_date, order_status, discount_code) VALUES
(1, '2023-10-01 10:30:00', 'Shipped', 'FALL10'),
(2, '2023-10-15 14:00:00', 'Pending', NULL),
(1, '2023-10-20 09:00:00', 'Pending', NULL),
(3, '2023-08-10 11:00:00', 'Delivered', NULL),
(4, '2023-10-25 16:00:00', 'Pending', 'NEWCUST5');
INSERT INTO order_items (order_id, product_sku, quantity, price_per_unit) VALUES
(1, 'ELEC-LAP-1001', 1, 1299.99),
(1, 'HOME-KIT-050', 1, 85.00), -- Цена немного отличается на момент заказа
(2, 'BOOK-FIC-205A', 2, 19.95),
(3, 'HOME-KIT-050', 1, 89.50),
(4, 'BOOK-NF-110B', 1, 35.00),
(5, 'ELEC-CAM-300', 1, 249.00);
Задачи для варианта 4:
- Полное имя клиента: Выбрать
customer_id
и отобразить полное имя клиента, объединивfirst_name
иlast_name
с пробелом между ними. Дать результату псевдонимfull_name
. - Стандартизированные адреса электронной почты: Отобразить
customer_id
иemail
для всех клиентов, убедившись, чтоemail
полностью в нижнем регистре. Дать псевдонимstandard_email
. - Продолжительность членства клиента: Вычислить, как долго зарегистрирован каждый клиент (с
registration_date
) по состоянию наCURRENT_DATE
. Отобразитьcustomer_id
,registration_date
и продолжительность, используяAGE()
, с псевдонимомmembership_duration
. - Очищенные почтовые индексы: Отобразить
customer_id
иpostal_code
. Еслиpostal_code
не NULL, отобразить его после удаления любых начальных или конечных пробелов; в противном случае отобразить ‘N/A’. Дать этому псевдонимcleaned_postal_code
. (Подсказка: используйтеTRIM
иCOALESCE
). - Анализ артикула товара: Для каждого товара извлечь часть категории (до первого ‘-‘) и часть основного кода (между первым и вторым ‘-‘). Отобразить
product_sku
, извлеченнуюsku_category
иsku_core
. (Подсказка: используйтеSUBSTRING
и, возможно,POSITION
или фиксированную длину, если шаблон является согласованным). Упрощено для учебника: Предположим, что первая часть состоит из 4 символов, вторая - из 3. ИзвлекитеSUBSTRING(product_sku FROM 1 FOR 4)
какsku_category_prefix
иSUBSTRING(product_sku FROM 6 FOR 3)
какsku_type_prefix
. - Ценовые категории товаров: Отобразить
product_name
,unit_price
и вычисленныйprice_tier
. Уровень должен быть ‘Budget’, если цена < 50 долларов США, ‘Mid-Range’, если цена от 50 до 250 долларов США (включительно), и ‘Premium’, если цена > 250 долларов США. Используйте операторCASE
. - Общая стоимость позиции заказа: Для каждой позиции в
order_items
вычислить общую стоимость (quantity * price_per_unit
). Отобразитьitem_id
,order_id
,product_sku
и вычисленныйitem_total
. - Дней с момента заказа: Для каждого заказа вычислить количество полных дней, прошедших с
order_date
(для простоты игнорировать часть времени). Отобразитьorder_id
,order_date
иdays_passed
. (Подсказка:CURRENT_DATE - CAST(order_date AS DATE)
). - Округленная цена за единицу: Отобразить
product_name
иunit_price
, а такжеunit_price
, округленную до ближайшего целого доллара. Дать этому псевдонимrounded_price
. - Минимальная стоимость доставки: Отобразить
product_name
иunit_price
. Вычислить гипотетическую минимальную стоимость доставки, округливunit_price
ВВЕРХ до ближайшего доллара (CEIL
). Дать этому псевдонимmin_ship_charge_base
. - Отображение статуса заказа: Отобразить
order_id
иorder_status
. Создать столбецis_processing
, который показываетTRUE
, еслиorder_status
имеет значение ‘Pending’, иFALSE
в противном случае. (Подсказка: используйтеCASE
или логическое выражение). - Час размещения заказа: Извлечь час (0-23) из
order_date
для каждого заказа. Отобразитьorder_id
,order_date
иorder_hour
. - Абсолютная разница в цене от 100 долларов США: Для каждого товара вычислить абсолютную разницу между его
unit_price
и 100 долларами США. Отобразитьproduct_name
,unit_price
иabs_diff_from_100
. - Отформатированная строка цены товара: Отобразить
product_name
иunit_price
. Создать строковое представление цены с префиксом ‘$’. Дать этому псевдонимformatted_price
. (например, ‘$1299.99’). Используйте'$' || unit_price::VARCHAR
. - Заполненный нулями ID заказа: Отобразить
order_id
в формате 10-значной строки с ведущими нулями (например, 1 становится ‘0000000001’). Дать этому псевдонимformatted_order_id
. ИспользуйтеLPAD
.
Вариант 5: Система управления мероприятиями
Сценарий: Вы управляете базой данных компании по организации мероприятий, отслеживая мероприятия, места проведения, регистрации участников и платежи.
Схема базы данных:
-- Удалить таблицы, если они существуют (необязательно)
-- DROP TABLE IF EXISTS registrations;
-- DROP TABLE IF EXISTS attendees;
-- DROP TABLE IF EXISTS events;
-- DROP TABLE IF EXISTS venues;
-- 1. Создать таблицу 'venues'
CREATE TABLE venues (
venue_id SERIAL PRIMARY KEY,
venue_name VARCHAR(100) NOT NULL UNIQUE, -- Для UPPER(), LENGTH()
address VARCHAR(255),
city VARCHAR(100),
capacity INTEGER CHECK (capacity > 0), -- Для MOD(), числовых операций
booking_cost NUMERIC(8, 2), -- Для ROUND(), CEIL(), ABS()
contact_phone VARCHAR(20) -- Например, ' 123-456-7890 ', для TRIM(), REPLACE()
);
-- 2. Создать таблицу 'events'
CREATE TABLE events (
event_id SERIAL PRIMARY KEY,
event_name VARCHAR(150) NOT NULL, -- Для SUBSTRING()
venue_id INTEGER REFERENCES venues(venue_id),
event_type VARCHAR(50), -- Например, 'Conference', 'Workshop', 'Webinar', 'Gala'
start_datetime TIMESTAMP NOT NULL, -- Для EXTRACT(), AGE(), INTERVAL
end_datetime TIMESTAMP, -- Может быть NULL (например, однодневное мероприятие), проверить продолжительность начала/окончания
base_ticket_price NUMERIC(7, 2) DEFAULT 0.00 -- Для CASE, NULLIF
);
-- 3. Создать таблицу 'attendees'
CREATE TABLE attendees (
attendee_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL, -- Для LOWER()
signup_date DATE DEFAULT CURRENT_DATE, -- Для AGE()
company_name VARCHAR(100) -- Допускает NULL, для COALESCE
);
-- 4. Создать таблицу 'registrations'
CREATE TABLE registrations (
registration_id SERIAL PRIMARY KEY,
event_id INTEGER NOT NULL REFERENCES events(event_id),
attendee_id INTEGER NOT NULL REFERENCES attendees(attendee_id),
registration_time TIMESTAMP DEFAULT NOW(), -- Для EXTRACT(), AGE()
ticket_type VARCHAR(20) DEFAULT 'Standard', -- Например, 'Standard', 'VIP', 'EarlyBird'
final_price NUMERIC(7, 2), -- Оплаченная цена, может отличаться от базовой цены
payment_status VARCHAR(15) -- Например, 'Paid', 'Pending', 'Refunded', NULL
);
-- Пример вставки данных --
INSERT INTO venues (venue_name, capacity, booking_cost, contact_phone) VALUES
('Grand Hall', 500, 5000.00, ' 111-222-3333 '),
('Convention Center East Wing', 1500, 12000.50, '444-555-6666'),
('Cozy Corner Room', 50, 800.75, NULL), -- NULL phone
('Online Platform', 10000, 200.00, ' N/A ');
INSERT INTO events (event_name, venue_id, event_type, start_datetime, end_datetime, base_ticket_price) VALUES
('Annual Tech Conference 2024', 2, 'Conference', '2024-09-10 09:00:00', '2024-09-12 17:00:00', 499.00),
('Data Science Workshop', 1, 'Workshop', '2024-07-15 10:00:00', '2024-07-15 16:30:00', 150.00),
('Introduction to SQL Webinar', 4, 'Webinar', '2024-05-20 14:00:00', NULL, 0.00), -- Бесплатное мероприятие, NULL время окончания
('Charity Gala Dinner', 1, 'Gala', '2024-11-01 19:00:00', '2024-11-01 23:00:00', 250.50);
INSERT INTO attendees (first_name, last_name, email, company_name) VALUES
('Alice', 'Wonder', 'alice.w@example.com', 'Curious Inc.'),
('Bob', 'Marley', 'bob.m@example.com', NULL), -- NULL company
('Charlie', 'Day', 'charlie.d@example.com', 'Paddy''s Pub'),
('Diana', 'Prince', 'diana.p@example.com', 'Themyscira Exports');
INSERT INTO registrations (event_id, attendee_id, registration_time, ticket_type, final_price, payment_status) VALUES
(1, 1, '2024-03-15 10:00:00', 'EarlyBird', 399.00, 'Paid'),
(1, 2, '2024-04-01 11:30:00', 'Standard', 499.00, 'Paid'),
(2, 3, '2024-06-10 16:00:00', 'Standard', 150.00, 'Pending'),
(3, 1, '2024-05-01 09:00:00', 'Standard', 0.00, 'Paid'), -- Бесплатное мероприятие
(4, 4, '2024-09-01 14:20:00', 'VIP', 350.00, 'Paid'),
(2, 4, '2024-07-01 13:00:00', 'Standard', 150.00, NULL); -- NULL статус платежа
Задачи для варианта 5:
- Полное имя участника: Выбрать
attendee_id
и отобразить полное имя участника, объединивfirst_name
иlast_name
с пробелом. Задать псевдоним результату какfull_name
. - Очищенный телефон площадки: Отобразить
venue_name
иcontact_phone
. Показатьcontact_phone
после удаления всех пробелов и дефисов. Если телефон NULL или ‘ N/A ‘, отобразить ‘Not Available’. Задать псевдоним этому какcleaned_phone
. (Подсказка: ИспользуйтеREPLACE
,TRIM
,COALESCE
). - Продолжительность мероприятия: Вычислить продолжительность каждого мероприятия (
end_datetime
-start_datetime
). Еслиend_datetime
имеет значение NULL, отобразить NULL. Отобразитьevent_name
,start_datetime
,end_datetime
и вычисленнуюduration
(как INTERVAL). - Время с момента регистрации: Для каждой регистрации вычислить, сколько времени прошло с момента ее регистрации (
registration_time
) относительноNOW()
. Отобразитьregistration_id
,registration_time
и продолжительность, используяAGE()
, с псевдонимомregistration_age
. - Категория цены мероприятия: Отобразить
event_name
иbase_ticket_price
. Создатьprice_category
, используяCASE
: ‘Free’, если цена равна 0, ‘Affordable’, если цена > 0 и <= 100, ‘Standard’, если цена > 100 и <= 300, ‘Premium’, если цена > 300. - Стандартизированные электронные письма участников: Отобразить
attendee_id
,first_name
иemail
, убедившись, чтоemail
полностью в нижнем регистре. Задать псевдоним этому какstandard_email
. - Проверка вместимости площадки: Отобразить
venue_name
иcapacity
. Добавить столбецis_large_venue
, который имеет значение TRUE, еслиcapacity
больше 1000, и FALSE в противном случае. - День начала мероприятия: Извлечь день недели (например, ‘Monday’, ‘Tuesday’) из
start_datetime
для каждого мероприятия. Отобразитьevent_name
,start_datetime
иstart_day
. (Подсказка: ИспользуйтеTO_CHAR
сEXTRACT(DOW FROM ...)
может понадобиться для названия, или просто покажите номер DOW изEXTRACT
). Давайте придерживаться номера:EXTRACT(DOW FROM start_datetime) AS start_dow
(0=Вс, 6=Сб в PG). - Стоимость площадки округленная вверх: Отобразить
venue_name
иbooking_cost
. Вычислить стоимость, округленную ВВЕРХ до ближайших $100. Задать псевдоним этому какcost_ceil_100
. (Подсказка:CEIL(booking_cost / 100.0) * 100
). - Отображение компании участника: Отобразить
attendee_id
,first_name
. ИспользоватьCOALESCE
, чтобы показатьcompany_name
; если оно NULL, отобразить ‘Individual Attendee’. Задать псевдоним этому какaffiliation
. - Абсолютная разница цен от базовой: Для регистраций вычислить абсолютную разницу между
final_price
иbase_ticket_price
мероприятия (требуется объединениеregistrations
иevents
). Отобразитьregistration_id
,base_ticket_price
,final_price
иprice_difference
. - Определить ожидающие платежи: Использовать
NULLIF
, чтобы вернутьregistration_id
только в том случае, еслиpayment_status
НЕ равен ‘Paid’. В противном случае вернуть NULL. Отобразитьregistration_id
,payment_status
и результат какunpaid_registration_id
. - Короткое название мероприятия: Отобразить
event_id
и первые 30 символовevent_name
. Задать псевдоним этому какshort_event_name
. ИспользоватьSUBSTRING
. - Дополненный ID площадки: Отобразить
venue_id
, отформатированный как 5-значную строку с ведущими нулями. Задать псевдоним этому какformatted_venue_id
. ИспользоватьLPAD
. - Дней до начала мероприятия: Для мероприятий, начинающихся в будущем, вычислить количество дней от
CURRENT_DATE
доstart_datetime
. Отобразитьevent_name
,start_datetime
иdays_until_start
. Обработать мероприятия в прошлом (результат может быть отрицательным или отфильтровать их). Использоватьstart_datetime::DATE - CURRENT_DATE
.
Вариант 6: Блог-платформа
Сценарий: Вы управляете базой данных для многопользовательской блог-платформы, отслеживая пользователей, записи (посты), комментарии и категории.
Схема базы данных:
-- Удалить таблицы, если они существуют (необязательно)
-- DROP TABLE IF EXISTS comments;
-- DROP TABLE IF EXISTS posts;
-- DROP TABLE IF EXISTS categories;
-- DROP TABLE IF EXISTS users;
-- 1. Создать таблицу 'users' (пользователи)
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(30) UNIQUE NOT NULL, -- Для LENGTH(), LOWER()
email VARCHAR(100) UNIQUE NOT NULL, -- Для LOWER()
full_name VARCHAR(100), -- Для CONCAT (если требуется разделить) или просто для отображения
join_date DATE NOT NULL DEFAULT CURRENT_DATE, -- Для AGE(), EXTRACT()
profile_bio TEXT -- Допускает NULL, для COALESCE, LENGTH()
-- password_hash VARCHAR(255) NOT NULL -- Не используется в задачах
);
-- 2. Создать таблицу 'categories' (категории)
CREATE TABLE categories (
category_id SERIAL PRIMARY KEY,
category_name VARCHAR(50) UNIQUE NOT NULL, -- Для UPPER(), REPLACE()
slug VARCHAR(60) UNIQUE -- Например, 'data-science-basics', для LOWER(), REPLACE()
);
-- 3. Создать таблицу 'posts' (записи)
CREATE TABLE posts (
post_id SERIAL PRIMARY KEY,
author_id INTEGER NOT NULL REFERENCES users(user_id),
category_id INTEGER REFERENCES categories(category_id),
title VARCHAR(200) NOT NULL, -- Для SUBSTRING()
content TEXT, -- Для LENGTH()
publish_datetime TIMESTAMP, -- Допускает NULL для черновиков. Для EXTRACT(), AGE(), INTERVAL
last_updated TIMESTAMP DEFAULT NOW(),
status VARCHAR(15) DEFAULT 'Draft', -- 'Draft', 'Published', 'Archived' - Для CASE, NULLIF
word_count INTEGER -- Для MOD(), CEIL(), числовых операций
);
-- 4. Создать таблицу 'comments' (комментарии)
CREATE TABLE comments (
comment_id SERIAL PRIMARY KEY,
post_id INTEGER NOT NULL REFERENCES posts(post_id),
commenter_id INTEGER REFERENCES users(user_id), -- NULL, если комментатор анонимный/не вошел в систему
commenter_name VARCHAR(50), -- Используется, если commenter_id равен NULL
comment_text TEXT NOT NULL,
comment_datetime TIMESTAMP DEFAULT NOW(), -- Для EXTRACT(), AGE()
parent_comment_id INTEGER REFERENCES comments(comment_id) -- Для древовидных комментариев (NULL, если верхний уровень)
);
-- Вставка образцов данных --
INSERT INTO users (username, email, full_name, join_date, profile_bio) VALUES
('john_doe', 'john.doe@blog.com', 'John Doe', '2022-01-10', 'Tech enthusiast and blogger.'),
('jane_smith', 'Jane.Smith@blog.com', 'Jane Smith', '2022-03-15', NULL), -- NULL bio
('bob_coder', 'bob@coder.net', 'Bob Coder', '2023-05-01', 'Software developer sharing tips.'),
('reader_x', 'readerX@mail.com', NULL, '2023-10-01', NULL); -- Нет полного имени, нет биографии
INSERT INTO categories (category_name, slug) VALUES
('Technology', 'technology'),
('Data Science', 'data-science'),
('Tutorials', 'tutorials'),
(' Opinion Pieces ', 'opinion-pieces'); -- Slug needs generating/cleaning
INSERT INTO posts (author_id, category_id, title, content, publish_datetime, status, word_count) VALUES
(1, 1, 'The Future of AI', 'AI is evolving rapidly...', '2023-06-01 10:00:00', 'Published', 1250),
(3, 2, 'Introduction to PostgreSQL Functions', 'This post covers several useful SQL functions...', '2023-07-15 14:30:00', 'Published', 1800),
(1, 3, 'Setting Up a Python Dev Environment', 'Step-by-step guide...', NULL, 'Draft', 950), -- Черновик, нет даты публикации
(2, 4, 'Why Static Sites Are Great', 'My thoughts on static site generators...', '2023-09-01 11:00:00', 'Published', 780),
(3, 1, 'Old Tech Thoughts', 'Some musings on older tech...', '2022-11-20 09:00:00', 'Archived', 600); -- Заархивировано
INSERT INTO comments (post_id, commenter_id, commenter_name, comment_text, comment_datetime) VALUES
(1, 2, NULL, 'Great overview!', '2023-06-01 11:00:00'),
(2, 1, NULL, 'Very helpful, thanks Bob!', '2023-07-16 09:15:00'),
(1, NULL, 'Guest User', 'I disagree with point 2.', '2023-06-02 15:00:00'), -- Анонимный комментарий
(4, 3, NULL, 'Nice points, Jane!', '2023-09-01 12:30:00'),
(2, 4, NULL, 'Where can I learn more?', '2023-10-05 10:00:00');
Задачи для варианта 6:
- Проверка длины имени пользователя: Отобразить
user_id
иusername
. Также показать длину каждогоusername
, указав псевдонимusername_length
. - Генерация Slug категории: Отобразить
category_name
. Сгенерировать потенциальныйslug
, преобразовавcategory_name
в нижний регистр, удалив начальные/конечные пробелы и заменив оставшиеся пробелы дефисами. Указать псевдонимgenerated_slug
. (ИспользоватьLOWER
,TRIM
,REPLACE
). - Возраст учетной записи пользователя: Рассчитать, как долго зарегистрирован каждый пользователь (с
join_date
) по состоянию наCURRENT_DATE
. Отобразитьusername
,join_date
и продолжительность, используяAGE()
, указав псевдонимaccount_age
. - Выдержка из записи: Для каждой записи отобразить
post_id
,title
и первые 150 символовcontent
. Если содержимое длиннее 150 символов, добавить ‘…’. Указать псевдонимpost_excerpt
. (Подсказка: использоватьSUBSTRING
,LENGTH
,CASE
,CONCAT
/||
). - Стандартизированные адреса электронной почты пользователей: Отобразить
user_id
,username
иemail
, убедившись, чтоemail
полностью в нижнем регистре. Указать псевдонимstandard_email
. - Возраст публикации записи: Для опубликованных записей (
publish_datetime
NOT NULL) рассчитать, как давно они были опубликованы относительноNOW()
. Отобразитьpost_id
,title
,publish_datetime
и продолжительность, используяAGE()
, указав псевдонимtime_since_publish
. - Анализ времени комментария: Для каждого комментария извлечь год, месяц и час из
comment_datetime
. Отобразитьcomment_id
,comment_datetime
,comment_year
,comment_month
иcomment_hour
. - Статус видимости записи: Отобразить
post_id
,title
иstatus
. Создать столбецis_visible
, используяCASE
: TRUE, еслиstatus
равен ‘Published’, FALSE в противном случае. - Четность количества слов в записи: Отобразить
post_id
,title
иword_count
. Определить, является лиword_count
‘Even’ (четным) или ‘Odd’ (нечетным). Указать псевдонимword_count_parity
. (Подсказка: использоватьMOD
или%
). - Отображение биографии пользователя: Отобразить
username
иprofile_bio
. ИспользоватьCOALESCE
, чтобы отобразить ‘No bio provided’ (Биография не предоставлена), еслиprofile_bio
равен NULL или пустой строке. (Подсказка:COALESCE(NULLIF(TRIM(profile_bio), ''), 'No bio provided')
). - Абсолютное отклонение количества слов: Рассчитать абсолютную разницу между
word_count
каждой записи и целевой длиной в 1000 слов. Отобразитьpost_id
,word_count
иabs_diff_from_1000
. - Определение неопубликованных записей: Использовать
NULLIF
, чтобы вернутьpost_id
, еслиstatus
записи равен ‘Draft’ (Черновик) или ‘Archived’ (Заархивировано). В противном случае вернуть NULL. Отобразитьpost_id
,status
и результат какnon_published_post_id
. - Оценка времени чтения: Рассчитать предполагаемое время чтения в минутах, разделив
word_count
на 200 (среднее количество слов в минуту) и округлив результат ВВЕРХ до ближайшего целого числа. Отобразитьpost_id
,word_count
иestimated_read_minutes
. (ИспользоватьCEIL
). - UserID с заполнением нулями: Отобразить
user_id
, отформатированный как 7-значная строка с ведущими нулями. Указать псевдонимformatted_user_id
. ИспользоватьLPAD
. - Идентификация комментатора: Отобразить
comment_id
иcomment_text
. Показать идентификатор комментатора: еслиcommenter_id
не NULL, отобразить ‘User: ‘ (Пользователь:) с последующимcommenter_id
(приведенным к VARCHAR). Еслиcommenter_id
равен NULL, отобразить ‘Guest: ‘ (Гость:) с последующимcommenter_name
. Указать псевдонимcommenter_identity
. (ИспользоватьCASE
иCOALESCE
или вложенныйCASE
).
Вариант 7: Управление Авиарейсами
Сценарий: Вы работаете с базой данных небольшой авиакомпании, управляя информацией о рейсах, самолетах, аэропортах и бронированиях пассажиров.
Схема базы данных:
-- Drop tables if they exist (optional)
-- DROP TABLE IF EXISTS bookings;
-- DROP TABLE IF EXISTS flights;
-- DROP TABLE IF EXISTS aircraft;
-- DROP TABLE IF EXISTS airports;
-- DROP TABLE IF EXISTS passengers;
-- 1. Create the 'airports' table
CREATE TABLE airports (
airport_code CHAR(3) PRIMARY KEY, -- e.g., 'JFK', 'LAX'. Fixed length.
airport_name VARCHAR(100) NOT NULL, -- For LENGTH(), UPPER()
city VARCHAR(50) NOT NULL,
country_code CHAR(2) NOT NULL -- e.g., 'US', 'GB'. For LOWER()
);
-- 2. Create the 'aircraft' table
CREATE TABLE aircraft (
aircraft_id SERIAL PRIMARY KEY,
model_name VARCHAR(50) NOT NULL, -- e.g., 'Boeing 737-800'
manufacturer VARCHAR(50),
seat_capacity INTEGER NOT NULL, -- For MOD()
range_miles NUMERIC(6, 0) -- For numeric functions
);
-- 3. Create the 'flights' table
CREATE TABLE flights (
flight_id SERIAL PRIMARY KEY,
flight_number VARCHAR(10) UNIQUE NOT NULL, -- e.g., ' AA101 ', for TRIM(), SUBSTRING()
departure_airport CHAR(3) REFERENCES airports(airport_code),
arrival_airport CHAR(3) REFERENCES airports(airport_code),
aircraft_id INTEGER REFERENCES aircraft(aircraft_id),
scheduled_departure TIMESTAMP WITH TIME ZONE NOT NULL, -- For EXTRACT(), INTERVAL, date/time funcs
scheduled_arrival TIMESTAMP WITH TIME ZONE NOT NULL,
base_price NUMERIC(7, 2) -- For ROUND(), CEIL(), FLOOR(), ABS()
);
-- 4. Create the 'passengers' table
CREATE TABLE passengers (
passenger_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
middle_name VARCHAR(50), -- For COALESCE()
last_name VARCHAR(50) NOT NULL, -- For CONCAT()
email VARCHAR(100) UNIQUE,
date_of_birth DATE -- For AGE()
);
-- 5. Create the 'bookings' table
CREATE TABLE bookings (
booking_id SERIAL PRIMARY KEY,
flight_id INTEGER REFERENCES flights(flight_id),
passenger_id INTEGER REFERENCES passengers(passenger_id),
booking_date DATE DEFAULT CURRENT_DATE,
seat_number VARCHAR(4), -- e.g., '12A'
final_price NUMERIC(7, 2), -- May differ from base_price due to fees/discounts
status VARCHAR(15) DEFAULT 'Confirmed' -- e.g., Confirmed, Cancelled, Checked-In. For CASE(), NULLIF()
);
-- Sample Data Insertion --
-- Пример вставки данных --
INSERT INTO airports (airport_code, airport_name, city, country_code) VALUES
('JFK', 'John F. Kennedy International Airport', 'New York', 'US'),
('LAX', 'Los Angeles International Airport', 'Los Angeles', 'US'),
('LHR', 'London Heathrow Airport', 'London', 'GB'),
('ORD', 'O''Hare International Airport', 'Chicago', 'US'),
('ATL', 'Hartsfield-Jackson Atlanta International Airport', 'Atlanta', 'US');
INSERT INTO aircraft (model_name, manufacturer, seat_capacity, range_miles) VALUES
('Boeing 737-800', 'Boeing', 189, 3500),
('Airbus A320neo', 'Airbus', 195, 4000),
('Boeing 777-300ER', 'Boeing', 396, 7370),
('Embraer E175', 'Embraer', 88, 2200);
INSERT INTO flights (flight_number, departure_airport, arrival_airport, aircraft_id, scheduled_departure, scheduled_arrival, base_price) VALUES
(' AA101 ', 'JFK', 'LAX', 1, '2024-09-15 08:00:00-04', '2024-09-15 11:30:00-07', 350.00), -- Spaces
('BA202', 'LHR', 'JFK', 3, '2024-09-16 10:30:00+01', '2024-09-16 13:30:00-04', 680.50),
(' UA303', 'ORD', 'ATL', 2, '2024-09-15 14:00:00-05', '2024-09-15 16:45:00-04', 180.75), -- Leading space
('AA102 ', 'LAX', 'JFK', 1, '2024-09-17 13:00:00-07', '2024-09-17 21:30:00-04', 365.25), -- Trailing space
('DL404', 'ATL', 'ORD', 4, '2024-09-18 09:15:00-04', '2024-09-18 10:00:00-05', 175.00);
INSERT INTO passengers (first_name, middle_name, last_name, email, date_of_birth) VALUES
('James', 'Tiberius', 'Kirk', 'j.kirk@starfleet.com', '1985-03-22'),
('Leia', NULL, 'Organa', 'leia.o@rebellion.org', '1990-11-01'),
('Han', NULL, 'Solo', 'han.solo@falcon.net', '1988-07-10'),
('Sarah', 'Jane', 'Connor', 'sarah.connor@resistance.fut', '1984-05-13'),
('Ellen', 'Louise', 'Ripley', 'e.ripley@wey-yu.corp', '1980-01-07');
INSERT INTO bookings (flight_id, passenger_id, booking_date, seat_number, final_price, status) VALUES
(1, 1, '2024-07-10', '5A', 375.00, 'Confirmed'),
(2, 2, '2024-08-01', '22K', 710.50, 'Confirmed'),
(3, 3, '2024-08-15', '10C', 180.75, 'Cancelled'),
(1, 4, '2024-07-11', '5B', 380.00, 'Checked-In'),
(4, 5, '2024-09-01', NULL, 365.25, 'Confirmed'), -- NULL seat
(2, 3, '2024-08-20', '40A', 680.50, 'Confirmed');
Задачи для Варианта 7:
- Полное имя пассажира: Отобразите
passenger_id
и создайтеfull_name
, объединивfirst_name
,middle_name
(если оно существует, иначе пропустите) иlast_name
. ИспользуйтеCOALESCE
, чтобы элегантно обработать потенциальное значение NULL вmiddle_name
(например,first || COALESCE(' ' || middle_name, '') || ' ' || last
). - Очистка номеров рейсов: Покажите
flight_id
иflight_number
после удаления любых начальных или конечных пробелов. Назовите очищенный столбецclean_flight_no
. - Возраст пассажира: Рассчитайте текущий возраст каждого пассажира на основе их
date_of_birth
. Отобразитеfirst_name
,last_name
,date_of_birth
и вычисленныйage
. - Продолжительность полета: Рассчитайте запланированную продолжительность каждого рейса (разницу между
scheduled_arrival
иscheduled_departure
). Отобразитеflight_id
,flight_number
и вычисленнуюduration
в виде INTERVAL. - Сводка по статусу бронирования: Отобразите
booking_id
,final_price
иbooking_summary
. Используйте операторCASE
: еслиstatus
имеет значение ‘Cancelled’, покажите ‘CANCELLED’. Еслиstatus
имеет значение ‘Checked-In’, покажите ‘CHECKED-IN’. В противном случае покажите ‘CONFIRMED’. - Длина названия аэропорта: Отобразите
airport_code
и длинуairport_name
для всех аэропортов. Назовите столбец длиныname_length
. - Код авиакомпании из номера рейса: Извлеките первые 2 символа (обычно код авиакомпании) из
clean_flight_no
(из логики задачи 2). Отобразитеclean_flight_no
и извлеченныйairline_code
. (ИспользуйтеSUBSTRING
для очищенного номера рейса). - Время до отправления: Для рейсов, запланированных на будущее, рассчитайте время, оставшееся до
scheduled_departure
отNOW()
. Отобразитеflight_number
,scheduled_departure
иtime_to_departure
. (Используйтеscheduled_departure - NOW()
). - Цена, округленная до ближайших 10 долларов: Отобразите
flight_id
иbase_price
. Также покажитеbase_price
, округленную до ближайших 10 долларов. Назовите это какprice_rounded_10
. (Подсказка:ROUND(price, -1)
). - Проверка назначения места: Отобразите
booking_id
иpassenger_id
. ИспользуйтеCOALESCE
, чтобы показатьseat_number
. Еслиseat_number
имеет значение NULL, отобразите ‘Unassigned’. Назовите это какseat_status
. - Месяц отправления и день недели: Извлеките месяц (числовой) и день недели (числовой, например, 0 для воскресенья, 6 для субботы в PostgreSQL) из времени
scheduled_departure
. Отобразитеflight_number
,scheduled_departure
,departure_month
иdeparture_dow
. - Абсолютная разница в цене: Рассчитайте абсолютную разницу между
final_price
бронирования иbase_price
соответствующего рейса (требуется JOIN - предположим, что вы можете соединитьbookings
иflights
поflight_id
). Отобразитеbooking_id
,final_price
,base_price
иprice_difference
. - Зануление определенного производителя самолетов: Используйте
NULLIF
, чтобы вернуть NULL, еслиmanufacturer
самолета имеет значение ‘Embraer’. В противном случае верните производителя. Отобразитеaircraft_id
,model_name
,manufacturer
и результат какnull_if_embraer
. - Четность вместимости самолета: Определите, является ли
seat_capacity
самолета нечетным или четным числом. Отобразитеaircraft_id
,model_name
,seat_capacity
и ‘Even’ или ‘Odd’ какcapacity_parity
. (ИспользуйтеMOD
). - Форматирование идентификатора бронирования: Отобразите
booking_id
, отформатированный как 7-значная строка с ведущими нулями (например, 1 становится ‘0000001’). Назовите это какformatted_booking_id
. (Подсказка: ИспользуйтеLPAD
).
Вариант 8: Записи о пациентах больницы
Сценарий: Вы управляете упрощенной базой данных для клиники, отслеживая пациентов, врачей и приемы.
Схема базы данных:
-- Удалите таблицы, если они существуют (необязательно)
-- DROP TABLE IF EXISTS appointments;
-- DROP TABLE IF EXISTS doctors;
-- DROP TABLE IF EXISTS patients;
-- 1. Создайте таблицу 'patients'
CREATE TABLE patients (
patient_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
middle_initial CHAR(1), -- Одна буква инициала, допускает NULL. Для COALESCE
last_name VARCHAR(50) NOT NULL, -- Для CONCAT
date_of_birth DATE NOT NULL, -- Для AGE, EXTRACT
gender CHAR(1) CHECK (gender IN ('M', 'F', 'O')), -- M=Мужской, F=Женский, O=Другое
phone_number VARCHAR(20), -- Может иметь форматирование, например, '(123) 456-7890'. Для REPLACE
email VARCHAR(100) UNIQUE -- Для LOWER
);
-- 2. Создайте таблицу 'doctors'
CREATE TABLE doctors (
doctor_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
specialty VARCHAR(100), -- Для общих запросов, NULLIF
office_number VARCHAR(10) UNIQUE, -- Например, ' RM 301 ', для TRIM
start_date DATE -- Для AGE
);
-- 3. Создайте таблицу 'appointments'
CREATE TABLE appointments (
appointment_id SERIAL PRIMARY KEY,
patient_id INTEGER REFERENCES patients(patient_id),
doctor_id INTEGER REFERENCES doctors(doctor_id),
appointment_datetime TIMESTAMP WITH TIME ZONE NOT NULL, -- Для EXTRACT, INTERVAL, CAST
reason VARCHAR(255), -- Для LENGTH
duration_minutes INTEGER DEFAULT 30, -- Для числовых операций
billing_amount NUMERIC(8, 2), -- Для ROUND, CEIL, FLOOR, ABS
status VARCHAR(20) DEFAULT 'Scheduled' -- Например, Scheduled, Completed, Cancelled, No-Show. Для CASE
);
-- Вставка образцов данных --
INSERT INTO patients (first_name, middle_initial, last_name, date_of_birth, gender, phone_number, email) VALUES
('Gregory', 'H', 'House', '1959-06-11', 'M', '(609) 555-0100', 'g.house@ppth.org'),
('Lisa', NULL, 'Cuddy', '1968-10-15', 'F', '609-555-0101', 'L.Cuddy@ppth.org'),
('James', 'E', 'Wilson', '1965-05-22', 'M', ' 609.555.0102 ', 'jewilson@ppth.org'), -- Пробелы в телефоне
('Allison', NULL, 'Cameron', '1979-09-01', 'F', NULL, 'ACameron@ppth.org'), -- NULL в телефоне
('Robert', 'C', 'Chase', '1978-02-17', 'M', '6095550104', 'r.chase@ppth.org');
INSERT INTO doctors (first_name, last_name, specialty, office_number, start_date) VALUES
('Gregory', 'House', 'Nephrology, Infectious Disease', ' RM 201', '1995-04-01'), -- Пробел в начале
('Lisa', 'Cuddy', 'Endocrinology, Administration', ' ADMIN 01', '1998-07-15'), -- Смешанный регистр/пробелы
('James', 'Wilson', 'Oncology', ' ONC 305 ', '1992-11-01'), -- Пробелы в начале/конце
('Eric', 'Foreman', 'Neurology', 'NEURO 110', '2004-08-20');
INSERT INTO appointments (patient_id, doctor_id, appointment_datetime, reason, duration_minutes, billing_amount, status) VALUES
(1, 1, '2024-08-15 09:00:00-04', 'Consultation', 45, 250.00, 'Completed'),
(2, 2, '2024-08-15 10:00:00-04', 'Follow-up', 30, 150.50, 'Completed'),
(3, 3, '2024-09-20 14:30:00-04', 'Check-up', 30, NULL, 'Scheduled'), -- Будущее, счет еще не выставлен
(4, 1, '2024-08-01 11:00:00-04', 'Initial Visit', 60, 300.75, 'No-Show'),
(5, 4, '2024-09-25 16:00:00-04', 'Neurology consult', 45, NULL, 'Scheduled'), -- Будущее
(1, 3, '2023-12-10 09:30:00-05', 'Scan results', 20, 120.00, 'Completed'); -- Прошлое
Задачи для Варианта 8:
- Полное имя пациента: Отобразите
patient_id
. Создайте строкуfull_name
в формате ‘Фамилия, Имя И.’, где И -middle_initial
. Еслиmiddle_initial
равно NULL, опустите его. (например, ‘House, Gregory H.’, ‘Cuddy, Lisa’). ИспользуйтеCONCAT
иCOALESCE
. - Стандартизованный номер телефона: Отобразите
patient_id
,first_name
иphone_number
. Создайте столбецclean_phone
, удалив пробелы, скобки и дефисы изphone_number
. (Подсказка: Используйте вложенныеREPLACE
). Обработайте NULL телефоны корректно (они должны остаться NULL). - Расчет возраста пациента: Вычислите текущий возраст каждого пациента в годах на основе их
date_of_birth
. Отобразитеfirst_name
,last_name
,date_of_birth
и целую часть возраста в годах (используйтеEXTRACT(YEAR FROM AGE(...))
или аналогичное). Назовите столбецage_years
. - Форматирование времени приема: Отобразите
appointment_id
,appointment_datetime
. Преобразуйтеappointment_datetime
в строку, отформатированную как ‘YYYY-MM-DD HH24:MI’. Назовите столбецformatted_datetime
. (Подсказка: ИспользуйтеTO_CHAR
, если доступно, или объединитеCAST
со строковыми функциями). Для простоты с CAST: Приведитеappointment_datetime::DATE
иappointment_datetime::TIME
отдельно и объедините. - Сводка статуса приема: Покажите
appointment_id
,patient_id
,doctor_id
иstatus_summary
. ИспользуйтеCASE
: Еслиstatus
равен ‘Completed’, покажите ‘Done’. Если ‘Cancelled’ или ‘No-Show’, покажите ‘Missed’. Если ‘Scheduled’, покажите ‘Upcoming’. - Длина специальности врача: Отобразите
doctor_id
,last_name
и длину строкиspecialty
. Назовите длинуspecialty_length
. Обработайте NULL специальности (длина должна быть 0 или NULL в зависимости от БД). - Домен электронной почты пациента: Извлеките доменное имя (часть после ‘@’) из адреса электронной почты пациента
email
. Отобразитеpatient_id
,email
и извлеченныйemail_domain
. (Подсказка: ИспользуйтеSUBSTRING
иPOSITION('@' IN email)
). - Дней с последнего приема: Для приемов со статусом ‘Completed’ рассчитайте количество дней, прошедших между
appointment_datetime
иCURRENT_DATE
. Отобразитеappointment_id
,appointment_datetime
иdays_since_appointment
. - Сумма счета округлена вверх: Отобразите
appointment_id
,billing_amount
. Также покажитеbilling_amount
, округленную ВВЕРХ до ближайшего целого доллара. Назовите этоbilled_ceil
. Обработайте NULL суммы. - Отображение инициала пациента: Отобразите
patient_id
,first_name
,last_name
. ИспользуйтеCOALESCE
для отображенияmiddle_initial
; если он NULL, отобразите ‘-‘. Назовите столбецdisplay_initial
. - Год и квартал приема: Извлеките год и календарный квартал (1-4) из
appointment_datetime
. Отобразитеappointment_id
,appointment_datetime
,appointment_year
иappointment_quarter
. - Абсолютная разница в счетах: Рассчитайте абсолютную разницу между
billing_amount
каждого приема и стандартной платой в размере 175,00 долларов США. Отобразитеappointment_id
,billing_amount
иabs_diff_from_standard
. Включите только приемы, гдеbilling_amount
не равен NULL. - Обратите в NULL конкретную специальность: Используйте
NULLIF
, чтобы вернуть NULL, если специальность врача - ‘Administration’. В противном случае верните специальность. Отобразитеdoctor_id
,last_name
,specialty
и результат какnull_if_admin
. - Четность ID врача: Определите, является ли
doctor_id
нечетным или четным. Отобразитеdoctor_id
,last_name
и ‘Even’ или ‘Odd’ какid_parity
. (ИспользуйтеMOD
). - Очистить номер кабинета: Отобразите
doctor_id
,last_name
иoffice_number
. Создайте столбецclean_office_no
, удалив все начальные/конечные пробелы и преобразовав результат в верхний регистр. (ИспользуйтеTRIM
иUPPER
).
Вариант 9: Сервис аренды автомобилей
Сценарий: Вы управляете базой данных для компании по прокату автомобилей, отслеживая транспортные средства, клиентов и договоры аренды.
Схема базы данных:
-- Удалить таблицы, если они существуют (необязательно)
-- DROP TABLE IF EXISTS rentals;
-- DROP TABLE IF EXISTS customers;
-- DROP TABLE IF EXISTS vehicles;
-- DROP TABLE IF EXISTS locations;
-- 1. Создать таблицу 'locations' (местоположения)
CREATE TABLE locations (
location_id SERIAL PRIMARY KEY,
location_code VARCHAR(5) UNIQUE NOT NULL, -- например, ' LGA01', для TRIM
address VARCHAR(255) NOT NULL,
city VARCHAR(50) NOT NULL,
phone_number VARCHAR(20) -- Для REPLACE
);
-- 2. Создать таблицу 'vehicles' (транспортные средства)
CREATE TABLE vehicles (
vehicle_id SERIAL PRIMARY KEY,
vin VARCHAR(17) UNIQUE NOT NULL, -- Vehicle Identification Number (VIN), для UPPER, SUBSTRING
make VARCHAR(50) NOT NULL, -- например, 'Toyota', 'Ford'
model VARCHAR(50) NOT NULL, -- например, 'Camry', 'Mustang'. Для NULLIF
year INTEGER NOT NULL, -- Для EXTRACT (из даты), AGE (возраст транспортного средства)
license_plate VARCHAR(10) UNIQUE, -- например, ' ABC-123 '. Для TRIM, REPLACE
daily_rate NUMERIC(6, 2) NOT NULL, -- Для ROUND, CEIL, FLOOR, ABS
current_mileage NUMERIC(7, 0) DEFAULT 0 -- Для числовых операций
);
-- 3. Создать таблицу 'customers' (клиенты)
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL, -- Для CONCAT, LENGTH
email VARCHAR(100) UNIQUE NOT NULL, -- Для LOWER
date_of_birth DATE, -- Для AGE
driver_license_no VARCHAR(20) UNIQUE,
join_date DATE DEFAULT CURRENT_DATE -- Для AGE, EXTRACT
);
-- 4. Создать таблицу 'rentals' (аренда)
CREATE TABLE rentals (
rental_id SERIAL PRIMARY KEY,
vehicle_id INTEGER REFERENCES vehicles(vehicle_id),
customer_id INTEGER REFERENCES customers(customer_id),
pickup_location_id INTEGER REFERENCES locations(location_id),
dropoff_location_id INTEGER REFERENCES locations(location_id), -- Разрешает NULL, если совпадает с местом получения
pickup_datetime TIMESTAMP WITH TIME ZONE NOT NULL, -- Для EXTRACT, INTERVAL, CAST
return_datetime TIMESTAMP WITH TIME ZONE, -- NULL, если в настоящее время арендован. Для COALESCE, CASE
total_amount NUMERIC(8, 2) -- Рассчитывается при возврате. Разрешает NULL.
);
-- Вставка примера данных --
INSERT INTO locations (location_code, address, city, phone_number) VALUES
('JFK01', 'Building 78, JFK Airport', 'New York', '718-555-0110'),
('LAX01', '9020 Aviation Blvd', 'Los Angeles', '310-555-0120'),
('ORD01 ', '10000 Bessie Coleman Dr', 'Chicago', '773-555-0130'), -- Пробел в конце
(' MIA01', '4200 NW 21st St', 'Miami', '(305) 555-0140'); -- Пробел в начале
INSERT INTO vehicles (vin, make, model, year, license_plate, daily_rate, current_mileage) VALUES
('1GKS19EC5L0123456', 'Chevrolet', 'Malibu', 2020, ' NYC-101', 55.00, 35000), -- Пробел в начале номера
('JTDKBRFU0P0654321', 'Toyota', 'RAV4', 2023, 'CAL-202 ', 70.50, 12000), -- Пробел в конце номера
('1FA6P8CFXH5987654', 'Ford', 'Mustang', 2021, 'FLA-303', 95.75, 21000),
('WVWZZZAUZMW112233', 'Volkswagen', 'Golf', 2022, 'ILL-404', 60.00, 18500),
('JTDKBRFU0P0654ABC', 'Toyota', 'RAV4', 2023, NULL, 72.00, 9500); -- NULL номер
INSERT INTO customers (first_name, last_name, email, date_of_birth, driver_license_no, join_date) VALUES
('Walter', 'White', 'w.white@jpwynne.edu', '1958-09-07', 'NM123456', '2022-01-15'),
('Jesse', 'Pinkman', 'capncook@kryskay.com', '1984-08-24', 'NM654321', '2022-05-20'),
('Skyler', 'White', 's.white@accountant.net', '1970-08-11', 'NM789012', '2023-03-10'),
('Saul', 'Goodman', 'saul@bettercallsaul.com', '1960-11-07', NULL, '2021-11-01'), -- NULL лицензия
('Mike', 'Ehrmantraut', 'mike.e@security.pro', '1945-03-18', 'PA999888', '2023-06-01');
INSERT INTO rentals (vehicle_id, customer_id, pickup_location_id, dropoff_location_id, pickup_datetime, return_datetime, total_amount) VALUES
(1, 1, 1, 1, '2024-07-01 10:00:00-04', '2024-07-08 11:30:00-04', 412.50),
(2, 2, 2, 2, '2024-08-10 14:00:00-07', NULL, NULL), -- В настоящее время арендован
(3, 3, 4, 4, '2024-08-20 09:00:00-04', '2024-08-25 10:00:00-04', 574.50),
(4, 4, 3, NULL, '2024-09-05 12:00:00-05', NULL), -- В настоящее время арендован, NULL место возврата (предполагается то же самое)
(1, 5, 1, 3, '2024-09-10 15:30:00-04', NULL); -- В настоящее время арендован
Задачи для Варианта 9:
- Полное имя клиента и длина: Отобразите
customer_id
. Создайтеfull_name
путем объединенияfirst_name
иlast_name
. Также отобразите длинуfull_name
. Дайте псевдонимname_length
. - Очищенные номерные знаки: Покажите
vehicle_id
,make
,model
иlicense_plate
. Создайте столбецclean_plate
, удалив все начальные/конечные пробелы и преобразовав результат в верхний регистр. Обработайте NULL номерные знаки корректно. - Возраст клиента: Вычислите текущий возраст каждого клиента на основе их
date_of_birth
. Отобразитеfirst_name
,last_name
,date_of_birth
и вычисленныйage
. Обработайте NULLdate_of_birth
, если они были добавлены. - Продолжительность аренды (завершенные аренды): Для аренд, где
return_datetime
не NULL, рассчитайте продолжительность аренды. Отобразитеrental_id
,pickup_datetime
,return_datetime
и вычисленнуюrental_duration
в виде интервала. - Статус транспортного средства: Отобразите
vehicle_id
,make
,model
. Определите статус транспортного средства. Проверьте, существует лиvehicle_id
в таблицеrentals
с NULLreturn_datetime
. Если да, статус - ‘Rented’ (Арендован). В противном случае статус - ‘Available’ (Доступен). (Требует LEFT JOIN иCASE
или подзапрос). Упрощено для задания: основывайтесь только на приведенных примерах данных. Если транспортное средство появляется в rentals с NULL return_datetime, оно ‘Rented’, иначе ‘Available’. Используйте CASE. - VIN в верхнем регистре: Отобразите
vehicle_id
и номерvin
, преобразованный полностью в верхний регистр. Дайте псевдонимupper_vin
. - Аббревиатура марки транспортного средства: Покажите
vehicle_id
и первые 3 символаmake
. Дайте псевдонимmake_abbr
. (ИспользуйтеSUBSTRING
). - Дней с момента присоединения клиента: Рассчитайте, сколько дней прошло с
join_date
каждого клиента. Отобразитеcustomer_id
,email
,join_date
иdays_as_member
. (ИспользуйтеCURRENT_DATE - join_date
). - Ежедневная ставка, округленная в меньшую сторону: Отобразите
vehicle_id
,daily_rate
. Также покажитеdaily_rate
, округленную ВНИЗ до ближайшего целого доллара. Дайте этому псевдонимrate_floor
. - Отображение местоположения возврата: Отобразите
rental_id
,pickup_location_id
. ИспользуйтеCOALESCE
, чтобы показатьdropoff_location_id
. Если он NULL, покажитеpickup_location_id
вместо него (предполагая возврат в то же место). Дайте этому псевдонимeffective_dropoff_id
. - Месяц и час получения: Извлеките месяц (числовой) и час (0-23) из
pickup_datetime
. Отобразитеrental_id
,pickup_datetime
,pickup_month
иpickup_hour
. - Абсолютная разница ставок: Рассчитайте абсолютную разницу между
daily_rate
каждого транспортного средства и средней ставкой в 75,00 долларов. Отобразитеvehicle_id
,make
,model
,daily_rate
иabs_diff_from_avg
. - Замена определенной модели на NULL: Используйте
NULLIF
, чтобы вернуть NULL, еслиmodel
транспортного средства - ‘RAV4’. В противном случае верните модель. Отобразитеvehicle_id
,make
,model
и результат какnull_if_rav4
. - Проверка четности Customer ID: Определите, является ли
customer_id
четным или нечетным. Отобразитеcustomer_id
,first_name
,last_name
и ‘Even’ (Четный) или ‘Odd’ (Нечетный) какid_parity
. (ИспользуйтеMOD
). - Форматировать ежедневную ставку как текст: Отобразите
vehicle_id
,make
,model
иdaily_rate
. Создайте строкуformatted_rate
, которая показывает ставку в формате ‘$XX.YY в день’. (например, ‘$55.00 в день’). ИспользуйтеCAST
и||
.
Вариант 10: Система Заказов Ресторана
Сценарий: Вы управляете базой данных для ресторана. Вам нужно запросить информацию о пунктах меню, заказах клиентов и деталях клиентов.
Схема Базы Данных:
-- Удаление таблиц, если они существуют (необязательно)
-- DROP TABLE IF EXISTS OrderItems;
-- DROP TABLE IF EXISTS Orders;
-- DROP TABLE IF EXISTS Customers;
-- DROP TABLE IF EXISTS MenuItems;
-- 1. Создание таблицы 'MenuItems'
CREATE TABLE MenuItems (
item_id SERIAL PRIMARY KEY,
item_name VARCHAR(100) NOT NULL, -- Для UPPER, LENGTH
description TEXT, -- Разрешает NULL
category VARCHAR(50), -- Для CASE
price NUMERIC(6, 2) NOT NULL, -- Для ROUND, CEIL, FLOOR, ABS
prep_time_minutes INTEGER, -- Для простых числовых операций
item_code VARCHAR(20) UNIQUE -- e.g., ' APP001 ', для TRIM
);
-- 2. Создание таблицы 'Customers'
CREATE TABLE Customers (
customer_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
phone_number VARCHAR(20), -- Может содержать '-', ' ', '(', ')' для REPLACE
email VARCHAR(100) UNIQUE, -- Для LOWER, COALESCE (возможно nullable)
join_date DATE DEFAULT CURRENT_DATE -- Для AGE, EXTRACT
);
-- 3. Создание таблицы 'Orders'
CREATE TABLE Orders (
order_id SERIAL PRIMARY KEY,
customer_id INTEGER REFERENCES Customers(customer_id), -- Может быть NULL для клиентов без регистрации
order_time TIMESTAMP NOT NULL DEFAULT NOW(), -- Для EXTRACT, CAST
status VARCHAR(20) DEFAULT 'Pending', -- 'Pending', 'Preparing', 'Ready', 'Completed', 'Cancelled'
table_number INTEGER, -- Для NULLIF
is_takeaway BOOLEAN NOT NULL DEFAULT FALSE
);
-- 4. Создание таблицы 'OrderItems'
CREATE TABLE OrderItems (
order_item_id SERIAL PRIMARY KEY,
order_id INTEGER NOT NULL REFERENCES Orders(order_id),
item_id INTEGER NOT NULL REFERENCES MenuItems(item_id),
quantity INTEGER NOT NULL DEFAULT 1,
special_requests VARCHAR(255) -- Разрешает NULL, для COALESCE
);
-- Вставка Примеров Данных --
INSERT INTO MenuItems (item_name, description, category, price, prep_time_minutes, item_code) VALUES
('Classic Burger', 'Beef patty, lettuce, tomato, cheese', 'Burgers', 12.50, 10, ' BUR001 '),
('Veggie Delight Pizza', NULL, 'Pizza', 15.00, 15, 'PIZ005'),
('Caesar Salad', 'Romaine lettuce, croutons, parmesan, caesar dressing', 'Salads', 9.75, 7, ' SAL002'),
('French Fries', 'Crispy potato fries', 'Sides', 4.50, 5, 'SID001'),
('Spaghetti Carbonara', 'Pasta with egg, cheese, pancetta', 'Pasta', 14.00, 12, 'PAS003 '), -- Пробел в конце
('Chocolate Lava Cake', 'Warm chocolate cake with molten center', 'Desserts', 7.99, 8, ' DES001');
INSERT INTO Customers (first_name, last_name, phone_number, email, join_date) VALUES
('Walter', 'White', '505-123-4567', 'heisenberg@bb.net', '2022-01-15'),
('Jesse', 'Pinkman', '(505) 987-6543', 'CAPNCook@bb.net', '2022-05-20'),
('Skyler', 'White', NULL, 'skyler.white@carwash.com', '2022-01-15'),
('Gus', 'Fring', '505 555 0101', NULL, '2023-03-10'); -- NULL email
INSERT INTO Orders (customer_id, order_time, status, table_number, is_takeaway) VALUES
(1, '2023-10-26 19:05:00', 'Completed', 5, FALSE),
(2, '2023-10-26 19:15:00', 'Preparing', NULL, TRUE),
(NULL, '2023-10-26 19:20:00', 'Pending', 12, FALSE),
(1, '2023-09-10 12:30:00', 'Completed', 3, FALSE),
(3, '2023-10-27 08:00:00', 'Pending', NULL, TRUE);
INSERT INTO OrderItems (order_id, item_id, quantity, special_requests) VALUES
(1, 1, 1, 'Extra cheese'),
(1, 4, 1, NULL),
(2, 2, 1, 'No onions'),
(2, 3, 1, 'Dressing on the side'),
(3, 5, 2, NULL),
(4, 1, 1, NULL),
(4, 6, 1, 'Add ice cream');
Задачи для Варианта 10:
- Полное Имя Клиента: Отобразить
customer_id
,first_name
,last_name
и объединитьfirst_name
иlast_name
вfull_name
. - Длина Имени Пункта Меню: Показать
item_name
и его длину в символахLENGTH
для всех пунктов меню. Дать псевдоним столбцу длиныname_length
. - Очищенные Номера Телефонов: Отобразить
customer_id
иphone_number
. Создать столбецcleaned_phone
, удалив пробелы, дефисы, скобки ‘(‘ и ‘)’ изphone_number
. (Подсказка: Несколько вызововREPLACE
). - Цена Пункта Меню Округленная: Показать
item_name
,price
иprice
, округленную до ближайшего целого доллара (ROUND
с 0 десятичными знаками). Дать псевдонимrounded_price
. - День Недели Заказа: Отобразить
order_id
иorder_time
. Извлечь день недели (например, 0 для воскресенья, 1 для понедельника… 6 для субботы в PostgreSQL, используяDOW
) изorder_time
. Дать псевдонимorder_dow
. - Длительность Членства: Вычислить, как долго каждый клиент (у которого есть
join_date
) зарегистрирован. Отобразитьcustomer_id
,join_date
и длительность, используяAGE()
. Дать псевдонимmembership_age
. - Очистка Кода Пункта Меню: Отобразить
item_id
иitem_code
, удалив все начальные и конечные пробелы. Дать псевдоним очищенному столбцуclean_item_code
. - Отображение Специальных Запросов: Показать
order_item_id
. ИспользоватьCOALESCE
для отображенияspecial_requests
; если NULL, отобразить ‘None’. Дать псевдонимrequests_info
. - Категоризация Времени Подготовки: Отобразить
item_name
,prep_time_minutes
. Создать столбецprep_category
: ‘Quick’, если < 8 минут, ‘Standard’, если 8-12 минут (включительно), ‘Long’, если > 12 минут. Обрабатывать NULLprep_time_minutes
как ‘Unknown’. - Стандартизированные Адреса Электронной Почты Клиентов: Отобразить
customer_id
иemail
. Показать электронную почту в нижнем регистре, с псевдонимомlower_email
. Если адрес электронной почты NULL, отобразить ‘N/A’ (ИспользоватьLOWER
иCOALESCE
). - Абсолютная Разница Цены от $10: Для каждого пункта меню вычислить абсолютную разницу между его
price
и $10.00. Отобразитьitem_name
,price
иabs_diff_from_10
. - Время Заказа - Час: Извлечь час (0-23) из
order_time
для каждого заказа. Отобразитьorder_id
,order_time
иorder_hour
. - Идентификация Заказов за Столиком (Не на Вынос): Использовать
NULLIF
, чтобы вернуть NULL, если заказis_takeaway
равен TRUE. Объединить это с проверкой, чтоtable_number
не NULL, чтобы концептуально идентифицировать заказы не на вынос, назначенные столику. Упрощенная задача: ИспользоватьNULLIF
, чтобы вернуть NULL, еслиtable_number
равен 5. Отобразитьorder_id
,table_number
иnull_if_table5
. - Заказы Следующей Недели (Концептуально): Показать заказы, размещенные в течение последних 7 дней. Отобразить
order_id
,order_time
. Использоватьorder_time >= CURRENT_DATE - INTERVAL '7 day'
. - Форматирование Цены Пункта Меню: Отобразить
item_name
. Создать строкуformatted_price
, добавив префикс ‘$’ кprice
и приведя ее к VARCHAR. (например, ‘$12.50’).
Вариант 11: Сервис объявлений о недвижимости
Сценарий: Вы управляете базой данных для агентства недвижимости, отслеживая объекты недвижимости на продажу, агентов, клиентов и просмотры объектов.
Схема базы данных:
-- Удаление таблиц, если они существуют (необязательно)
-- DROP TABLE IF EXISTS Viewings;
-- DROP TABLE IF EXISTS Clients;
-- DROP TABLE IF EXISTS Agents;
-- DROP TABLE IF EXISTS Properties;
-- 1. Создание таблицы 'Properties'
CREATE TABLE Properties (
property_id SERIAL PRIMARY KEY,
address_line1 VARCHAR(255) NOT NULL, -- Для общего использования
city VARCHAR(100),
postal_code VARCHAR(12), -- Например, ' SW1A 0AA ', для TRIM
property_type VARCHAR(50), -- 'House', 'Apartment', 'Commercial' и т.д. Для CASE
list_price NUMERIC(12, 2), -- Для ROUND, CEIL, ABS
bedrooms INTEGER, -- Для MOD
square_footage INTEGER, -- Для простых числовых операций
list_date DATE NOT NULL, -- Для AGE, EXTRACT
status VARCHAR(20) DEFAULT 'Active' -- 'Active', 'Pending', 'Sold'
);
-- 2. Создание таблицы 'Agents'
CREATE TABLE Agents (
agent_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
middle_name VARCHAR(50), -- Для COALESCE
last_name VARCHAR(50) NOT NULL,
license_number VARCHAR(30) UNIQUE NOT NULL,-- Для LENGTH, SUBSTRING
phone VARCHAR(20),
email VARCHAR(100) UNIQUE NOT NULL, -- Для LOWER
hire_date DATE -- Для AGE
);
-- 3. Создание таблицы 'Clients'
CREATE TABLE Clients (
client_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
phone VARCHAR(20) -- Для REPLACE (очистка)
-- preferred_contact_method VARCHAR(10) NULL -- Не используется в задачах для упрощения
);
-- 4. Создание таблицы 'Viewings'
CREATE TABLE Viewings (
viewing_id SERIAL PRIMARY KEY,
property_id INTEGER NOT NULL REFERENCES Properties(property_id),
client_id INTEGER NOT NULL REFERENCES Clients(client_id),
agent_id INTEGER NOT NULL REFERENCES Agents(agent_id),
viewing_time TIMESTAMP NOT NULL, -- Для EXTRACT, CAST to DATE
client_feedback_score INTEGER -- NULLable, 1-5. Для NULLIF
-- feedback_notes TEXT NULL -- Не используется в задачах
);
-- Вставка образцов данных --
INSERT INTO Properties (address_line1, city, postal_code, property_type, list_price, bedrooms, square_footage, list_date, status) VALUES
('10 Downing St', 'London', ' SW1A 2AA ', 'House', 15000000.00, 10, 5000, '2023-01-15', 'Active'),
('221B Baker St', 'London', 'NW1 6XE', 'Apartment', 1200000.50, 3, 1500, '2023-03-01', 'Active'),
('1600 Pennsylvania Ave NW', 'Washington', ' 20500', 'House', 40000000.00, 132, 55000, '2022-11-10', 'Pending'), -- Пробел в почтовом коде
('1 Privet Drive', 'Little Whinging', ' GU15 3EJ', 'House', 350000.75, 4, 1200, '2023-05-20', 'Sold'), -- Пробел
('42 Wallaby Way', 'Sydney', ' NSW 2000 ', 'Commercial', 850000.00, 0, 2500, '2023-07-01', 'Active'); -- Пробелы
INSERT INTO Agents (first_name, middle_name, last_name, license_number, phone, email, hire_date) VALUES
('James', 'Tiberius', 'Kirk', 'NCC-1701-A', '555-1234', 'j.kirk@starfleet.org', '2018-04-01'),
('Jean-Luc', NULL, 'Picard', 'NCC-1701-D', '555-5678', 'jl.picard@starfleet.org', '2015-09-01'),
('Kathryn', 'Janeway', 'V', 'NCC-74656', '555-9101', 'K.JANEWAY@starfleet.org', '2019-11-15');
INSERT INTO Clients (first_name, last_name, email, phone) VALUES
('Frodo', 'Baggins', 'frodo@shire.net', '123-456-7890'),
('Samwise', 'Gamgee', 'sam.gamgee@shire.net', '123-456-7891'),
('Luke', 'Skywalker', 'luke@rebellion.org', '(987) 654-3210'),
('Leia', 'Organa', 'leia.organa@rebellion.org', NULL);
INSERT INTO Viewings (property_id, client_id, agent_id, viewing_time, client_feedback_score) VALUES
(1, 1, 2, '2023-02-10 14:00:00', 4),
(2, 3, 1, '2023-03-15 11:00:00', 5),
(2, 4, 1, '2023-03-18 15:30:00', NULL),
(4, 2, 3, '2023-06-01 10:00:00', 3),
(5, 1, 2, '2023-08-05 16:00:00', 2);
Задачи для Варианта 11:
- Отображение полного имени агента: Показать
agent_id
,first_name
,last_name
. ИспользоватьCOALESCE
для отображенияmiddle_name
; если NULL, показать пустую строку ‘’. Объединить имя, отчество (если есть) и фамилию вfull_name
. - Очистка почтового индекса объекта: Отобразить
property_id
иpostal_code
. Очиститьpostal_code
, удалив начальные/конечные пробелы и преобразовав его в верхний регистр. Псевдоним:clean_postal_code
. - Стаж агента: Рассчитать, как долго каждый агент работает в агентстве на
CURRENT_DATE
. Отобразитьagent_id
,hire_date
и рассчитанныйtenure
. - Категоризация цены объекта: Отобразить
property_id
,list_price
. Классифицировать по цене: ‘Affordable’, если < 500 000, ‘Mid-Range’, если от 500 000 до 1 999 999,99, ‘Luxury’, если >= 2 000 000. Псевдоним:price_category
. - Стандартизированные email агентов: Показать
agent_id
иemail
, убедившись, чтоemail
полностью в нижнем регистре. Псевдоним:standard_email
. - Возраст объявления объекта: Рассчитать, сколько дней объект находится в списке (от
list_date
доCURRENT_DATE
). Отобразитьproperty_id
,list_date
и разницу в днях. (Подсказка:CURRENT_DATE - list_date
). Псевдоним:days_on_market
. - Проверка длины номера лицензии: Отобразить
agent_id
,license_number
иLENGTH
license_number
. Псевдоним:license_length
. - Просмотры в этом году: Найти просмотры, которые произошли в текущем календарном году. Отобразить
viewing_id
,viewing_time
. ИспользоватьEXTRACT(YEAR FROM viewing_time) = EXTRACT(YEAR FROM CURRENT_DATE)
. - Цена, округленная вверх (до ближайшего миллиона): Отобразить
property_id
,list_price
. Показатьlist_price
, округленную ВВЕРХ до ближайшего миллиона. Псевдоним:price_ceil_million
. (Подсказка: Разделить на 1 000 000, использоватьCEIL
, затем умножить обратно). - Извлечение последних 4 цифр телефона (концептуально): Для клиентов с номером телефона извлечь последние 4 цифры. Отобразить
client_id
,phone
. (Подсказка: ИспользуйтеSUBSTRING
иLENGTH
. Требуется предположение о формате телефона или предварительная очистка). Упрощенная задача: Извлечь первые 3 символаfirst_name
. Псевдоним:name_prefix
. - Абсолютная разница цены от средней: Предположим, что средняя цена объекта недвижимости составляет 1 000 000 долларов. Рассчитать абсолютную разницу между
list_price
каждого объекта и этим средним значением. Отобразитьproperty_id
,list_price
иabs_diff_from_avg
. - Четное/Нечетное количество спален: Определить, имеет ли объект нечетное или четное количество спален. Отобразить
property_id
,bedrooms
и ‘Odd’ или ‘Even’ какbedroom_parity
. Обработать NULLbedrooms
. - NULL оценки отзывов: Использовать
NULLIF
, чтобы вернуть NULL, еслиclient_feedback_score
для просмотра равен 3. Отобразитьviewing_id
,client_feedback_score
иnull_if_score_3
. - Очистка номера телефона клиента: Отобразить
client_id
,phone
. ИспользоватьREPLACE
для удаления символов(
,)
и-
из номера телефона. Псевдоним:clean_phone
. - Заполнение Agent ID: Отобразить
agent_id
в формате 4-значной строки с ведущими нулями (например, 1 становится ‘0001’). Псевдоним:formatted_agent_id
. (Подсказка:LPAD
иCAST
).
Вариант 12: Членство в спортзале и бронирование классов
Сценарий: Вы управляете базой данных фитнес-центра, отслеживая членов, тренеров, фитнес-классы и бронирования классов.
Схема базы данных:
-- Удалить таблицы, если они существуют (необязательно)
-- DROP TABLE IF EXISTS Bookings;
-- DROP TABLE IF EXISTS Classes;
-- DROP TABLE IF EXISTS Trainers;
-- DROP TABLE IF EXISTS Members;
-- 1. Создать таблицу 'Members' (Члены)
CREATE TABLE Members (
member_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE, -- Для LOWER
date_of_birth DATE, -- Для AGE, EXTRACT
join_date DATE NOT NULL, -- Для AGE, EXTRACT
membership_type VARCHAR(20), -- 'Basic', 'Premium', 'VIP', NULL. Для COALESCE, CASE
emergency_contact_name VARCHAR(100) NULL -- Для COALESCE
);
-- 2. Создать таблицу 'Trainers' (Тренеры)
CREATE TABLE Trainers (
trainer_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
specialization VARCHAR(100), -- Для общих запросов
certification_code VARCHAR(20) UNIQUE, -- например, ' ACSM-CPT ', для TRIM
years_experience INTEGER -- Для числовых операций
);
-- 3. Создать таблицу 'Classes' (Классы)
CREATE TABLE Classes (
class_id SERIAL PRIMARY KEY,
class_name VARCHAR(100) NOT NULL, -- Для UPPER, SUBSTRING
trainer_id INTEGER REFERENCES Trainers(trainer_id),
schedule_time TIME NOT NULL, -- Для EXTRACT
schedule_day VARCHAR(10) NOT NULL, -- 'Monday', 'Tuesday', и т.д.
duration_minutes INTEGER NOT NULL, -- Для ROUND, CEIL, FLOOR
max_capacity INTEGER NOT NULL,
difficulty_level VARCHAR(15) -- 'Beginner', 'Intermediate', 'Advanced'. Для NULLIF
);
-- 4. Создать таблицу 'Bookings' (Бронирования)
CREATE TABLE Bookings (
booking_id SERIAL PRIMARY KEY,
member_id INTEGER NOT NULL REFERENCES Members(member_id),
class_id INTEGER NOT NULL REFERENCES Classes(class_id),
booking_time TIMESTAMP DEFAULT NOW(), -- Для операций с датой/временем
attendance_status VARCHAR(15) DEFAULT 'Booked', -- 'Booked', 'Attended', 'Cancelled', 'No-Show'. Для CASE
waitlist_position INTEGER NULL -- Для COALESCE
);
-- Вставка образцов данных --
INSERT INTO Members (first_name, last_name, email, date_of_birth, join_date, membership_type, emergency_contact_name) VALUES
('Arnold', 'Schwarzenegger', 'arnold@gov.com', '1947-07-30', '2020-01-10', 'VIP', 'Maria Shriver'),
('Dwayne', 'Johnson', 'TheRock@wwe.net', '1972-05-02', '2021-06-15', 'Premium', NULL),
('Jane', 'Fonda', 'jane.fonda@workout.com', '1937-12-21', '2022-03-01', 'Basic', 'Ted Turner'),
('Richard', 'Simmons', 'richard@sweatintotheoldies.org', '1948-07-12', '2022-08-20', NULL, 'Self'); -- NULL type
INSERT INTO Trainers (first_name, last_name, specialization, certification_code, years_experience) VALUES
('Jillian', 'Michaels', 'HIIT, Weight Loss', ' NASM-CPT ', 15), -- Пробелы
('Bob', 'Harper', 'CrossFit, Strength Training', 'CF-L1', 20),
('Tony', 'Horton', 'Functional Fitness, P90X', 'ACE-GFI', 25);
INSERT INTO Classes (class_name, trainer_id, schedule_time, schedule_day, duration_minutes, max_capacity, difficulty_level) VALUES
('Morning Yoga', 1, '07:00:00', 'Monday', 60, 20, 'Beginner'),
('Lunchtime HIIT', 1, '12:15:00', 'Wednesday', 45, 15, 'Intermediate'),
('Evening CrossFit', 2, '18:00:00', 'Tuesday', 75, 10, 'Advanced'),
('Total Body Conditioning', 3, '09:00:00', 'Friday', 55, 25, NULL), -- NULL difficulty
('Spin Cycle Express', 2, '17:30:00', 'Thursday', 30, 18, 'Intermediate');
INSERT INTO Bookings (member_id, class_id, booking_time, attendance_status, waitlist_position) VALUES
(1, 3, '2023-10-20 10:00:00', 'Booked', NULL),
(2, 2, '2023-10-21 11:00:00', 'Attended', NULL),
(3, 1, '2023-10-22 12:00:00', 'Booked', NULL),
(1, 5, '2023-10-23 13:00:00', 'Cancelled', NULL),
(4, 1, '2023-10-24 14:00:00', 'Booked', 1), -- В листе ожидания
(2, 3, '2023-10-25 15:00:00', 'No-Show', NULL);
Задания для варианта 12:
- Полное имя участника: Отобразите
member_id
,first_name
,last_name
и объедините их вfull_name
. - Аббревиатура названия класса: Покажите
class_id
и первые 15 символовclass_name
. Присвойте псевдонимshort_class_name
. - Очистка кода сертификации тренера: Отобразите
trainer_id
иcertification_code
, удалив любые начальные или конечные пробелы. Присвойте псевдонимclean_cert_code
. - Продолжительность класса в часах (округленно): Покажите
class_id
,duration_minutes
. Вычислите продолжительность в часах (duration_minutes / 60.0
) и округлите ее до 1 десятичного знака. Присвойте псевдонимduration_hours
. - Расчет возраста участника: Вычислите текущий возраст каждого участника на основе
date_of_birth
. Отобразитеmember_id
,first_name
,date_of_birth
и вычисленныйage
. - Продолжительность членства: Рассчитайте, как долго каждый участник является членом спортзала (от
join_date
доCURRENT_DATE
). Отобразитеmember_id
,join_date
иmembership_length
, используяAGE()
. - Действительный тип членства: Отобразите
member_id
,first_name
. ИспользуйтеCOALESCE
, чтобы отобразитьmembership_type
; если NULL, отобразите ‘Standard’. Присвойте псевдонимeffective_type
. - Сводка статуса бронирования: Отобразите
booking_id
,attendance_status
. Создайтеstatus_summary
: ‘Present’, еслиattendance_status
равен ‘Attended’, ‘Absent’, если ‘No-Show’ или ‘Cancelled’, ‘Upcoming’, если ‘Booked’. - Категоризация времени класса: Отобразите
class_id
,schedule_time
. Создайтеtime_category
: ‘Morning’, если час < 12, ‘Afternoon’, если час равен 12-16, ‘Evening’, если час >= 17. (Подсказка:EXTRACT(HOUR FROM schedule_time)
). - Стандартизированные электронные письма участников: Отобразите
member_id
иemail
во всех строчных буквах. Присвойте псевдонимlower_email
. - Статус листа ожидания: Отобразите
booking_id
. Покажите ‘On Waitlist’, еслиwaitlist_position
NOT NULL, и ‘Confirmed Spot’, еслиwaitlist_position
IS NULL. Присвойте псевдонимspot_status
. Используйте логикуCASE
илиCOALESCE
. - Абсолютная разница опыта: Предположим, что эталоном для тренеров является опыт в 10 лет. Рассчитайте абсолютную разницу между
years_experience
каждого тренера и 10. Отобразитеtrainer_id
,years_experience
,abs_exp_diff
. - Определение классов для начинающих: Используйте
NULLIF
, чтобы вернуть NULL, еслиdifficulty_level
класса равен ‘Beginner’. Отобразитеclass_id
,class_name
,difficulty_level
иnull_if_beginner
. - Форматирование идентификатора участника: Отобразите
member_id
в виде 6-значной строки с ведущими нулями. Присвойте псевдонимformatted_member_id
. - Продолжительность класса, округленная вверх: Отобразите
class_id
,duration_minutes
. Покажите продолжительность, округленную ВВЕРХ до ближайших 10 минут. Присвойте псевдонимduration_ceil_10
. (Подсказка:CEIL(duration_minutes / 10.0) * 10
).
Вариант 13: Аналитика музыкального стримингового сервиса
Сценарий: Вы работаете в музыкальном стриминговом сервисе и вам необходимо проанализировать данные об исполнителях, альбомах, треках и привычках пользователей при прослушивании музыки.
Схема базы данных:
-- Drop tables if they exist (optional)
-- DROP TABLE IF EXISTS listen_history;
-- DROP TABLE IF EXISTS tracks;
-- DROP TABLE IF EXISTS albums;
-- DROP TABLE IF EXISTS artists;
-- 1. Create the 'artists' table
CREATE TABLE artists (
artist_id SERIAL PRIMARY KEY,
artist_name VARCHAR(100) NOT NULL, -- For UPPER, LENGTH, SUBSTRING
country VARCHAR(50), -- For COALESCE
primary_genre VARCHAR(50), -- For CASE, NULLIF
formation_year INTEGER -- For EXTRACT (from date if converted), simple arithmetic
);
-- 2. Create the 'albums' table
CREATE TABLE albums (
album_id SERIAL PRIMARY KEY,
artist_id INTEGER REFERENCES artists(artist_id),
album_title VARCHAR(150) NOT NULL, -- For REPLACE, CONCAT
release_date DATE, -- For AGE, EXTRACT, INTERVAL
label_code VARCHAR(20) UNIQUE -- e.g., ' LBL-001 ', for TRIM
);
-- 3. Create the 'tracks' table
CREATE TABLE tracks (
track_id SERIAL PRIMARY KEY,
album_id INTEGER REFERENCES albums(album_id),
track_title VARCHAR(200) NOT NULL,
track_number INTEGER, -- For simple comparison
duration_seconds INTEGER, -- For numeric functions (ABS, ROUND, CEIL, FLOOR, MOD)
is_explicit BOOLEAN DEFAULT FALSE -- Added for potential CASE usage
);
-- 4. Create the 'listen_history' table (Simplified: assumes user_id exists elsewhere)
CREATE TABLE listen_history (
listen_id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL, -- Assume this user exists in another table
track_id INTEGER REFERENCES tracks(track_id),
listen_timestamp TIMESTAMP NOT NULL DEFAULT NOW() -- For EXTRACT, date/time ops
);
-- Sample Data Insertion --
INSERT INTO artists (artist_name, country, primary_genre, formation_year) VALUES
('The Cosmic Keys', 'USA', 'Psychedelic Rock', 1968),
('SynthWave Riders', 'France', 'Synthwave', 2015),
('Acoustic Echoes', NULL, 'Folk', 2005), -- NULL Country
('DJ Metronome', 'Germany', 'Techno', 1995),
('Lunar Quartet', 'Canada', 'Jazz', 2010);
INSERT INTO albums (artist_id, album_title, release_date, label_code) VALUES
(1, 'Galactic Dreams', '1970-05-20', ' VNYL-001 '),
(2, 'Neon Nights', '2017-11-01', ' ELEC-042'), -- Leading space
(3, 'Whispers in the Wood', '2008-03-15', 'FOLKREC-10'),
(4, 'Rhythm Sequence', '1999-09-09', 'TECHNO-X '), -- Trailing space
(2, 'Future Retro', '2020-08-25', 'ELEC-099 '); -- Trailing space
INSERT INTO tracks (album_id, track_title, track_number, duration_seconds, is_explicit) VALUES
(1, 'Intro Voyage', 1, 125, FALSE),
(1, 'Starlight Serenade', 2, 345, FALSE),
(2, 'City Drive', 1, 280, FALSE),
(2, 'Midnight Run (Explicit Edit)', 4, 310, TRUE), -- Explicit Track
(3, 'Forest Path', 3, 195, FALSE),
(4, 'Beat Pulse', 1, 450, FALSE),
(4, 'System Overload', 5, 390, FALSE),
(5, 'Retrograde Motion', 2, 295, FALSE);
INSERT INTO listen_history (user_id, track_id, listen_timestamp) VALUES
(101, 2, '2023-10-26 08:15:00'),
(102, 3, '2023-10-26 09:00:15'),
(101, 4, '2023-10-26 10:30:00'),
(103, 5, '2023-10-25 14:00:45'),
(102, 7, '2023-10-26 11:05:10'),
(101, 2, '2023-10-24 18:00:00'),
(104, 8, '2023-09-10 20:21:30');
Задачи для Варианта 13:
- Длина имени исполнителя: Отобразите
artist_id
иartist_name
для всех исполнителей, а также длину их имен. Назовите столбец с длинойname_length
. Отсортируйте по длине в порядке убывания. - Форматированные названия треков: Покажите
track_id
иtrack_title
во всех заглавных буквах. Назовите этоupper_title
. - Очищенные коды лейблов: Отобразите
album_id
иlabel_code
для всех альбомов. Удалите все начальные и конечные пробелы изlabel_code
. Назовите очищенный столбецclean_label_code
. - Длительность трека в минутах: Отобразите
track_id
,track_title
иduration_seconds
. Вычислите приблизительную продолжительность в минутах, разделивduration_seconds
на 60 и округлив до 1 знака после запятой. Назовите этоduration_minutes_approx
. - Возраст альбома: Вычислите возраст каждого альбома на основе его
release_date
относительноCURRENT_DATE
. Отобразитеalbum_title
,release_date
и вычисленныйalbum_age
с помощьюAGE()
. - Отображение происхождения исполнителя: Покажите
artist_id
иartist_name
. ИспользуйтеCOALESCE
, чтобы отобразитьcountry
; еслиcountry
имеет значение NULL, отобразите ‘Unknown’. Назовите этот столбецorigin_country
. - Десятилетие формирования: Отобразите
artist_name
иformation_year
. Определите десятилетие формирования (например, 1960-е, 1990-е, 2010-е). Назовите этоformation_decade
. (Подсказка: используйте целочисленное делениеFLOOR(formation_year / 10) * 10
и конкатенацию). - Категории продолжительности трека: Отобразите
track_id
,track_title
иduration_seconds
. Классифицируйте треки по продолжительности: ‘Short’, если < 180 секунд, ‘Medium’, если >= 180 и < 300 секунд, ‘Long’, если >= 300 секунд. Назовите столбецduration_category
. - Идентификатор трека с ненормативной лексикой: Покажите
track_id
,track_title
иis_explicit
. Создайте столбецdisplay_title
, который объединяетtrack_title
с ‘ (Explicit)’, еслиis_explicit
имеет значение TRUE, в противном случае просто покажитеtrack_title
. (Подсказка: используйтеCASE
иCONCAT
/||
). - Час прослушивания: Для каждой записи в
listen_history
извлеките час (0-23) изlisten_timestamp
. Отобразитеlisten_id
,user_id
,track_id
и извлеченныйlisten_hour
. - Сокращенное название альбома: Отобразите
album_id
и первые 20 символовalbum_title
. Назовите этоshort_album_title
. - Время с момента последнего прослушивания: Для каждого прослушанного трека найдите время, прошедшее с момента самого последнего прослушивания, зафиксированного в
listen_history
на моментNOW()
. Отобразитеtrack_id
и вычисленное время с помощьюAGE(MAX(listen_timestamp))
. (Требуется агрегация -GROUP BY track_id
). - Проверка даты выпуска: Добавьте 6 месяцев к
release_date
каждого альбома. Отобразитеalbum_title
,release_date
и вычисленныйrelease_plus_6m
. - Обнуление жанра: Используйте
NULLIF
, чтобы вернуть NULL, еслиprimary_genre
исполнителя - ‘Techno’. В противном случае верните жанр. Отобразитеartist_id
,artist_name
,primary_genre
и результат какnull_if_techno
. - Заполнение Artist ID: Отобразите
artist_id
в формате 6-значной строки с ведущими нулями (например, 1 становится ‘000001’). Назовите этоformatted_artist_id
. (Подсказка: используйтеLPAD
иCAST
).
Вариант 14: Система отслеживания ошибок (Bug Tracking System)
Сценарий: Вы управляете базой данных для отслеживания программных ошибок (bugs), включая затронутые продукты, участвующих разработчиков и статус исправлений.
Схема базы данных:
-- Удаление таблиц, если они существуют (необязательно)
-- DROP TABLE IF EXISTS bug_comments;
-- DROP TABLE IF EXISTS bugs;
-- DROP TABLE IF EXISTS developers;
-- DROP TABLE IF EXISTS products;
-- 1. Создание таблицы 'products'
CREATE TABLE products (
product_id SERIAL PRIMARY KEY,
product_name VARCHAR(100) NOT NULL, -- Для общего справочника
current_version VARCHAR(20), -- Например, ' v2.1.3-RC1 ', для TRIM, REPLACE
release_date DATE -- Для AGE, EXTRACT
);
-- 2. Создание таблицы 'developers'
CREATE TABLE developers (
dev_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL, -- Для LOWER
hire_date DATE, -- Для AGE
skill_level INTEGER -- 1=Младший, 2=Средний, 3=Старший, 4=Ведущий. Для CASE
);
-- 3. Создание таблицы 'bugs'
CREATE TABLE bugs (
bug_id SERIAL PRIMARY KEY,
product_id INTEGER REFERENCES products(product_id),
reported_by_dev_id INTEGER REFERENCES developers(dev_id),
assigned_to_dev_id INTEGER REFERENCES developers(dev_id), -- Допускает NULL
summary VARCHAR(255) NOT NULL, -- Для SUBSTRING, LENGTH
severity INTEGER NOT NULL, -- 1(Низкая) до 5(Критическая). Для ABS, численных операций
status VARCHAR(20) DEFAULT 'New', -- 'New', 'Assigned', 'In Progress', 'Resolved', 'Closed'. Для NULLIF
reported_date TIMESTAMP DEFAULT NOW(), -- Для EXTRACT, операций с датами
resolved_date DATE -- NULL, если не решена. Для COALESCE, AGE, CASE
);
-- 4. Создание таблицы 'bug_comments'
CREATE TABLE bug_comments (
comment_id SERIAL PRIMARY KEY,
bug_id INTEGER REFERENCES bugs(bug_id),
author_dev_id INTEGER REFERENCES developers(dev_id),
comment_text TEXT, -- Для LENGTH
comment_date TIMESTAMP DEFAULT NOW()
);
-- Вставка образцов данных --
INSERT INTO products (product_name, current_version, release_date) VALUES
('Data Analyzer Pro', ' v3.0.1 ', '2022-08-15'),
('Secure Messenger', '1.5.0-beta', '2023-01-20'),
('Cloud Sync Service', ' v2.2.5 ', '2021-11-01');
INSERT INTO developers (first_name, last_name, email, hire_date, skill_level) VALUES
('Ada', 'Lovelace', 'ada.l@code.com', '2020-06-01', 3),
('Charles', 'Babbage', 'charles.b@code.com', '2019-11-15', 4),
('Grace', 'Hopper', 'grace.h@code.com', '2021-03-10', 3),
('Alan', 'Turing', 'Alan.Turing@code.com', '2022-09-01', 2); -- Email в смешанном регистре
INSERT INTO bugs (product_id, reported_by_dev_id, assigned_to_dev_id, summary, severity, status, reported_date, resolved_date) VALUES
(1, 1, 3, 'Incorrect calculation for average function', 4, 'Assigned', '2023-09-10 14:30:00', NULL),
(2, 4, 4, 'UI alignment issue on main screen (iOS only)', 2, 'In Progress', '2023-10-01 09:00:00', NULL),
(1, 2, 1, 'Data export fails for large datasets > 1GB', 5, 'Resolved', '2023-08-20 11:15:00', '2023-09-05'),
(3, 3, NULL, 'Intermittent sync failures under heavy load', 3, 'New', '2023-10-25 16:00:00', NULL), -- Не назначена
(2, 1, 4, 'Typo in welcome message : "Welocme"', 1, 'Resolved', '2023-09-28 10:00:00', '2023-09-29');
INSERT INTO bug_comments (bug_id, author_dev_id, comment_text, comment_date) VALUES
(1, 3, 'Confirmed the issue. Working on a fix.', '2023-09-11 10:00:00'),
(2, 4, 'Reproduced on iPhone 14 simulator. Looks like a constraint problem.', '2023-10-02 14:00:00'),
(3, 1, 'Patch applied and tested. Closing issue.', '2023-09-05 17:00:00'),
(5, 4, 'Fixed the typo. Simple change.', '2023-09-29 09:30:00');
Задания для варианта 14:
- Полное имя и Email разработчика: Отобразите
dev_id
. Создайтеfull_name
, объединивfirst_name
иlast_name
. Отобразитеemail
адрес полностью в нижнем регистре, используя псевдонимlower_email
. - Очищенные версии продукта: Покажите
product_id
,product_name
иcurrent_version
. Очиститеcurrent_version
, удалив начальные/конечные пробелы и заменив дефисы (‘-‘) точками (‘.’). Используйте псевдонимclean_version
для очищенной версии. (Подсказка: ИспользуйтеTRIM
иREPLACE
). - Возраст ошибки (открытые ошибки): Для ошибок, которые не решены или не закрыты (т.е.,
resolved_date
IS NULL), вычислите, как долго они открыты сreported_date
доNOW()
. Отобразитеbug_id
,summary
,reported_date
и вычисленнуюopen_duration
, используяAGE()
. - Описание статуса ошибки: Отобразите
bug_id
иstatus
. Предоставьте более описательный статус, используяCASE
: Если ‘New’, отобразите ‘Ожидает рассмотрения’. Если ‘Assigned’ или ‘In Progress’, отобразите ‘Находится на стадии исследования’. Если ‘Resolved’, отобразите ‘Исправление ожидает проверки’. Если ‘Closed’, отобразите ‘Завершено’. В противном случае отобразите сам статус. Используйте псевдонимstatus_description
. - Уровень квалификации разработчика: Отобразите
dev_id
,first_name
иskill_level
. Создайте столбецskill_name
, используяCASE
, чтобы перевести числовойskill_level
(1=’Младший’, 2=’Средний’, 3=’Старший’, 4=’Ведущий’). - Аббревиатура описания ошибки: Отобразите
bug_id
и первые 50 символовsummary
. Еслиsummary
длиннее 50 символов, добавьте ‘…’. Используйте псевдонимshort_summary
. (Подсказка: ИспользуйтеSUBSTRING
,LENGTH
,CONCAT
/||
). - Округление серьезности в большую сторону: Отобразите
bug_id
иseverity
. Покажитеseverity
, “округленную в большую сторону” до ближайшего кратного 2 (например, 1->2, 2->2, 3->4, 4->4, 5->6). Используйте псевдонимseverity_group
. (Подсказка:CEIL(severity / 2.0) * 2
может сработать, или используйтеCASE
). - Отображение назначенного разработчика: Отобразите
bug_id
иsummary
. ИспользуйтеCOALESCE
, чтобы показатьassigned_to_dev_id
. Если он NULL (не назначен), отобразите 0. Используйте псевдонимassignee_id
. - Месяц и год отчета: Извлеките месяц (числовой) и год из временной метки
reported_date
для каждой ошибки. Отобразитеbug_id
,reported_date
,reported_month
иreported_year
. - Дни до решения: Для ошибок, которые решены или закрыты (
resolved_date
IS NOT NULL), вычислите количество дней междуreported_date
(приведенной к DATE) иresolved_date
. Отобразитеbug_id
,summary
,reported_date
,resolved_date
иdays_to_resolve
. (Подсказка: Вычитание дат). - Абсолютная разница серьезности: Вычислите абсолютную разницу между
severity
каждой ошибки и целевым уровнем серьезности 3. Отобразитеbug_id
,severity
иabs_diff_from_target
. - Возраст продукта: Вычислите возраст каждого продукта на основе его
release_date
относительноCURRENT_DATE
. Отобразитеproduct_name
,release_date
иproduct_age
. - Поиск ошибок, отличных от ‘New’: Используйте
NULLIF
, чтобы вернуть NULL, еслиstatus
ошибки равен ‘New’. В противном случае верните статус. Отобразитеbug_id
,status
и результат какnull_if_new
. - Проверка четности идентификатора ошибки: Определите, является ли
bug_id
четным или нечетным, используя оператор взятия остатка от деления (modulo). Отобразитеbug_id
и ‘Even’ или ‘Odd’ какid_parity
. - Домен электронной почты разработчика: Извлеките имя домена (часть после ‘@’) из адреса электронной почты разработчика
email
. Отобразитеdev_id
,email
иemail_domain
. (Подсказка: ИспользуйтеSUBSTRING
иPOSITION('@' IN email)
).
Вариант 15: Система управления автопарком
Сценарий: Вы управляете базой данных для логистической компании, отслеживая транспортные средства, водителей, поездки и графики технического обслуживания.
Схема базы данных:
-- Удалить таблицы, если они существуют (необязательно)
-- DROP TABLE IF EXISTS maintenance;
-- DROP TABLE IF EXISTS trips;
-- DROP TABLE IF EXISTS vehicles;
-- DROP TABLE IF EXISTS drivers;
-- 1. Создать таблицу 'drivers'
CREATE TABLE drivers (
driver_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
license_number VARCHAR(30) UNIQUE NOT NULL, -- e.g., ' CA-12345-X ', для TRIM, UPPER, REPLACE
hire_date DATE NOT NULL, -- Для AGE, EXTRACT
date_of_birth DATE, -- Для AGE
contact_phone VARCHAR(20) -- e.g., '+1 (555) 123-4567', для REPLACE
);
-- 2. Создать таблицу 'vehicles'
CREATE TABLE vehicles (
vehicle_id SERIAL PRIMARY KEY,
make VARCHAR(50),
model VARCHAR(50),
year INTEGER, -- Для простой арифметики
license_plate VARCHAR(15) UNIQUE NOT NULL, -- e.g., ' 7XYZ123 ', для TRIM, UPPER
purchase_date DATE, -- Для AGE
fuel_capacity_liters NUMERIC(6, 1), -- e.g., 150.5. Для ROUND, CEIL, FLOOR, ABS
last_service_date DATE -- Для COALESCE, INTERVAL
);
-- 3. Создать таблицу 'trips'
CREATE TABLE trips (
trip_id SERIAL PRIMARY KEY,
vehicle_id INTEGER REFERENCES vehicles(vehicle_id),
driver_id INTEGER REFERENCES drivers(driver_id),
start_datetime TIMESTAMP NOT NULL, -- Для EXTRACT, date ops
end_datetime TIMESTAMP, -- NULL, если поездка продолжается. Для COALESCE, AGE, CASE
start_location_code VARCHAR(10), -- e.g., 'WAREHSE-A'
end_location_code VARCHAR(10), -- e.g., 'CLIENT-X'
distance_km NUMERIC(8, 2) -- Для ROUND, ABS
);
-- 4. Создать таблицу 'maintenance'
CREATE TABLE maintenance (
maint_id SERIAL PRIMARY KEY,
vehicle_id INTEGER REFERENCES vehicles(vehicle_id),
service_date DATE NOT NULL,
service_type VARCHAR(50), -- e.g., 'Oil Change', 'Tire Rotation'. Для CASE
cost NUMERIC(7, 2), -- Для ROUND, числовые операции
notes VARCHAR(255) -- Для LENGTH
);
-- Вставка примера данных --
INSERT INTO drivers (first_name, last_name, license_number, hire_date, date_of_birth, contact_phone) VALUES
('Max', 'Rockatansky', ' AU-R0AD-WAR ', '2018-05-15', '1980-11-01', '+61 (4) 5555-1234'),
('Ellen', 'Ripley', ' US-LV426-X ', '2019-09-01', '1975-01-07', '+1 (800) 254-3678'),
('Han', 'Solo', ' DL-44BLASTER ', '2020-01-20', NULL, NULL), -- Отсутствует дата рождения, телефон
('Sarah', 'Connor', ' CA-T800-TERM ', '2021-07-10', '1984-05-12', '+1 (213) 555-1984');
INSERT INTO vehicles (make, model, year, license_plate, purchase_date, fuel_capacity_liters, last_service_date) VALUES
('Ford', 'Falcon XB GT', 1973, ' MFP-008 ', '2018-04-01', 120.0, '2023-08-15'),
('Weyland-Yutani', 'M577 APC', 2179, ' LV-426 ', '2019-08-01', 500.5, '2023-05-01'), -- Год в далеком будущем
('Corellian', 'YT-1300', -20, ' FALCON ', '2019-12-01', 1000.0, NULL), -- Отрицательный год, NULL дата обслуживания
('Jeep', 'Gladiator Rubicon', 2020, ' SKYNET ', '2021-06-15', 83.3, '2023-10-01');
INSERT INTO trips (vehicle_id, driver_id, start_datetime, end_datetime, start_location_code, end_location_code, distance_km) VALUES
(1, 1, '2023-10-20 08:00:00', '2023-10-20 18:30:00', 'BASE-A', 'SITE-B', 450.75),
(2, 2, '2023-10-21 06:00:00', NULL, 'HADLEYS', 'ORBIT', 15.50), -- Поездка продолжается
(3, 3, '2023-10-22 10:00:00', '2023-10-22 10:15:00', 'MOS-EISLEY', 'ANCHORHEAD', 12.20), -- Короткая поездка
(4, 4, '2023-10-23 09:00:00', '2023-10-24 17:00:00', 'LA-2023', 'MEXICO', 2450.00),
(1, 1, '2023-10-25 07:00:00', NULL, 'SITE-B', 'BASE-A', NULL); -- Обратный маршрут продолжается, расстояние неизвестно
INSERT INTO maintenance (vehicle_id, service_date, service_type, cost, notes) VALUES
(1, '2023-08-15', 'Engine Tune-up', 450.00, 'Replaced spark plugs'),
(2, '2023-05-01', 'Armor Repair', 2500.50, 'Welded hull breach'),
(4, '2023-10-01', 'Oil Change', 120.99, 'Standard 5k service'),
(1, '2023-02-10', 'Tire Rotation', 75.00, NULL); -- NULL notes
Задания для Варианта 15:
- Полное имя и номер лицензии водителя: Отобразите
driver_id
. Создайтеfull_name
. Очиститеlicense_number
, удалив пробелы и преобразовав в верхний регистр. Назовите очищенную лицензиюclean_license
. - Очистка номерного знака транспортного средства: Покажите
vehicle_id
,make
,model
. Очиститеlicense_plate
, удалив пробелы и преобразовав в верхний регистр. Назовитеclean_plate
. - Стаж работы водителя: Рассчитайте, как долго каждый водитель работает в компании, используя
hire_date
иCURRENT_DATE
. Отобразитеdriver_id
,full_name
(из задания 1),hire_date
иtenure
с использованиемAGE()
. - Продолжительность поездки: Для завершенных поездок (
end_datetime
IS NOT NULL) рассчитайте продолжительность, используяAGE(end_datetime, start_datetime)
. Отобразитеtrip_id
,start_datetime
,end_datetime
иtrip_duration
. - Возраст транспортного средства: Рассчитайте возраст каждого транспортного средства на основе его
purchase_date
. Отобразитеvehicle_id
,license_plate
,purchase_date
иvehicle_age
. - Последняя проверка обслуживания: Отобразите
vehicle_id
,license_plate
. ИспользуйтеCOALESCE
, чтобы показатьlast_service_date
. Если значение NULL, отобразитеpurchase_date
вместо этого. Назовите этоeffective_last_service
. - Стандартизированный номер телефона: Отобразите
driver_id
иcontact_phone
. Создайтеstandard_phone
, удалив пробелы, скобки()
, дефисы-
и ведущий знак+
. Обработайте возможные NULL-значения (должны оставаться NULL). (Подсказка: Используйте цепочку функцийREPLACE
). - Расстояние в милях: Отобразите
trip_id
,distance_km
. Рассчитайте приблизительное расстояние в милях (1 км = 0.621371 мили) и округлите его до 1 десятичного знака. Назовитеdistance_miles
. Обработайте NULL-значения расстояний. - Округление емкости бака: Отобразите
vehicle_id
,fuel_capacity_liters
. Покажите емкость, округленную ВВЕРХ (CEIL
) и ВНИЗ (FLOOR
) до ближайшего целого литра. Назовитеfuel_ceil_l
иfuel_floor_l
. - Категория стоимости обслуживания: Отобразите
maint_id
,service_type
,cost
. Классифицируйте стоимость, используяCASE
: ‘Low’, если < $100, ‘Medium’, если $100-$500 (включительно), ‘High’, если > $500. Назовитеcost_category
. - День недели начала поездки: Извлеките день недели (например, 0 для воскресенья, 1 для понедельника… или текст, зависящий от БД) из
start_datetime
для каждой поездки. Отобразитеtrip_id
,start_datetime
иstart_dow
. (Подсказка: ИспользуйтеEXTRACT(DOW FROM ...)
или эквивалент). - Абсолютная разница в расстоянии: Рассчитайте абсолютную разницу между
distance_km
каждой поездки и стандартным расстоянием в 100 км. Отобразитеtrip_id
,distance_km
иabs_diff_from_100km
. Игнорируйте поездки с NULL-значением расстояния. - Дата следующего обслуживания: Для каждого транспортного средства рассчитайте дату, которая на 6 месяцев позже, чем
effective_last_service
(из задания 6). Отобразитеvehicle_id
,effective_last_service
иnext_service_due
. (Подсказка: ИспользуйтеINTERVAL
). - Поиск длинных заметок: Используйте
LENGTH
, чтобы найти записи о техническом обслуживании, где полеnotes
длиннее 20 символов. Отобразитеmaint_id
,notes
иnotes_length
. - Четность ID водителя: Проверьте, является ли
driver_id
четным или нечетным, используяMOD
. Отобразитеdriver_id
,full_name
(из задания 1) иid_parity
(‘Odd’ или ‘Even’).
Инструкции по сдаче
- Создайте новый Google Doc. Пример
- Добавьте ссылку на ваш Google Doc здесь: Google Таблица
