2009-11-13 2 views
2

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

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 

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

+0

Возможно, стоит рассмотреть другие подобные вопросы здесь http://stackoverflow.com/search?q=%5Bsql%5D+%5Bduplicates%5D+delete – Kristen

ответ

4

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

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

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; 

вы могли бы сделать что-то подобное (это будет удалить все дубликаты пользователей на основе имени пользователя с и ID больше, чем меньший ID для этого пользователя):

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 

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

+0

ЭТО РАБОТЫ. Я написал этот бесполезный сценарий ни за что! Http: // StackOverflow.com/questions/1728048/remove-duplicate-field-entries-in-sql/1728724 # 1728724 – Homework

+0

Ну, большинство людей не знают, что вы можете делать подобные вещи с MySQL. Фактически, возможно даже удалить связанные записи из двух или более разных таблиц одновременно. – Sergi

+0

Он не обрабатывает связанные таблицы с FK, но, кажется, в этом случае у него его нет! – badbod99

0

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

Edit: Моя ошибка, я не читал, что последняя строка: «Я хочу, чтобы иметь возможность найти повторяющиеся записи».

+1

Но теперь это поможет ему избавиться от существующих повторяющихся значений. Фактически он не сможет создать такой индекс, если таблица уже содержит повторяющиеся значения. – Tomas

+0

Я знаю это, но не будет ли это выводить сообщение об ошибке, если вы попытаетесь ввести дубликаты данных? Предположим, я попытался загрузить список имен пользователей. Дубликаты скрывают список влево и вправо. Что случилось бы? – Homework

+0

@ Томас Ровно! – Homework

0

Я бы получил все результаты, поставил их в массив ID и VALUES. Используйте функцию PHP для работы с обманами, запишите все идентификаторы в массиве и используйте эти значения для удаления записей.

+0

Доступ предоставляется. Хотя парень ответил на вопрос, его способ удаления дубликатов намного проще. http://stackoverflow.com/questions/1728048/removing-duplicate-field-entries-in-sql/1728724#1728724 – Homework

0

Я не знаю вашу схему db, но самое простое решение состоит в том, чтобы сделать SELECT DISTINCT в этой таблице, сохранить результат в переменной (то есть массиве), удалить все записи из таблицы, а затем повторно вставить список returne по SELECT DISTINCT ранее.

+2

Вы не получите столбец идентификатора, используя выделение, указанное в имени пользователя. Если вы укажете столбец идентификатора в элементе выбора, вы снова получите всю строку. – badbod99

5

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

create table tmp as select distinct name from users; 
drop table users; 
alter table tmp rename users; 
+0

Звучит так, как будто это на самом деле работает, тестируя сейчас. – Homework

+3

Не будет работать, если внешние ключи нацелены на эту таблицу, хотя (нужно удалить и воссоздать эти FK) – Kristen

+0

Мне просто интересно, могут ли внешние ключи работать в ситуации с дублирующимися записями? (не иронично, просто спрашиваю, потому что я не знаю ...) – fritzone

-1

Если у вас есть уникальный ID/первичный ключ на столе затем:

 
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 ... 
) 

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

+0

P.S. А затем добавьте UNIQUE INDEX в этот столбец :) – Kristen

+0

Будьте осторожны. Убедитесь, что вы добавили другое предложение where, чтобы однозначно идентифицировать имя пользователя, которое вы хотите удалить во внешнем запросе, иначе вы получите таблицу, содержащую только имя пользователя. :) – ZombieSheep

+0

Это не сработает, так как в MySQL вам не разрешено иметь цель подвыборки так же, как цель удаления. Запустите его, и вы увидите. –

0

Закладка временной ле является отличным решением, но я хотел бы предоставить 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 
1

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

DELETE FROM Users 
WHERE ID NOT IN (
    SELECT MIN(ID) 
    FROM Users 
    GROUP BY User 
) 
+0

Это не работает, поскольку в MySQL вам не разрешено иметь суб- Цель select должна быть такой же, как и цель удаления. Запустите его, и вы увидите. –

+0

Не работает вообще. – Homework

+0

@Emil: У меня есть только SQL Server. – cjk

0

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

create table tmp like users; 
insert into tmp select distinct name from users; 
drop table users; 
alter table tmp rename users; 
0

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

ВЫБОР user.userId, user.username user.password ОТ пользователя Как пользователь GROUP BY user.userId, user.username HAVING (COUNT (пользователя.имя пользователя)> 1));

1

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

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

Doing магию с временным требуется, так как 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); 

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

+0

+1 для временного стола temp для неспособности MySQL сделать это правильно :) – cjk

1

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

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

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); 

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

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

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); 

Go через любые таблицы, которые ссылаются на таблицу пользователей и обновлять их столбец 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; 
0

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

Я в основном написал содержимое базы данных временному файлу, называемому временным файлом, применил функцию к вызываемому файлу, чтобы удалить дубликаты, усечь таблицу и затем ввести данные обратно в 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 
?> 

 Смежные вопросы

  • Нет связанных вопросов^_^