JavaRush /Курсы /SQL SELF /Типичные ошибки при работе с данными

Типичные ошибки при работе с данными

SQL SELF
22 уровень , 4 лекция
Открыта

Работа с базой данных — как та жизнь программиста: полна неожиданностей. Даже самый опытный разработчик может совершить ошибку, будь то случайное удаление данных, попытка вставить дубликат или нарушение ограничений целостности. Но важно не только избегать таких ошибок, но и знать, как их исправить, если вдруг они произошли. Давайте рассмотрим несколько самых типичных ошибок.

Ошибка №1: Нехватка условия WHERE

Самая классическая ошибка, которую совершают новички (и, давайте будем честны, иногда даже опытные разработчики), — это забыть добавить WHERE в запрос на обновление или удаление данных. Запросы без WHERE обновляют или удаляют все строки таблицы.

-- Пример, как не надо делать:
UPDATE students SET status = 'graduated';

-- Или вот так:
DELETE FROM students;

Последствия: представьте, что после выполнения такого запроса вы обнаруживаете, что ваша таблица students, содержащая все данные о студентах, опустела. И самое неприятное — данные не вернуть, если у вас нет резервной копии или использовались транзакции (и даже тогда это уже стресс).

Как избежать: всегда добавляйте условия в запросы UPDATE и DELETE, чтобы точно определить, какие строки вы хотите изменить или удалить.

-- Как надо делать:
UPDATE students
SET status = 'graduated'
WHERE year_of_study = 4;

DELETE FROM students
WHERE status = 'expelled';

Ещё один трюк — перед выполнением операции удаления всегда запускайте SELECT, чтобы убедиться, что условие правильно настроено:

-- Вначале проверяем:
SELECT * FROM students WHERE status = 'expelled';

-- Затем выполняем удаление:
DELETE FROM students WHERE status = 'expelled';

Ошибка №2: Нарушение уникальности данных (UNIQUE)

Если на таблицу наложено ограничение UNIQUE, то попытка вставить дубликат закончится ошибкой.

-- Ошибка из-за дублирования email:
INSERT INTO students (name, email) VALUES ('Otto Lin', 'otto.lin@email.com');
INSERT INTO students (name, email) VALUES ('Peter Pen', 'otto.lin@email.com');

Ошибка:

ERROR: duplicate key value violates unique constraint "students_email_key"

Как избежать: перед вставкой данных нужно проверить, нет ли уже строки с такими же значениями.

-- Один из подходов:
SELECT * FROM students WHERE email = 'otto.lin@email.com';

-- Или же использовать конструкцию UPSERT:
INSERT INTO students (name, email)
VALUES ('Peter Pen', 'otto.lin@email.com')
ON CONFLICT (email) DO NOTHING;

Ошибка №3: Нарушение ограничений целостности (FOREIGN KEY)

Предположим, у вас есть две таблицы: students и enrollments, где student_id в таблице enrollments связан внешним ключом с id таблицы students. Если вы попытаетесь вставить запись в таблицу enrollments, указав student_id, которого нет в таблице students, получите ошибку.

INSERT INTO enrollments (student_id, course_id)
VALUES (999, 101); -- Ошибка, потому что student_id 999 не существует

Как избежать?

  1. Всегда проверяйте наличие записи в родительской таблице перед вставкой в связанную таблицу:
SELECT * FROM students WHERE id = 999;
  1. Используйте ограничение ON DELETE CASCADE, чтобы записи в связанных таблицах автоматически удалялись при удалении записи из родительской таблицы (но с осторожностью).
CREATE TABLE enrollments (
    id SERIAL PRIMARY KEY,
    student_id INT REFERENCES students(id) ON DELETE CASCADE,
    course_id INT
);

Ошибка №4: Неверные типы данных

При вставке или обновлении данных PostgreSQL строго проверяет совместимость типов данных. Если вы попытаетесь вставить строку в числовое поле, получите ошибку.

-- Ошибка из-за несовместимости типов:
INSERT INTO students (id, name) VALUES ('abc', 'Alex Go');

Ошибка:

ERROR: invalid input syntax for type integer

Как избежать? Следите за типами данных во вставляемых значениях. Если данные приходят из формы пользователя, обязательно валидируйте их на стороне приложения.

Ошибка №5: Проблемы с параллельным доступом (утечка данных)

Представьте, что два пользователя одновременно пытаются обновить одну и ту же запись в таблице. Без надлежащей изоляции транзакций велика вероятность возникновения конфликтов.

-- Пользователь A:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- Пользователь B:
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 1;

Как избежать? Используйте транзакции и уровни изоляции, чтобы предотвратить одновременное изменение данных.

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

Ошибка №6: Потеря данных из-за TRUNCATE

TRUNCATE удаляет все строки из таблицы без возможности восстановления, так как для этой команды не предусмотрена поддержка ROLLBACK (она не вызывает триггеры и выполняется мгновенно).

-- Удаляет всё безвозвратно:
TRUNCATE TABLE students;

Как избежать: используйте DELETE с условием вместо TRUNCATE, если нужно сохранить возможность отката.

BEGIN;
DELETE FROM students WHERE year_of_study = 1;
-- Если передумали:
ROLLBACK;

Ошибка №7: Отсутствие транзакций для важных операций

Если выполняется сложная операция, состоящая из нескольких шагов, и в её середине возникает ошибка, данные могут остаться в неконсистентном состоянии.

-- Шаг 1: добавляем студента
INSERT INTO students (name, email) VALUES ('Otto Lin', 'otto.lin@email.com');

-- Шаг 2: записываем его на курс
INSERT INTO enrollments (student_id, course_id) VALUES (LASTVAL(), 101); -- ошибка

Как избежать? Упакуйте такие операции в транзакцию:

BEGIN;

INSERT INTO students (name, email) VALUES ('Иван Иванов', 'ivan.ivanov@email.com');
INSERT INTO enrollments (student_id, course_id) VALUES (LASTVAL(), 101);

COMMIT;

Если на любом этапе возникнет ошибка, вы можете откатить изменения:

ROLLBACK;

Ошибка №8: Случайная работа с NULL

NULL часто приводит к сюрпризам, так как он не равен ни нулю, ни пустой строке, и сравнения с ним могут дать неожиданные результаты.

-- Это не сработает:
SELECT * FROM students WHERE email = NULL;

Как избежать? Используйте IS NULL или IS NOT NULL:

SELECT * FROM students WHERE email IS NULL;

Типичные ошибки неизбежны, но зная, как их распознать и как их избежать, вы сможете выполнять операции с данными безопасно и эффективно. PostgreSQL — строгий, но справедливый страж ваших данных, и он всегда готов вернуть ошибку, если что-то пошло не так. Просто помните, что ошибки — это не враги, а учителя.

2
Задача
SQL SELF, 22 уровень, 4 лекция
Недоступна
Предотвращение удаления всех данных
Предотвращение удаления всех данных
1
Опрос
Введение в транзакции, 22 уровень, 4 лекция
Недоступен
Введение в транзакции
Введение в транзакции
Комментарии (5)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Slevin Уровень 64
14 сентября 2025
Ошибка №6: Потеря данных из-за TRUNCATE TRUNCATE удаляет все строки из таблицы без возможности восстановления, так как для этой команды не предусмотрена поддержка ROLLBACK (она не вызывает триггеры и выполняется мгновенно). А ЭТО НЕПРАВДА! TRUNCATE прекрасно откатывается, если выполняется в рамках ТРАНСАКЦИИ и до того как был выполнен COMMIT И в этом можно убедиться! Переключите IDE в режим ручного управления трансакциями: и напишите например такой код для существующей непустой таблицы:

begin;
truncate students;
select * from students;
и вы увидите что таблица очистилась. Теперь выполните ROLLBACK через кнопку (там рядом с Tx:Manual - стрелка против часовой) и проверьте что есть в вашей таблице снова. Данные будут на месте По этой ошибке вообще полный бред написан. Ибо дальше приведен пример, что надо обязательно писать через DELETE в рамках трансакции, чтобы можно было сделать ROLLBACK ТЕСТ 7й вопрос: Как обрабатывается команда TRUNCATE в PostgreSQL? Правильный ответ не верен - TRUNCATE поддерживает ROLLBACK Из документации: https://www.postgresql.org/docs/current/sql-truncate.html "TRUNCATE is transaction-safe with respect to the data in the tables: the truncation will be safely rolled back if the surrounding transaction does not commit."
Евгений Уровень 49 Expert
11 августа 2025
Кажется, в тесте ошибка. ON CONFLICT не может также обрабатывать нарушения внешнего ключа, согласно документации https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT. ON CONFLICT can be used to specify an alternative action to raising a unique constraint or exclusion constraint violation error - речь о том, что обрабатываются ошибки уникальности или ошибки специального exclusion constraint, который не относится к внешним ключам.
Ra Уровень 35 Student
31 июля 2025
Примеры кода, где NULL может вызвать неожиданные проблемы в SQL (на примере PostgreSQL): 1. Сравнение с NULL через = (банально) 2. Проверка IN с NULL - SELECT * FROM users WHERE id IN (1, 2, NULL); -- Не найдёт записи, если есть хотя бы один id=NULL Правильно: SELECT * FROM users WHERE id IN (1, 2) OR id IS NULL; 3. NOT IN с NULL - SELECT * FROM users WHERE id NOT IN (1, 2, NULL); -- ВООБЩЕ НИЧЕГО не вернёт! Правильно: - SELECT * FROM users WHERE id NOT IN (1, 2) AND id IS NOT NULL; 4. COUNT(*) считает все строки, а COUNT(column) — только не-NULL значения. (банально) 5. GROUP BY и NULL - SELECT category, COUNT(*) FROM items GROUP BY category; -- NULL будет отдельной группой 6. DISTINCT и NULL - SELECT DISTINCT email FROM users; -- NULL учитывается как отдельное значение 7. ORDER BY с NULL - SELECT * FROM tasks ORDER BY due_date; -- NULL будут в конце (по умолчанию) Контроль сортировки: SELECT * FROM tasks ORDER BY due_date NULLS FIRST; 8. JOIN с NULL SELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id WHERE orders.user_id IS NULL; -- Найдёт пользователей без заказов 9. Условные выражения (CASE) SELECT name, CASE WHEN discount IS NULL THEN price ELSE price * (1 - discount) END AS final_price FROM products; 10. Функции работы с NULL SELECT COALESCE(NULL, NULL, 'default'); -- 'default' SELECT NULLIF(10, 10); -- NULL SELECT GREATEST(5, NULL, 10); -- NULL 11. Уникальные ограничения - CREATE TABLE tags (name TEXT UNIQUE); -- Разрешает несколько NULL (в PostgreSQL) 12. Проверочные ограничения (CHECK) - ALTER TABLE users ADD CONSTRAINT age_check CHECK (age > 0); -- NULL пропустит! Правильно: CHECK (age IS NULL OR age > 0); 13. Оконные функции (PARTITION BY) - SELECT id, RANK() OVER (PARTITION BY department ORDER BY salary NULLS LAST) FROM employees; 14. Регулярные выражения - SELECT * FROM logs WHERE message ~ NULL; -- Всегда NULL 15. Массивы и JSON - SELECT '[1, null, 3]'::jsonb -> 1; -- Вернёт `null` (но это JSON-null, а не SQL-NULL)
Никита Иванов Уровень 25
15 июля 2025
Про уровни изоляции поговорим позже, но в тесте все равно спросим кто же все таки нас спасет от фантомных чтений?
Ra Уровень 35 Student
31 июля 2025
да, вопрос 6 гениален 🤣👍 7,8 вопрос c триггерами тоже из этой оперы