Я не понимаю, почему вы используете JOIN
, когда это выглядит так просто:
DELETE FROM subject_class WHERE subject_id = previous_subject_id
?
Кроме того, 285 000 строк - это не большое количество, и производительность должна быть в порядке. Однако 285 000 * 285 000 (81 млрд.) - это большое число, и это, по сути, то, с чем должен работать ваш запрос с JOIN
.
Хорошо, теперь у нас проблема. В реляционной базе данных нет понятия «первый» или «последний». Строки не имеют какого-либо внутреннего порядка, если вы не скажете им что-то для заказа. В вашем примере вы визуально выбрали две строки, чтобы исключить их из списка исключительно на том основании, что когда вы их перечисляете, это порядок, в котором они появляются. Однако этот порядок совершенно недетерминирован c. На самом деле это, скорее всего, тот порядок, в котором данные были вставлены в кучу (неиндексированная таблица), но это практически невозможно воспроизвести, и это выходит за рамки этого вопроса.
Что я могу сделать, так это предоставить детерминированный c способ удаления строк. Поскольку это более сложно, я настрою некоторые тестовые данные:
DECLARE @subject_class TABLE (
subject_id INT,
subject_name VARCHAR(20),
[standard] VARCHAR(20),
[rank] INT,
previous_subject_id INT);
INSERT INTO @subject_class SELECT 13, 'ABC', '1st', 1, 21;
INSERT INTO @subject_class SELECT 13, 'ABC', '1st', 1, 23;
INSERT INTO @subject_class SELECT 13, 'ABC', '1st', 1, 13;
INSERT INTO @subject_class SELECT 25, 'def', '3rd', 6, 42;
INSERT INTO @subject_class SELECT 25, 'def', '3rd', 6, 25;
INSERT INTO @subject_class SELECT 25, 'def', '3rd', 6, 28;
Это в основном ваши настройки, данные, которые вы перечислили в таблице без индекса.
Первая часть прост:
DELETE FROM @subject_class WHERE subject_id = previous_subject_id; --fixes 2 records
Вторая часть немного сложнее, поэтому я использую выражение общей таблицы:
WITH cte AS (
SELECT
subject_id,
MIN(previous_subject_id) AS min_previous_subject_id
FROM
@subject_class
GROUP BY
subject_id)
DELETE
s
FROM
@subject_class s
INNER JOIN cte c ON c.subject_id = s.subject_id AND c.min_previous_subject_id != s.previous_subject_id;
SELECT * FROM @subject_class;
Это работает, сначала определив минимум previous_subject_id
для каждого subject_id
и предполагая, что это единственный, который мы хотим сохранить. Есть много других способов сделать это, вы можете выбрать наибольшее значение или придумать более сложное правило.
Это не даст вам того, о чем вы просили, вместо этого вы получите результат:
subject_id subject_name standard rank previous_subject_id
13 ABC 1st 1 21
25 def 3rd 6 28
Однако это определенно c, поскольку вы будете получать один и тот же результат при каждом выполнении запроса.
Вы хотели, чтобы запрос удалял только те строки, где было найдено совпадение в «других» полях, так что вот так:
DECLARE @subject_class TABLE (
subject_id INT,
subject_name VARCHAR(20),
[standard] VARCHAR(20),
[rank] INT,
previous_subject_id INT);
INSERT INTO @subject_class SELECT 13, 'ABC', '1st', 1, 21;
INSERT INTO @subject_class SELECT 13, 'ABF', '1st', 1, 23;
INSERT INTO @subject_class SELECT 13, 'ABC', '1st', 1, 13;
INSERT INTO @subject_class SELECT 25, 'def', '3rd', 6, 42;
INSERT INTO @subject_class SELECT 25, 'dez', '3rd', 6, 25;
INSERT INTO @subject_class SELECT 25, 'def', '3rd', 6, 28;
DELETE FROM @subject_class WHERE subject_id = previous_subject_id;
WITH cte AS (
SELECT
subject_id,
subject_name,
[standard],
[rank],
MIN(previous_subject_id) AS min_previous_subject_id
FROM
@subject_class
GROUP BY
subject_id,
subject_name,
[standard],
[rank])
DELETE
s
FROM
@subject_class s
INNER JOIN cte c ON c.subject_id = s.subject_id
AND c.subject_name = s.subject_name
AND c.[standard] = s.[standard]
AND c.[rank] = s.[rank]
WHERE
c.min_previous_subject_id != s.previous_subject_id;
SELECT * FROM @subject_class;
На этот раз мы в итоге получим 3 строки: - строка для «dez» все еще удаляется на основании того, что она имеет одинаковые subject_id и previous_subject_id; - строка для "ABF" сохраняется, поскольку она не соответствует имени субъекта.
На этот раз с вашими обновленными данными:
DECLARE @subject_class TABLE (
subject_id INT,
subject_name VARCHAR(20),
[standard] VARCHAR(20),
[rank] INT,
previous_subject_id INT);
INSERT INTO @subject_class SELECT 13, 'ABC', '1st', 1, 21;
INSERT INTO @subject_class SELECT 13, 'ABC', '1st', 1, 23;
INSERT INTO @subject_class SELECT 13, 'ABC', '1st', 1, 13;
INSERT INTO @subject_class SELECT 25, 'def', '3rd', 6, 42;
INSERT INTO @subject_class SELECT 25, 'def', '3rd', 6, 25;
INSERT INTO @subject_class SELECT 25, 'def', '3rd', 6, 28;
INSERT INTO @subject_class SELECT 25, 'XYZ', '2nd', 7, 26;
INSERT INTO @subject_class SELECT 29, 'PQR', '1st', 1, 31;
DELETE FROM @subject_class WHERE subject_id = previous_subject_id;
WITH cte AS (
SELECT
subject_id,
subject_name,
[standard],
[rank],
MIN(previous_subject_id) AS min_previous_subject_id
FROM
@subject_class
GROUP BY
subject_id,
subject_name,
[standard],
[rank])
DELETE
s
FROM
@subject_class s
INNER JOIN cte c ON c.subject_id = s.subject_id
AND c.subject_name = s.subject_name
AND c.[standard] = s.[standard]
AND c.[rank] = s.[rank]
WHERE
c.min_previous_subject_id != s.previous_subject_id;
SELECT * FROM @subject_class;
Я получаю Результаты:
subject_id subject_name standard rank previous_subject_id
13 ABC 1st 1 21
25 def 3rd 6 28
25 XYZ 2nd 7 26
29 PQR 1st 1 31
Что соответствует тому, что вы ожидали? Ну, не совсем, но это потому, что вы все еще используете «первое», когда такой концепции нет. Я получаю одинаковое количество строк, и результаты в основном одинаковы. Я просто выбираю другой ряд, чтобы сохранить, чем вы.