Как удалить повторяющиеся строки в SQL 2000? - PullRequest
1 голос
/ 22 апреля 2010

Я думал, что понял это, но оказалось, что я просто удаляю первую запись.Следующее возвращает дубликаты строк.У всех счетчик 2. Я просто хочу удалить первый для каждой дублирующейся записи.

select scorestudentid, scoreadvisor, scorecorrect, count(*) 
from scores
where scoretestid = 3284
group by scorestudentid, scoreadvisor, scorecorrect
having count(scorestudentid) > 1

, который возвращает:

scorestudentid  scoreadvisor  scorecorrect  no column name
13033719        28059     3.0           2
13033777        28086     3.0           2
13033826        28147     3.0           2
13033960        28023     3.0           2

Так что я собрал все вместе, думая, что это будет работать:

set rowcount 1
delete
from scores
where scoretestid = 3284 
and scorestudentid in (
    select scorestudentid
    from scores
    where scoretestid = 3284
    group by scorestudentid
    having count(scorestudentid) > 1)

Похоже, это должна быть простая концепция, но я не понимаю.

На основе сценария Томаса я обновил запрос, чтобы он соответствовал, но он все еще не работает.

Delete Scores
Where Exists    (
                Select 1
                From Scores As S2
                Where S2.ScoreStudentId = Scores.ScoreStudentId
                        And S2.ScoreAdvisor = Scores.ScoreAdvisor
                        And S2.ScoreCorrect = Scores.ScoreCorrect
                Group By S2.ScoreStudentId, S2.ScoreAdvisor, S2.ScoreCorrect
                Having Count(*) > 1
                    And Min(S2.NewScoreID) = Scores.NewScoreID
                )
    And Scores.ScoreTestId = 3284

Ответы [ 3 ]

5 голосов
/ 22 апреля 2010

Хитрость заключается в том, чтобы использовать столбец первичного ключа (у вас есть один, верно?) И просто найти первое значение PK, которое соответствует критериям, которые вы хотите. Если по какой-то ненормальной причине у вас нет столбца первичного ключа, добавьте столбец Identity и сделайте его первичным ключом, а затем выполните удаление.

РЕДАКТИРОВАТЬ Пересмотрено, чтобы сделать его более общим. Если вы удалите окончательный фильтр в ScoreTest, он удалит все дубликаты на основе ScoreStudentId, ScoreAdvisor и ScoreCorrect.

Delete Scores
Where Exists    (
                Select 1
                From Scores As S2
                Where S2.ScoreStudentId = Scores.ScoresStudentId
                        And S2.ScoreAdvisor = Scores.ScoreAdvisor
                        And S2.ScoreCorrect = Scores.ScoreCorrect
                Group By S2.ScoreStudentId, S2.ScoreAdvisor, S2.ScoreCorrect
                Having Count(*) > 1
                    And Min(S2.PrimaryKeyColumn) = Scores.PrimaryKeyColumn
                )
    And Scores.ScoreTest = 3284
0 голосов
/ 02 февраля 2014

Я собираюсь поговорить об интересной теме в мире SQL. Если вы воспользуетесь этой темой в Google, вы найдете несколько способов удаления повторяющихся данных из таблицы. Я не собираюсь писать что-то очень новое, но да, я буду говорить о проблеме производительности, удаляя дублирующиеся данные, используя традиционный подход.

Удаление дублирующихся строк из SQL 2000: - Я создал таблицу DuplicateData и вставил несколько дублирующихся строк на основе EmpId.

Создать таблицу DuplicateData (EmpId int, Имя varchar (100)) -> Создание таблицы

insert into DuplicateData values(4,'Akshay')
insert into DuplicateData values(4,'Akshay')
insert into DuplicateData values(5,'ankit')
insert into DuplicateData values(3,'Vikas')
insert into DuplicateData values(3,'Vikas')
insert into DuplicateData values(3,'Vikas')
insert into DuplicateData values(3,'Vikas')
insert into DuplicateData values(2,'Raj')
insert into DuplicateData values(2,'Raj')
insert into DuplicateData values(1,'Neeraj')
insert into DuplicateData values(1,'Neeraj')

insert into DuplicateData values(1,'Neeraj')

Традиционный способ удаления дублирующихся строк из таблицы в SQL 2000: -Если мы запустим приведенный ниже пакет в анализаторе запросов, он удалит все дублирующиеся значения из таблицы DuplicateData. Этот запрос «ОК», если вы делаете это в тестовой среде или на фиктивных данных. Но если у вас есть миллионы записей или большие данные, этот запрос будет худшим с точки зрения производительности. Это может занять несколько часов или дней в зависимости от объема данных в предполагаемой таблице.

Причина: - Под запросом находится коррелированный подзапрос, который будет выполняться для каждого EmpId, присутствующего в таблице, и проверять, равно ли число для каждого EmpId> 1, а затем удалять каждую запись одну за другой. Это является причиной его низкой производительности.

set rowcount 1
delete from DuplicateData where (select count(EmpId) from DuplicateData a where a.EmpId=DuplicateData.EmpId)>1
while @@rowcount>0
delete from DuplicateData where (select count(EmpId) from DuplicateData a where a.EmpId=DuplicateData.EmpId)>1

set rowcount 0

Мы можем создать хранимую процедуру, чтобы преодолеть эту проблему производительности. Ниже приведен пример.

declare @tmp table(empid int,cnt int, rowid int identity)--> declare table variable

declare @maxcounter as integer--> Declaration of variables
declare @mincounter as integer
declare @rowcnt as integer
declare @empid as int-->End of Declaration

insert into @tmp(empid,cnt)-->Inserting duplicate empid along with no of duplicate entries
select empid,count(empid) from duplicatedata 
group by empid having count(empid)>1

select @mincounter=min(rowid),@maxcounter=max(rowid) from @tmp -->assigning minimum and maximum rowid to variables.

while @mincounter <=@maxcounter
begin
 select @rowcnt=cnt,@empid=empid from @tmp where rowid=@mincounter 
 set @rowcnt =@rowcnt-1
 set rowcount @rowcnt
 delete from duplicatedata where empid=@empid
 set rowcount 0
 set @mincounter=@mincounter +1
end

давайте разберемся с приведенным выше циклом while, у нас есть все повторяющиеся записи в таблице @tmp без повторяющихся записей. Теперь мы будем перебирать каждую запись, присутствующую в таблице @tmp, поэтому мы присвоили минимальный и максимальный rowid переменным (@maxcounter, @mincounter).

В теле цикла While мы присваиваем значения «no of duplicate records» переменной @rowcnt и empid переменной @ empid

В следующем операторе мы устанавливаем @ rowcnt = @ rowcnt-1, мы делаем это, потому что эта переменная не содержит повторяющихся записей для определенного empid, но мы хотим сохранить один empid из дублирующих. в следующем утверждении мы устанавливаем количество строк на одно значение меньше, чем количество повторяющихся записей для этого конкретного empid.

Следующий оператор сбрасывает количество строк с 0, а последний оператор увеличивает значение @mincounter для получения следующей записи из таблицы @tmp.

0 голосов
/ 17 февраля 2011

Я считаю, что решение Томаса не работает с уникальными идентификаторами для первичных ключей.Кроме того, если одна запись дублируется несколько раз (то есть 3, 4, 5+ раз) в таблице, она удалит только одну.

Это то, что мы использовали:

Declare @ Col1uniqueidentifier объявить @ col2 varchar (256) объявить @ col3 datetime

DECLARE C CURSOR
FOR

            select col1, col2, col3
            from MyTable
            where IsDeleted = 0
            group by col1, col2, col3
            having count(*) > 1
OPEN    C
FETCH NEXT FROM C
INTO    @col1, @col2, @col3

WHILE @@FETCH_STATUS = 0
BEGIN

declare @primaryKey uniqueidentifier
set @primaryKey = (select top 1 primaryKey from MyTable
                            where col1 = @col1 and col2= @col2 and col3 = @col3)

update MyTable
set IsDeleted = 1, DeleteDt = GETDATE()
where col1 = @col1
    and col2 = @col2
    and col3 = @col3
    and PrimaryKey<> @primaryKey


FETCH NEXT FROM C
INTO    @col1, @col2, @col3
END

CLOSE C
DEALLOCATE C

Что делает этот курсор:

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