2015-11-05 44 views
2

的我编译包含的结构/像这样的数据的数据库:我想消除重复套PHP和MySQL - 一套独特的列

id | col_1 | col_2 | col_3 | col_4 
----------------------------------- 
0 | a | b | c | d 
1 | a | b | d | c 
2 | a | c | b | d 

,所以在上面的例子中,所有三排有相同的四个值(显然除外id),所以我想消除所有重复的集合。有没有一种快速/优雅的方式来做到这一点?

我现在正在做的是按字母顺序排序每个集合,保存到数组,然后比较数组。这工作得很好,当你有行100的,但我知道这是不够的高效运行1000年或数百万行的数据集....

编辑:

预期输出:

id | col_1 | col_2 | col_3 | col_4 
----------------------------------- 
0 | a | b | c | d 

只要只有一个唯一集合,它确实对列或顺序很重要。除非我失去了一些东西MySQL的UNIQUE约束就不会在这里工作......

SQL Fiddle

+0

因此,所有3行都将被删除? – Mihai

+0

请定义重复的集合,列的问题?重复项必须位于同一列吗? – AgeDeO

+0

你会保留哪一个?什么是可能的值范围? – Strawberry

回答

0

这里是一个PHP的解决方案:

$distinct = array(); 
$duplicates = array(); 

$stmt = $pdo->query("SELECT id, col_1, col_2, col_3, col_4 FROM my_table"); 
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
    $id = array_shift($row); 
    $row = asort($row); 
    $key = implode('.', $row); 

    if (isset($distinct[$key])) { 
     $duplicates[] = $id; 
    } else { 
     $distinct[$key] = $id; 
    } 
} 

$pdo->beginTransaction(); 

$idToBeDeleted = 0; 

$stmt = $pdo->query("DELETE FROM my_table WEHRE id = :id"); 
$stmt->bindParam(':id', $idToBeDeleted, PDO::PARAM_INT); 

foreach ($duplicates as $duplicate) { 
    $idToBeDeleted = $duplicate; 
    $stmt->execute(); 
} 

$pdo->commit(); 

如果您有可能会做提交数据库许多行在10.000块删除之后。

请注意,此代码未经测试,可能需要做一些更改才能工作。

2

这里是一个纯粹的MySQL的答案:

我已经扩展您的样本数据:

DROP TABLE IF EXISTS test; 
CREATE TABLE test (
id INT(11) AUTO_INCREMENT PRIMARY KEY, 
col_1 VARCHAR(128), 
col_2 VARCHAR(128), 
col_3 VARCHAR(128), 
col_4 VARCHAR(128) 
); 

INSERT INTO test VALUES (1,'a','b','c','d'),(2,'a','b','d','c'),(3,'a','d','c','b'),(4,'a','c','d','b'),(5,'e','f','g','h'),(6,'f','h','g','e') 
; 

SELECT * FROM test; 

+----+-------+-------+-------+-------+ 
| id | col_1 | col_2 | col_3 | col_4 | 
+----+-------+-------+-------+-------+ 
| 1 | a  | b  | c  | d  | 
| 2 | a  | b  | d  | c  | 
| 3 | a  | d  | c  | b  | 
| 4 | a  | c  | d  | b  | 
| 5 | e  | f  | g  | h  | 
| 6 | f  | h  | g  | e  | 
+----+-------+-------+-------+-------+ 

一个辅助表开始发挥作用:

DROP TABLE IF EXISTS tmp_test; 
CREATE TABLE tmp_test (id int, col varchar(128)); 

INSERT INTO tmp_test 
SELECT id, col_1 FROM test 
UNION 
SELECT id, col_2 FROM test 
UNION 
SELECT id, col_3 FROM test 
UNION 
SELECT id, col_4 FROM test 
; 

然后我截断原始表

TRUNCATE TABLE test; 

ALTER TABLE test AUTO_INCREMENT = 1; 

,以便可以用“不同”值重新填充:

INSERT INTO test (col_1, col_2, col_3, col_4) 
SELECT SUBSTRING_INDEX(gc, '@', 1), SUBSTRING(SUBSTRING_INDEX(gc, '@', 2) FROM LOCATE('@', gc) + 1), SUBSTRING(SUBSTRING_INDEX(gc, '@', 3) FROM LENGTH(SUBSTRING_INDEX(gc, '@', 3))), REVERSE(SUBSTRING_INDEX(REVERSE(gc), '@', 1)) 
FROM (
    SELECT DISTINCT 
    GROUP_CONCAT(col ORDER BY col SEPARATOR '@') AS gc 
    FROM tmp_test 
    GROUP BY id 
) sq; 

SELECT * FROM test; 

+----+-------+-------+-------+-------+ 
| id | col_1 | col_2 | col_3 | col_4 | 
+----+-------+-------+-------+-------+ 
| 1 | a  | b  | c  | d  | 
| 2 | e  | f  | g  | h  | 
+----+-------+-------+-------+-------+ 
+0

这看起来正是我所期待的!谢谢,今晚将测试并将答案标记为已接受! :) –