У меня есть две таблицы БД в отношении "один ко многим". Данные выглядят так:
select * from student, application
Resultset :
+-----------+---------------+---------------------+
| StudentID | ApplicationID | ApplicationDateTime |
+-----------+---------------+---------------------+
| 1 | 20001 | 12 April 2011 |
| 1 | 20002 | 15 May 2011 |
| 2 | 20003 | 02 Feb 2011 |
| 2 | 20004 | 13 March 2011 |
| 2 | 20005 | 05 June 2011 |
+-----------+---------------+---------------------+
Я хочу удалить все приложения, кроме самого последнего. Другими словами, с каждым студентом должно быть связано только одно приложение. В приведенном выше примере данные должны выглядеть так:
+-----------+---------------+---------------------+
| StudentID | ApplicationID | ApplicationDateTime |
+-----------+---------------+---------------------+
| 1 | 20002 | 15 May 2011 |
| 2 | 20005 | 05 June 2011 |
+-----------+---------------+---------------------+
Как мне построить оператор DELETE, чтобы отфильтровать правильные записи?
3 ответа
DELETE FROM student
WHERE ApplicationDateTime <> (SELECT max(ApplicationDateTime)
FROM student s2
WHERE s2.StudentID = student.StudentID)
Учитывая долгое обсуждение в комментариях, обратите внимание на следующее:
Вышеупомянутый оператор будет работать в любой базе данных, которая должным образом реализует согласованность чтения на уровне операторов, независимо от любых изменений в таблице во время выполнения оператора.
Базы данных, в которых я точно знаю, что это работает правильно даже с одновременными модификациями таблицы: Oracle (тот, о котором идет речь в этом вопросе), Postgres, SAP HANA, Firebird (и, скорее всего, MySQL, использующий InnoDB). Потому что все они гарантируют непротиворечивое представление данных в момент начала выполнения оператора. Изменение <>
на <
ничего не изменит для них (включая Oracle, о котором идет речь в этом вопросе)
Для вышеупомянутых баз данных оператор не подчиняется уровню изоляции, поскольку фантомные чтения или неповторяющиеся чтения могут происходить только между несколькими операторами, а не внутри одиночный оператор.
Для базы данных, которая не реализует должным образом MVCC и полагается на блокировку для управления параллелизмом (таким образом, блокируя одновременный доступ на запись), это может фактически привести к неверным результатам, если таблица обновляется одновременно. Для них, вероятно, потребуется обходной путь с использованием <
.
Вы можете использовать row_number()
(или rank()
или dense_rank()
, или даже просто псевдоколонку rownum
), чтобы применить порядок к записям, а затем использовать этот порядок, чтобы решить, какой отказаться. В этом случае сортировка по applicationdatetime desc
дает приложению с самой последней датой для каждого студента рейтинг 1:
select studentid, applicationid from (
select studentid, applicationid,
row_number() over (partition by studentid
order by applicationdatetime desc) as rn
from application
)
where rn = 1;
STUDENTID APPLICATIONID
---------- -------------
1 20002
2 20005
Затем вы можете удалить все, что имеет рейтинг выше 1, что сохранит нужные вам записи:
delete from application
where (studentid, applicationid) in (
select studentid, applicationid from (
select studentid, applicationid,
row_number() over (partition by studentid
order by applicationdatetime desc) as rn
from application
)
where rn > 1
);
3 rows deleted.
Сначала вы можете это сделать
DELETE FROM [student]
or [application]
WHERE (studentid, applicationid) NOT IN (SELECT StudentID
,MAX(ApplicationID)
FROM student
,application
group by StudentID);
Но есть другое решение, вы можете создать резервную копию таблицы после удаления всех записей в ваших таблицах и после вставки ваших данных (что вы хотите) с максимальными значениями, выбранными в ваших таблицах.
Похожие вопросы
Связанные вопросы
Новые вопросы
sql
Язык структурированных запросов (SQL) - это язык запросов к базам данных. Вопросы должны включать примеры кода, структуру таблицы, примеры данных и тег для используемой реализации СУБД (например, MySQL, PostgreSQL, Oracle, MS SQL Server, IBM DB2 и т. Д.). Если ваш вопрос относится исключительно к конкретной СУБД (использует определенные расширения / функции), используйте вместо этого тег этой СУБД. Ответы на вопросы, помеченные SQL, должны использовать стандарт ISO / IEC SQL.