Удаление повторяющихся записей полей в SQL - PullRequest
2 голосов
/ 13 ноября 2009

Можно ли в любом случае удалить все дублирующиеся записи из определенной таблицы (users)? Вот пример типа записей, которые у меня есть. Я должен сказать, что таблица users состоит из 3 полей: ID, user и pass.

mysql_query("DELETE FROM users WHERE ???") or die(mysql_error());

randomtest
randomtest
randomtest
nextfile
baby
randomtest
dog
anothertest
randomtest
baby
nextfile
dog
anothertest
randomtest
randomtest

Я хочу иметь возможность найти дубликаты записей, а затем удалить все дубликаты и оставить один .

Ответы [ 13 ]

5 голосов
/ 13 ноября 2009

Вы можете сделать это с тремя sqls:

create table tmp as select distinct name from users;
drop table users;
alter table tmp rename users;
4 голосов
/ 13 ноября 2009

Вы можете решить это только одним запросом.

Если ваша таблица имеет следующую структуру:

CREATE TABLE  `users` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `username` varchar(45) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;

Вы можете сделать что-то подобное (это удалит всех дублированных пользователей на основе имени пользователя с идентификатором, превышающим меньший идентификатор для этого имени пользователя):

DELETE users
  FROM users INNER JOIN
  (SELECT MIN(id) as id, username FROM users GROUP BY username) AS t
  ON users.username = t.username AND users.id > t.id

Это работает, и я уже использую нечто подобное для удаления дубликатов.

1 голос
/ 13 ноября 2009

Вы должны быть немного осторожны с тем, как используются данные в вашей таблице. Если это действительно таблица пользователей, вероятно, есть другие таблицы с FK, указывающими на столбец ID. В этом случае вам необходимо обновить эти таблицы для использования идентификатора, который вы выбрали для сохранения.

Если это просто отдельная таблица (таблица на нее не ссылается)

CREATE TEMPORARY TABLE Tmp (ID int);
INSERT INTO Tmp SELECT ID FROM USERS GROUP BY User;
DELETE FROM Users WHERE ID NOT IN (SELECT ID FROM Tmp);

Таблица пользователей, связанная с другими таблицами

Создание временных таблиц, включая таблицу ссылок, в которой хранятся все старые идентификаторы и соответствующие новые идентификаторы, на которые вместо этого должны ссылаться другие таблицы.

CREATE TEMPORARY TABLE Keep (ID int, User varchar(45));
CREATE TEMPORARY TABLE Remove (OldID int, NewID int);
INSERT INTO Keep SELECT ID, User FROM USERS GROUP BY User;
INSERT INTO Remove SELECT u1.ID, u2.ID FROM Users u1 INNER JOIN Keep u2 ON u2.User = u1.User WHERE u1.ID NOT IN (SELECT ID FROM Users GROUP BY User);

Просмотрите все таблицы, которые ссылаются на вашу таблицу пользователей, и обновите их столбец FK (вероятно, он называется UserID), чтобы он указывал на новый уникальный идентификатор, который вы выбрали, например, так ...

UPDATE MYTABLE t INNER JOIN Remove r ON t.UserID = r.OldID
SET t.UserID = r.NewID;

Наконец, вернитесь к таблице пользователей и удалите дубликаты, на которые больше нет ссылок:

DELETE FROM Users WHERE ID NOT IN (SELECT ID FROM Keep);

Очистите эти таблицы Tmp:

DROP TABLE KEEP;
DROP TABLE REMOVE;
1 голос
/ 13 ноября 2009

Я предполагаю, что у вас есть такая структура:

users
-----------------
| id | username |
-----------------
|  1 | joe      |
|  2 | bob      |
|  3 | jane     |
|  4 | bob      |
|  5 | bob      |
|  6 | jane     |
-----------------

Требуется волшебство с временным, поскольку MySQL не может использовать суб-выбор в запросе на удаление, который использует таблицу назначения удаления.

CREATE TEMPORARY TABLE IF NOT EXISTS users_to_delete (id INTEGER);

INSERT INTO users_to_delete (id)
    SELECT MIN(u1.id) as id
    FROM users u1
    INNER JOIN users u2 ON u1.username = u2.username
    GROUP BY u1.username;

DELETE FROM users WHERE id NOT IN (SELECT id FROM users_to_delete);

Я знаю, что запрос немного сложный, но он работает, даже если таблица пользователей содержит более 2 столбцов.

1 голос
/ 13 ноября 2009

Этот скрипт удаления (синтаксис SQL Server) должен работать:

DELETE FROM Users
WHERE ID NOT IN (
    SELECT MIN(ID)
    FROM Users
    GROUP BY User
)
0 голосов
/ 13 ноября 2009

Каждый ответ выше и / или ниже не работал для меня, поэтому я решил написать свой собственный маленький сценарий. Это не самое лучшее, но оно выполняет свою работу.
Комментарии включены повсюду, но этот скрипт настроен для моих нужд, и я надеюсь, что идея поможет вам.

Я в основном записал содержимое базы данных во временный файл, называемый временным файлом, применил функцию к вызываемому файлу, чтобы удалить дубликаты, обрезал таблицу и затем ввел данные обратно в SQL. Звучит как много, я знаю.

Если вы не понимаете, что такое $setprofile, это сеанс, который создается при входе в мой скрипт (для создания профиля) и очищается при выходе из системы.


<?php
// session and includes, you know the drill.
session_start();
include_once('connect/config.php');

// create a temp file with session id and current date
$datefile =  date("m-j-Y");
$file = "temp/$setprofile-$datefile.txt";

$f = fopen($file, 'w'); // Open in write mode

// call the user and pass via SQL and write them to $file
$sql = mysql_query("SELECT * FROM _$setprofile ORDER BY user DESC");
while($row = mysql_fetch_array($sql))
{
$user = $row['user'];
$pass = $row['pass'];

$accounts = "$user:$pass "; // the white space right here is important, it defines the separator for the dupe check function
fwrite($f, $accounts);

}
fclose($f);


// **** Dupe Function **** //

// removes duplicate substrings between the seperator
function uniqueStrs($seperator, $str) {
// convert string to an array using ' ' as the seperator
$str_arr = explode($seperator, $str);
// remove duplicate array values
$result = array_unique($str_arr);
// convert array back to string, using ' ' to glue it back
$unique_str = implode(' ', $result);
// return the unique string
return $unique_str;
}

// **** END Dupe Function **** //


// call the list we made earlier, so we can use the function above to remove dupes
$str = file_get_contents($file);
// seperator
$seperator = ' ';
// use the function to save a unique string
$new_str = uniqueStrs($seperator, $str);



// empty the table
mysql_query("TRUNCATE TABLE _$setprofile") or die(mysql_error());

// prep for SQL by replacing test:test with ('test','test'), etc.
// this isn't a sufficient way of converting, as  i said, it works for me.
$patterns = array("/([^\s:]+):([^\s:]+)/", "/\s++\(/");
$replacements = array("('$1', '$2')", ", (");


// insert the values into your table, and presto! no more dupes.
$sql = 'INSERT INTO `_'.$setprofile.'` (`user`, `pass`) VALUES ' . preg_replace($patterns, $replacements, $new_str) . ';';
$product = mysql_query($sql) or die(mysql_error()); // put $new_str here so it will replace new list with SQL formatting

// if all goes well.... OR wrong? :)
if($product){ echo "Completed!";
} else {
echo "Failed!";
}

unlink($file); // delete the temp file/list we made earlier
?>
0 голосов
/ 13 ноября 2009

Выберите 3 столбца в соответствии со структурой таблицы и примените условие в соответствии с вашими требованиями.

SELECT user.userId, user.username user.password ОТ пользователя как пользователь GROUP BY user.userId, user.username HAVING (COUNT (user.username)> 1));

0 голосов
/ 13 ноября 2009

Это будет работать:

create table tmp like users;
insert into tmp select distinct name from users;
drop table users;
alter table tmp rename users;
0 голосов
/ 13 ноября 2009

Временная таблица - отличное решение, но я хотел бы предоставить запрос SELECT, который в качестве альтернативы получает дублирующиеся строки из таблицы:

SELECT * FROM `users` LEFT JOIN (
        SELECT `name`, COUNT(`name`) AS `count`
        FROM `users` GROUP BY `name`
    ) AS `grouped`
    WHERE `grouped`.`name` = `users`.`name`
    AND `grouped`.`count`>1
0 голосов
/ 13 ноября 2009

Если у вас есть уникальный идентификатор / первичный ключ в таблице, то:

DELETE FROM MyTable AS T1
WHERE MyID <
(
    SELECT MAX(MyID)
    FROM MyTable AS T2
    WHERE     T2.Col1 = T1.Col1
          AND T2.Col2 = T1.Col2
          ... repeat for all columns to consider duplicates ...
)

если у вас нет уникального ключа, выделите все отдельные значения во временной таблице, удалите все исходные строки и скопируйте обратно из временной таблицы - но это будет проблематично, если у вас есть внешние ключи, ссылающиеся на эту таблицу

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...