2011-07-05 17 views
2

削除された重複レコードへのクエリを次の表(valid_columns)から作成し、最も低い[order]番号のレコードのみを保持しようとしています。SQLサブクエリを削除し、重複したレコードを削除しました

たとえば、次の表では、重複する行、領域2,3、およびジョブ3を削除し、できるだけ少ない[順序]でレコードを保持したいと考えています。

など。私はバグを修正しようとしていると私はSQLを理解することはできません

name col_order 
------------- 
job  1  
status 2 
cust 2 
county 1 
state 1 
region 1 
so  4 

name col_order 
------------- 
job  1 
job  3 
status 2 
cust 2 
county 1 
state 1 
region 1 
region 2 
region 3 
so  4 

所望の出力:入力テーブルは、valid_columnsは次のようになります。現在は、削除文とサブクエリを使用しています。現時点で使用されたクエリは次のようになります。

から3)を

DELETE 
FROM valid_columns 
WHERE NOT (col_order = (SELECT TOP 1 col_order 
      FROM valid_columns firstValid 
      WHERE name = firstValid.name 
      AND col_order = firstValid.col_order 
      ORDER BY col_order ASC)) 

重複列を削除しかし、これは唯一間違っている以下、返します

name col_order 
------------- 
job  1 
county 1 
state 1 
region 1 

感謝

答えて

1
DELETE FROM t1 
FROM valid_columns t1 
WHERE col_order > 
    (SELECT MIN(col_order) from valid_columns t2 WHERE t1.name = t2.name) 

EDIT: は、このように単純化することができます。

DELETE FROM valid_columns 
    WHERE col_order > 
     (SELECT MIN(col_order) from valid_columns t2 WHERE valid_columns.name = t2.name) 

DELETE文は、2番目の表の関連レコードの値に基づいてレコードを削除するFROM句を持つことができます。この場合、FROMは本当に必要ではありません(FROMを使用してテーブル名のエイリアスを作成することがあります。)

DELETE FROM TableA 
FROM TableA 
JOIN TableB On TableA.CriteriaA = TableB.CriteriaA 

また、あなたがこれをたくさんしなければならない場合は()速いかもしれません。この例を試すことができます:

DELETE FROM valid_columns 
WHERE EXISTS 
    (SELECT * FROM valid_columns t1 
    WHERE t1.name = valid_columns.name AND valid_columns.col_order > t1.col_order); 
+0

where句で相関サブクエリを使用するとちょっと混乱しますが、簡単に答えを展開できますか?それはうまくいくように見えます。 – bobbo

0

これを試してください(削除する前に正しい結果が得られるように、削除したものをselectに置き換えることができます)。

DELETE FROM [valid_columns] t1 
WHERE col_order > (SELECT MIN(col_order) from [valid_columns] t2 
     WHERE t1.name = t2.name) 
1
-- Test table 
declare @T table(Name varchar(10), col_order int) 

-- Sample data 
insert into @T 
select 'job',  1 union all 
select 'job',  3 union all 
select 'status', 2 union all 
select 'cust', 2 union all 
select 'county', 1 union all 
select 'state', 1 union all 
select 'region', 1 union all 
select 'region', 2 union all 
select 'region', 3 union all 
select 'so',  4 

-- Delete using CTE and row_number() 
;with cte as 
(
    select row_number() over(partition by Name order by col_order) as rn 
    from @T 
) 
delete from cte 
where rn > 1 

-- Result 
select * 
from @T 

またはサブクエリではなく、CTE

delete vc 
from (select row_number() over(partition by Name order by col_order) as rn 
     from valid_columns) as vc 
where vc.rn > 1  
0

これはあなたが必要なものを行う必要があります。

DELETE FROM valid_columns a 
WHERE (SELECT MAX(col_order) 
    FROM valid_columns b 
    WHERE a.name = b.name) > a.col_order; 

私はあなたが試験前にデータのバックアップを作成お勧めしますそれは、しかし、。

0

カーソルを使用してテーブルを反復して、一時テーブルに項目の最初に見つかった値を挿入することができます(一時テーブルには名前列に一意の制約が指定されていることを確認してください)。

編集:私は便宜上のコードスニペットを含めました...

declare @Ti table(name varchar(10), col_order int); 
declare @Tf table(name varchar(10) unique not null, col_order int not null); 

declare @name varchar(10); 
declare @col_order int; 

-- Sample data 
insert into @Ti 
select 'job',  1 union all 
select 'job',  3 union all 
select 'status', 2 union all 
select 'cust', 2 union all 
select 'county', 1 union all 
select 'state', 1 union all 
select 'region', 1 union all 
select 'region', 2 union all 
select 'region', 3 union all 
select 'so',  4 

select * from @Ti 

declare i cursor for 
    select * from @Ti; 

open i; 
fetch next from i into @name, @col_order; 

while @@FETCH_STATUS = 0 
begin 
    if not exists(select * from @Tf where name = @name) 
    begin 
     insert into @Tf(name, col_order) 
      select @name, @col_order; 
    end 

    fetch next from i into @name, @col_order; 
end 

close i; 
deallocate i; 

select * from @Tf; 
0

(これは)任意のSQL Serverのバージョンで動作しているバイナリのチェックサムを持つレコードを削除します。

 

CREATE TABLE #t1(ID INT NULL, VALUE VARCHAR(2)) 
INSERT INTO #t1(ID, VALUE) VALUES (1,'aa') 
INSERT INTO #t1(ID, VALUE) VALUES (2,'bb') 
INSERT INTO #t1(ID, VALUE) VALUES (1,'aa') 
INSERT INTO #t1(ID, VALUE) VALUES (1,'aa') 
INSERT INTO #t1(ID, VALUE) VALUES (3,'cc') 
INSERT INTO #t1(ID, VALUE) VALUES (3,'cc') 
GO 

-- BINARY_CHECKSUM(): are columns that we want to compare duplicates for 
-- if you want to compare the full row then change BINARY_CHECKSUM() -> BINARY_CHECKSUM(*) 

-- for SQL Server 2000+ a loop 
-- save checksums and rowcounts for duplicates 

SELECT BINARY_CHECKSUM(ID, VALUE) AS ChkSum, COUNT(*) AS Cnt 
INTO #t2 
FROM #t1 
GROUP BY BINARY_CHECKSUM(ID, VALUE) HAVING COUNT(*)>1 

DECLARE @ChkSum BIGINT, @rc INT 

-- get the first checksum and set the rowcount to the count - 1 
-- because we want to leave one duplicate 

SELECT TOP 1 @ChkSum = ChkSum, @rc = Cnt-1 FROM #t2 

WHILE EXISTS (SELECT * FROM #t2) 
BEGIN  
    -- rowcount is one less than the duplicate rows count 
    SET ROWCOUNT @rc 
    DELETE FROM #t1 WHERE BINARY_CHECKSUM(ID, VALUE) = @ChkSum 
    -- remove the processed duplicate from the checksum table 
    DELETE #t2 WHERE ChkSum = @ChkSum 
    -- select the next duplicate rows to delete 
    SELECT TOP 1 @ChkSum = ChkSum, @rc = Cnt-1 FROM #t2  
END 
SET ROWCOUNT 0 
GO 

SELECT * FROM #t1 

-- for SQL Server 2005+ a cool CTE 
;WITH Numbered 
AS 
(
    SELECT ROW_NUMBER() OVER (PARTITION BY ChkSum ORDER BY ChkSum) AS RN, * 
    FROM (
      SELECT BINARY_CHECKSUM(ID, VALUE) AS ChkSum 
      FROM #t1 
     ) t 
) 
DELETE FROM Numbered WHERE RN > 1; 
GO 

SELECT * FROM #t1 

DROP TABLE #t1; 
DROP TABLE #t2;