На склад поступила партия компьютерных комплектующих из 5 позиций. Схема целевой таблицы:
CREATE TABLE warehouse_stock (
id SERIAL PRIMARY KEY,
sku VARCHAR(30) UNIQUE NOT NULL,
item_name VARCHAR(120) NOT NULL,
stock_quantity INT NOT NULL CHECK (stock_quantity >= 0),
purchase_price NUMERIC(10, 2) NOT NULL,
last_received_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Требование: Напишите единый SQL-запрос INSERT INTO warehouse_stock, осуществляющий пакетную вставку 5 новых позиций с явным перечислением колонок и возвращающий через RETURNING присвоенные идентификаторы id, артикулы sku и метки last_received_at:
'SKU-CPU-01', 'Intel Core i5-13400', 10 шт., 18500.00 руб.'SKU-MB-02', 'ASUS TUF Gaming B760-PLUS', 8 шт., 14200.00 руб.'SKU-RAM-03', 'Kingston Fury DDR5 32GB Kit', 25 шт., 9600.00 руб.'SKU-SSD-04', 'Samsung 980 Pro 1TB NVMe', 15 шт., 8900.00 руб.'SKU-PSU-05', 'DeepCool DQ750-M-V2L 750W', 12 шт., 7800.00 руб.Поступила накладная догрузки: товар с артикулом 'SKU-CPU-01' поступил повторно в количестве 5 штук по скорректированной цене 17900.00 руб.
Требование: Напишите идемпотентный запрос INSERT ... ON CONFLICT (sku) DO UPDATE SET, который:
unique_violation.warehouse_stock.stock_quantity + EXCLUDED.stock_quantity.EXCLUDED.purchase_price.last_received_at = CURRENT_TIMESTAMP.RETURNING колонки id, sku, итоговый остаток stock_quantity и актуальную цену.Объясните, почему использование ON CONFLICT DO UPDATE с псевдотаблицей EXCLUDED является надежнее, чем предварительная проверка наличия товара через SELECT ... WHERE sku = ... в приложении перед вставкой?
В клинике работают две таблицы: приемы врачей и платежные транзакции:
-- Журнал приемов
CREATE TABLE medical_appointments (
appointment_id SERIAL PRIMARY KEY,
patient_id INT NOT NULL,
doctor_id INT NOT NULL,
appointment_status VARCHAR(25) NOT NULL DEFAULT 'AWAITING_PAYMENT',
created_at TIMESTAMP NOT NULL,
confirmed_at TIMESTAMP
);
-- Платежи кассы/онлайн-банка
CREATE TABLE appointment_invoices (
invoice_id SERIAL PRIMARY KEY,
appointment_id INT UNIQUE NOT NULL,
payment_status VARCHAR(20) NOT NULL, -- 'PAID', 'REJECTED', 'PENDING'
payment_time TIMESTAMP NOT NULL
);
Требование: Напишите SQL-запрос UPDATE medical_appointments с использованием секции FROM appointment_invoices, который переводит статус приема в 'CONFIRMED' и заполняет поле confirmed_at = appointment_invoices.payment_time для всех приемов, находящихся в статусе 'AWAITING_PAYMENT', по которым зафиксирован платеж со статусом 'PAID'. Запрос должен возвращать через RETURNING поля appointment_id, patient_id и новый статус.
Согласно регламенту архивации, отмененные приемы (appointment_status = 'CANCELLED'), созданные более 1 года назад (created_at < CURRENT_DATE - INTERVAL '1 year'), подлежат удалению из оперативной базы.
Требование: Составьте запрос DELETE FROM medical_appointments, который удаляет указанные устаревшие отмененные записи и одновременно возвращает через RETURNING поля appointment_id, patient_id, created_at для передачи в журнал аудита службы безопасности.
Почему саму обновляемую таблицу medical_appointments категорически нельзя указывать в списке таблиц секции FROM при выполнении запроса UPDATE в PostgreSQL?
В банке функционирует таблица действующих договоров loan_contracts и архивная таблица loan_contracts_archive:
-- Действующие договоры
CREATE TABLE loan_contracts (
contract_num VARCHAR(24) PRIMARY KEY,
client_id INT NOT NULL,
issued_amount NUMERIC(14, 2) NOT NULL,
current_debt NUMERIC(14, 2) NOT NULL,
status VARCHAR(20) NOT NULL, -- 'ACTIVE', 'OVERDUE', 'CLOSED'
closed_at DATE
);
-- Архивная таблица
CREATE TABLE loan_contracts_archive (
archive_id SERIAL PRIMARY KEY,
contract_num VARCHAR(24) NOT NULL,
client_id INT NOT NULL,
total_settled NUMERIC(14, 2) NOT NULL,
archived_date DATE NOT NULL DEFAULT CURRENT_DATE
);
Требование: Напишите SQL-запрос INSERT INTO loan_contracts_archive (...) SELECT ..., который осуществляет перенос всех договоров со статусом 'CLOSED' и датой закрытия старше 1 года (closed_at < CURRENT_DATE - INTERVAL '1 year'). Укажите явные списки столбцов и свяжите поля contract_num, client_id, issued_amount (в качестве total_settled).
В конце расчетного дня банк производит начисление процентов по всем активным договорам (status = 'ACTIVE' с остатком долга current_debt > 0). Дневная ставка составляет 0.05% от текущего долга (current_debt * 0.0005).
Требование: Напишите запрос UPDATE loan_contracts, который прибавляет рассчитанные дневные проценты к сумме current_debt только по активным договорам и возвращает через RETURNING перечень обновленных contract_num, client_id и новую задолженность current_debt.
В чем заключается опасность выполнения массового UPDATE по миллиону договоров в единой длинной транзакции в высоконагруженной системе? Как эта операция повлияет на журнал предзаписи WAL и фоновый процесс VACUUM?
В электронной ведомости действует таблица оценок с составным ограничением уникальности:
CREATE TABLE student_grades (
grade_id SERIAL PRIMARY KEY,
student_id INT NOT NULL,
discipline_id INT NOT NULL,
grade_value INT NOT NULL CHECK (grade_value BETWEEN 2 AND 5),
teacher_id INT NOT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_student_discipline UNIQUE (student_id, discipline_id)
);
Требование: Напишите запрос INSERT INTO student_grades, выставляющий студенту student_id = 45 по дисциплине discipline_id = 8 оценку grade_value = 5 от преподавателя teacher_id = 12:
ON CONFLICT (student_id, discipline_id) DO UPDATE SET.grade_value = EXCLUDED.grade_value, актуализировать teacher_id = EXCLUDED.teacher_id и выставить assigned_at = CURRENT_TIMESTAMP.RETURNING колонки grade_id, student_id, grade_value, assigned_at.Таблица регистрации студентов на портале содержит записи о заявках:
CREATE TABLE portal_registration_requests (
request_id SERIAL PRIMARY KEY,
email VARCHAR(100) NOT NULL,
is_email_verified BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL
);
Требование: Составьте запрос DELETE FROM portal_registration_requests, который удаляет все профили, у которых email не был подтвержден (is_email_verified = FALSE) и с момента регистрации прошло более 30 дней (created_at < CURRENT_TIMESTAMP - INTERVAL '30 days'). Запрос должен возвращать через RETURNING список удаленных email для логирования.
Сравните физические последствия выполнения DELETE FROM student_grades; и TRUNCATE TABLE student_grades; с точки зрения сброса счетчика автоинкремента grade_id и блокировок других пользователей портала.