#sql #sql-server #database
#sql #sql-сервер #База данных
Вопрос:
Я работал с MySQL, но теперь я пытаюсь выполнить аналогичные действия с MS SQL (2016), но запрос не работает. У меня есть таблица «TEST», и я пытаюсь удалить дубликаты на основе совпадения столбцов «lastname, firstname».
Использование наименьшего значения ID:
DELETE FROM TEST
WHERE lastname NOT IN (
SELECT t.id FROM (
SELECT MIN(PersonID) id
FROM TEST
GROUP BY lastname, firstname
) t
)
Столбцы: «PersonID», «LastName», «FirstName», «Address», «City»
Ошибка:
Сообщение 245, уровень 16, состояние 1, преобразование строки 1 завершилось ошибкой при преобразовании значения varchar ‘JOHN’ в тип данных int.
Комментарии:
1. Извините! Ошибка заключается в следующем: Сообщение 245, уровень 16, состояние 1, ошибка преобразования строки 1 при преобразовании значения varchar ‘JOHN’ в тип данных int.
Ответ №1:
Вы хотите, чтобы строка с минимальным идентификатором была правильной? Используйте EXISTS
:
delete t from test t
where exists (
select 1 from test
where firstname = t.firstname and lastname = t.lastname
and id < t.id
)
Комментарии:
1. Да, как и в первом появившемся, должен остаться тот, который останется. Я получаю «Сообщение 102, уровень 15, состояние 1, в строке 1 неправильный синтаксис рядом с ‘t'». . Я не совсем понимаю, почему.
2. Вы изменили на:
delete t from test t
?3. Вы правы, это работает, и я это понимаю. Спасибо!
Ответ №2:
Вы сравниваете фамилию с идентификатором, отсюда и ошибка, о которой вы сообщили «Ошибка преобразования при преобразовании значения varchar ‘JOHN’ в тип данных int» попробуйте это вместо:
DELETE FROM TEST
WHERE PersonID NOT IN (
SELECT t.id FROM (
SELECT MIN(PersonID) id
FROM TEST
GROUP BY lastname, firstname
) t
)
Ответ №3:
В SQL Server я рекомендую использовать для этого оконные функции:
with todelete as (
select t.*,
row_number() over (partition by firstname, lastname order by id) as seqnum
from test t
)
delete from todelete
where seqnum > 1;
Комментарии:
1. Это определенно работает, но я недостаточно разбираюсь в SQL Server, чтобы полностью понять это. Является ли это более эффективным подходом для описания того, как Forpas это делал? Спасибо!
2. @Natsu . . . Это интересный вопрос. Вам нужно будет протестировать это на ваших данных. В общем, я думаю, что это было бы быстрее, но при некоторых обстоятельствах
exists
предложение могло бы быть.3. Это не позволит мне проголосовать за ваш ответ, потому что я все еще новичок, извините. Однако я очень ценю вашу помощь.
Ответ №4:
Вы можете попробовать преобразовать свой идентификатор в varchar / nvarchar, поскольку lastname
это символ. Хотя вы можете дважды проверить, следует ли ссылаться на PersonID или lastname.
DELETE FROM TEST
WHERE lastname NOT IN (
SELECT CONVERT(VARCHAR(50),t.id) FROM (
SELECT MIN(PersonID) id
FROM TEST
GROUP BY lastname, firstname
) t
)
Ответ №5:
Вы тоже можете попробовать этот подход :
DELETE T2 FROM (
SELECT
MIN(PersonID) id
FROM
TEST
GROUP BY
lastname, firstname
) t
INNER JOIN TEST T2 ON t.id = T2.PersonID