programing

중복 행을 삭제하려면 어떻게 해야 합니까?

padding 2023. 4. 8. 08:01
반응형

중복 행을 삭제하려면 어떻게 해야 합니까?

상당히 큰 SQL Server 테이블에서 중복된 행을 제거해야 합니다(즉, 300,000개 이상의 행).

이 완전히 되는 것은 . 행이 이다.RowID[ 아이덴티티 ]

마이테이블

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

이거 어떻게 해?

없는 null이 .GROUP BY 컬럼 및 """ " " "SELECTMIN (or MAX)RowId를 선택합니다.신분을 밝히다

DELETE FROM MyTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, Col1, Col2, Col3 
   FROM MyTable 
   GROUP BY Col1, Col2, Col3
) as KeepRows ON
   MyTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

정수 대신 GUID가 있는 경우,

MIN(RowId)

와 함께

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))

또 다른 가능한 방법은

; 

--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 
                                       ORDER BY ( SELECT 0)) RN
         FROM   #MyTable)
DELETE FROM cte
WHERE  RN > 1;

하고 .ORDER BY (SELECT 0)동점이 발생할 경우 어느 행을 유지할지는 임의적이기 때문에 위의 항목에서 확인할 수 있습니다.

RowID는 " " "를 사용할 수 .ORDER BY RowID DESC

실행 계획

이를 위한 실행 계획은 셀프 가입을 필요로 하지 않기 때문에 일반적으로 승인된 답변보다 간단하고 효율적입니다.

실행 계획

을 사용하다 ★★★★★★★★★★★★★★★★★★★★★★★★★★GROUP BY스트림 애그리게이트보다 해시 애그리게이트를 선택하는 것이 바람직할 수 있습니다.

ROW_NUMBER 같은 을 제시하지만, 해법은 거의 계획을 합니다.GROUP BY보다 유연한 전략입니다.

실행 계획

해시 집계 접근방식을 선호할 수 있는 요인은 다음과 같습니다.

  • 파티션 열에 유용한 인덱스가 없습니다.
  • 각 그룹에서 중복되는 수가 상대적으로 적은 그룹

두케이스의 그룹에 되는 수가 에서는 단순히 을 새 에 삽입하는 할 수 .TRUNCATE- 하기 위해 - 행의 많은 부분을 삭제하는 것에 비해 가 최소화됩니다.

Microsoft 지원 사이트에 중복 제거에 대한 좋은 기사가 있습니다.이것은 매우 보수적입니다.- 그들은 모든 것을 따로따로 하도록 합니다.- 하지만 큰 테이블에 비해서는 잘 작동될 것입니다.

나는 과거에 이것을 하기 위해 셀프 조인을 사용한 적이 있다.하지만, 아마 HAVING 조항으로 예쁘게 꾸며질 수 있을 것이다.

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField

다음 조회는 중복 행을 삭제하는 데 유용합니다.에는 '아까보다'가 있습니다.ID은 아이디입니다.Column1,Column2 ★★★★★★★★★★★★★★★★★」Column3.

DELETE FROM TableName
WHERE  ID NOT IN (SELECT MAX(ID)
                  FROM   TableName
                  GROUP  BY Column1,
                            Column2,
                            Column3
                  /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
                    nullable. Because of semantics of NOT IN (NULL) including the clause
                    below can simplify the plan*/
                  HAVING MAX(ID) IS NOT NULL) 

은 ᄃ자 사용법을 .GROUP BY,HAVING,ORDER BY하나의 쿼리에서 중복된 열과 개수가 포함된 결과를 반환합니다.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 
delete t1
from table t1, table t2
where t1.columnA = t2.columnA
and t1.rowid>t2.rowid

포스트그레스:

delete
from table t1
using table t2
where t1.columnA = t2.columnA
and t1.rowid > t2.rowid
DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 

이렇게 하면 첫 번째 행을 제외한 중복된 행이 삭제됩니다.

DELETE
FROM
    Mytable
WHERE
    RowID NOT IN (
        SELECT
            MIN(RowID)
        FROM
            Mytable
        GROUP BY
            Col1,
            Col2,
            Col3
    )

참조(http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server)

SQL 서버 테이블에서 중복 행을 삭제하는 CTE를 선호합니다.

다음 문서를 따를 것을 강력히 권장합니다.http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

독창성을 유지함으로써

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

독창성을 잃지 않고

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)

중복 행을 가져오려면:

SELECT
name, email, COUNT(*)
FROM 
users
GROUP BY
name, email
HAVING COUNT(*) > 1

중복 행을 삭제하려면:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      

[Quick] (빠른) 및 [Dirty] (더러운) : 중복된 행을 삭제합니다(작은 테이블의 경우).

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;

내부 조인보다 카운트(*) >1의 솔루션을 갖는 서브쿼리를 사용하는 것이 좋습니다.이는 읽기 쉽고 SELECT 스테이트먼트를 실행하기 전에 삭제할 내용을 확인하는 것이 매우 쉽기 때문입니다.

--DELETE FROM table1 
--WHERE id IN ( 
     SELECT MIN(id) FROM table1 
     GROUP BY col1, col2, col3 
     -- could add a WHERE clause here to further filter
     HAVING count(*) > 1
--)
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable

특별한 상황에서 작동하기 때문에 솔루션을 공유하려고 합니다.값이 중복된 테이블에는 외부 키가 없습니다(다른 DB에서 값이 중복되었기 때문입니다).

begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2

-- insert distinct values into temp
insert into #temp 
select distinct * 
from  tableName

-- delete from source
delete from tableName 

-- insert into source from temp
insert into tableName 
select * 
from #temp

rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!

추신: 이런 작업을 할 때는 항상 트랜잭션을 사용합니다.이것에 의해, 모든 것이 전체적으로 실행될 뿐만 아니라, 어떠한 리스크도 감수하지 않고 테스트 할 수 있습니다.하지만 만약을 위해서라도 백업을 받아두셔야 합니다...

이 쿼리는 저에게 매우 좋은 성능을 보여 주었습니다.

DELETE tbl
FROM
    MyTable tbl
WHERE
    EXISTS (
        SELECT
            *
        FROM
            MyTable tbl2
        WHERE
            tbl2.SameValue = tbl.SameValue
        AND tbl.IdUniqueValue < tbl2.IdUniqueValue
    )

200만 개의 테이블에서 100만 개의 행을 30초 남짓 만에 삭제(50% 중복)

CTE 사용.중복 레코드를 형성하는 하나 이상의 열에 조인한 후 원하는 열을 제거하는 것이 좋습니다.

;with cte as (
    select 
        min(PrimaryKey) as PrimaryKey
        UniqueColumn1,
        UniqueColumn2
    from dbo.DuplicatesTable 
    group by
        UniqueColumn1, UniqueColumn1
    having count(*) > 1
)
delete d
from dbo.DuplicatesTable d 
inner join cte on 
    d.PrimaryKey > cte.PrimaryKey and
    d.UniqueColumn1 = cte.UniqueColumn1 and 
    d.UniqueColumn2 = cte.UniqueColumn2;

여기에 붙여진 링크에서 다른 간단한 해결책을 찾을 수 있습니다.이것은 이해하기 쉽고, 대부분의 유사한 문제에 효과가 있는 것 같습니다.SQL Server용이지만 사용되는 개념은 허용 범위 이상입니다.

링크된 페이지의 관련 부분을 다음에 나타냅니다.

다음 데이터를 고려하십시오.

EMPLOYEE_ID ATTENDANCE_DATE
A001    2011-01-01
A001    2011-01-01
A002    2011-01-01
A002    2011-01-01
A002    2011-01-01
A003    2011-01-01

그럼 어떻게 하면 중복된 데이터를 삭제할 수 있을까요?

먼저 다음 코드를 사용하여 해당 테이블에 ID 열을 삽입합니다.

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)  

이 문제를 해결하려면 다음 코드를 사용합니다.

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 

중복 레코드를 삭제하는 가장 쉬운 방법입니다.

 DELETE FROM tblemp WHERE id IN 
 (
  SELECT MIN(id) FROM tblemp
   GROUP BY  title HAVING COUNT(id)>1
 )

이것을 사용하다

WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name)
   As RowNumber,* FROM <table_name>
)
DELETE FROM tblTemp where RowNumber >1

여기 중복 제거에 대한 또 다른 좋은 기사가 있습니다.

"SQL은 관계대수에 기초하고 있으며 집합에서 중복이 허용되지 않기 때문에 관계대수에서는 중복이 발생할 수 없다"는 이유를 설명합니다.

temp 테이블솔루션과 2개의 mysql 예시.

앞으로는 데이터베이스 수준 또는 애플리케이션 관점에서 이를 방지할 예정입니다.데이터베이스 레벨을 제안합니다.데이터베이스는 참조 무결성을 유지하는 책임을 져야 하기 때문입니다.개발자는 문제를 일으킬 뿐입니다.

중복되지 않은 행을 보존해야 하는 테이블이 있었습니다.속도나 효율은 잘 모르겠어요.

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )

아, 물론입니다.임시 테이블을 사용합니다.퍼포먼스가 그다지 좋지 않은 단일 스테이트먼트를 「작동」하고 싶은 경우는, 다음과 같이 할 수 있습니다.

DELETE FROM MyTable WHERE NOT RowID IN
    (SELECT 
        (SELECT TOP 1 RowID FROM MyTable mt2 
        WHERE mt2.Col1 = mt.Col1 
        AND mt2.Col2 = mt.Col2 
        AND mt2.Col3 = mt.Col3) 
    FROM MyTable mt)

기본적으로 테이블의 각 행에 대해 하위 선택 항목은 맨 위의 행을 찾습니다.고려 중인 행과 정확히 동일한 모든 행의 ID.결국 'Row'의 리스트가 됩니다."원래" 중복되지 않은 행을 나타내는 ID.

다른 방법은 동일한 필드와 고유 색인을 사용하여 새 테이블을 작성하는 입니다.그런 다음 모든 데이터를 이전 테이블에서 새 테이블로 이동합니다.SQL SERVER는 자동으로 값을 무시합니다(무시, 인터럽트 또는 어떤 값이 중복될 경우 수행할 작업에 대한 옵션도 있습니다).같은 테이블에 중복된 행이 없습니다.고유 인덱스를 원하지 않는 경우 데이터를 전송한 후 삭제할 수 있습니다.

특히 테이블이 큰 경우 모든 데이터를 고유 인덱스된 새 테이블로 신속하게 전송하기 위해 DTS(데이터 가져오기/내보내기 SSIS 패키지)를 사용할 수 있습니다.700만 줄에 몇 분이면 충분합니다.

또는 컬럼을 으로 중복 할 수 쿼리는 두수과 같습니다. 아래 쿼리는 두 열을 기준으로 삭제합니다. 테이블 이름은 다음과 같습니다.testing 열 이름 " " " "empno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
  1. 동일한 구조로 새 빈 테이블 만들기

  2. 다음과 같이 쿼리를 실행합니다.

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
    
  3. 그런 다음 이 쿼리를 실행합니다.

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1
    

또 다른 방법 :--

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 

이 접근방식은 도움이 될 수 있을 뿐만 아니라 모든 SQL 서버에서 작동합니다.대부분 중복되는 것은 1-2개뿐이며 ID와 중복되는 수는 알려져 있습니다.이 경우:

SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0

애플리케이션 레벨로부터(안타깝게도).중복을 방지하는 적절한 방법은 고유한 인덱스를 사용하는 데이터베이스 수준이라는 것에 동의합니다.그러나 SQL Server 2005에서는 인덱스는 900바이트밖에 허용되지 않으며 my varchar(2048) 필드는 그것을 날려버립니다.

얼마나 잘 될지는 모르겠지만, 인덱스로 직접 할 수 없는 경우에도 이것을 강제하는 트리거를 쓸 수 있을 것 같습니다.예를 들어 다음과 같습니다.

-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism 
ON stories 
after INSERT, UPDATE 
AS 
    DECLARE @cnt AS INT 

    SELECT @cnt = Count(*) 
    FROM   stories 
           INNER JOIN inserted 
                   ON ( stories.story = inserted.story 
                        AND stories.story_id != inserted.story_id ) 

    IF @cnt > 0 
      BEGIN 
          RAISERROR('plagiarism detected',16,1) 

          ROLLBACK TRANSACTION 
      END 

또, varchar(2048)가 수상쩍게 들립니다(인생에 따라서는 2048바이트도 있습니다만, 매우 드문 경우입니다). varchar(max)가 아닌 것이 맞습니까?

DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)

INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)

--SELECT * FROM car

;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)

DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)

제거하려는 행을 미리 보고 유지할 중복 행을 제어하려고 합니다.http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/ 를 참조해 주세요.

with MYCTE as (
  SELECT ROW_NUMBER() OVER (
    PARTITION BY DuplicateKey1
                ,DuplicateKey2 -- optional
    ORDER BY CreatedAt -- the first row among duplicates will be kept, other rows will be removed
  ) RN
  FROM MyTable
)
DELETE FROM MYCTE
WHERE RN > 1

언급URL : https://stackoverflow.com/questions/18932/how-can-i-remove-duplicate-rows

반응형