PHP和MySQL-唯一的列集

PHP和MySQL-唯一的列集,php,mysql,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),因此我想消除所有重复集。有没有一种快速

我正在编译一个包含如下结构/数据的数据库:

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唯一约束在这里不起作用,除非我遗漏了一些东西


以下是一个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个数据块后进行提交


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

以下是一个纯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;
以便可以用“不同”值重新填充:


那么所有3行都将被删除?请定义重复集,列是否重要?副本必须在同一列吗?你会保留哪一个?可能值的范围是多少?请公布您的预期输出应该是多少?好的,我明白您的意思。这似乎正是我想要的!谢谢,今晚将进行测试,并将答案标记为已接受!:)
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     |
+----+-------+-------+-------+-------+