1

私のデータベースには次のような重複したIPアドレスレコードがあります:

id | ipaddress
1    192.168.xxx.xxx
2    192.168.xxx.xxx
3    111.118.xxx.xxx
4    111.118.xxx.xxx

自分のフィールドに一意のIPアドレスが必要です。重複するエントリをすべて削除するにはどうすればよいですか?

ありがとう

4

3 に答える 3

4

サブセレクトでテーブルを参照できないという愚かな制限があるため、MySQLで重複を削除するのは少し注意が必要です。そのため、副選択を結合に書き直す必要があります。

DELETE d
FROM mytable d
LEFT JOIN (
   SELECT min(id) as min_id
   FROM   mytable
   GROUP BY trim(ipaddress)
) tokeep ON tokeep.min_id = d.id
WHERE keep.min_id IS NULL;

SQLFiddleデモ:http ://sqlfiddle.com/#!2/9cfb9c/1

編集

実際には、愚かな副選択の制限を回避する方法があります。テーブルが副選択内の派生テーブルにラップされている場合、MySQLパーサーはこれに気付かず、副選択で喜んで削除します。

delete mt 
from mytable mt
where exists (
    select * 
    from (
      select id, ipaddress
      from mytable
    ) ex
    where TRIM(ex.ipaddress) = TRIM(mt.ipaddress)
   and ex.id < mt.id
)
于 2012-10-27T12:19:11.637 に答える
0
CREATE TABLE mytable
        (id SERIAL NOT NULL PRIMARY KEY
        , ipaddress varchar
        );
INSERT INTO mytable(id, ipaddress) VALUES
 (1, '192.168.xxx.xxx')
,(2, '192.168.xxx.xxx ')        --<< note trailing whitespace
,(3, '111.118.xxx.xxx')
,(4, '111.118.xxx.xxx')
        ;
SELECT * FROM mytable;

DELETE FROM mytable mt
WHERE EXISTS (
  SELECT * FROM mytable ex
  WHERE ex.ipaddress = mt.ipaddress
  AND ex.id < mt.id
  )
  ;
SELECT * FROM mytable;

DELETE FROM mytable mt
WHERE EXISTS (
  SELECT * FROM mytable ex
  WHERE TRIM(ex.ipaddress) = TRIM(mt.ipaddress)
  AND ex.id < mt.id
  )
  ;
SELECT * FROM mytable;

出力:

CREATE TABLE
INSERT 0 4
 id |    ipaddress     
----+------------------
  1 | 192.168.xxx.xxx
  2 | 192.168.xxx.xxx 
  3 | 111.118.xxx.xxx
  4 | 111.118.xxx.xxx
(4 rows)

DELETE 1
 id |    ipaddress     
----+------------------
  1 | 192.168.xxx.xxx
  2 | 192.168.xxx.xxx 
  3 | 111.118.xxx.xxx
(3 rows)

DELETE 1
 id |    ipaddress    
----+-----------------
  1 | 192.168.xxx.xxx
  3 | 111.118.xxx.xxx
(2 rows)

更新:testdataを追加し、1つのレコードを変更して末尾にwhitspaceを追加しました。

注:stringfunctionsの名前は、DMBS実装間で異なる場合があります。TRIM()関数はpostgresで機能します。おそらく、mysqlには同じものの別の名前があります。

UPDATE2:mysqlはdeleteステートメントでの自己結合を許可していないように見えるため、回避策は、保持したい(保持したくない)レコードのIDを持つ補助テーブルを使用することです。

(@ahose_with_no_nameによる解決策はより短いですが、これはプレーンバニラSQLに近づこうとします):

CREATE table without_dups(id INTEGER NOT NULL);
INSERT INTO without_dups(id)
SELECT id
FROM mytable mt
WHERE NOT EXISTS (
  SELECT * FROM mytable ex
  WHERE ex.ipaddress = mt.ipaddress
  AND ex.id < mt.id
  )
  ;

DELETE FROM mytable mt
WHERE NOT EXISTS (
  SELECT * FROM without_dups nx
  WHERE nx.id = mt.id
  )
  ;

DROP TABLE without_dups;

SELECT * FROM mytable;
于 2012-10-27T11:50:49.613 に答える
0

これを試して

DELETE * FROM MyTable AS aa INNER JOIN (
  SELECT MIN(id) as MID, id, ipaddress FROM MyTable
  GROUP BY id, ipaddress HAVING COUNT(*) > 1
) AS bb ON bb.id = aa.id AND bb.ipaddress = aa.ipaddress
  AND bb.MID <> aa.id;

このリンクにアクセス

于 2012-10-27T12:30:02.637 に答える