Как вы можете найти строки с одинаковыми столбцами? - PullRequest
4 голосов
/ 17 сентября 2009

Если у меня есть таблица с важными 2 столбцами,

CREATE TABLE foo (id INT, a INT, b INT, KEY a, KEY b);

Как я могу найти все строки, в которых a и b одинаковы в обеих строках? Например, в этом наборе данных

id | a | b
----------
1  | 1 | 2
2  | 5 | 42
3  | 1 | 42
4  | 1 | 2 
5  | 1 | 2
6  | 1 | 42

Я хочу вернуть все строки, кроме id=2, поскольку он уникален в (a,b). По сути, я хочу найти все ошибочные строки, которые остановили бы

ALTER TABLE foo ADD UNIQUE (a, b);

Было бы неплохо что-то лучше, чем цикл n ^ 2 for, так как в моей таблице 10M строк.

Для бонусных баллов : Как убрать все, кроме одного из рядов (мне все равно, какие из них, пока один остается)

Ответы [ 8 ]

1 голос
/ 17 сентября 2009

Попробуйте это:

    With s as (Select a,b from foo group by a,b having Count(1)>1)
Select foo.* from foo,s where foo.a=s.a and foo.b=s.b

В этом запросе должны отображаться повторяющиеся строки в таблице foo.

1 голос
/ 17 сентября 2009

Не могли бы вы уточнить, что вам нужно сделать в конечном итоге? Наилучшее решение может зависеть от этого (например, хотите ли вы просто удалить все строки с дублирующими ключами?)

Один из способов - обработать эту таблицу (не уверен, что mySQL ее поддерживает, она из SYBASE), если вам нужны строки с уникальным ключом:

SELECT MIN(id), A, B FROM FOO GROUP BY A, B HAVING COUNT(*)>1

Ваш точный вопрос (хотя я немного растерялся относительно того, зачем вам нужны все строки, кроме id = 2):

SELECT F1.*  
FROM FOO F1 , 
     (SELECT A, B FROM FOO GROUP BY A, B HAVING COUNT(*)>1) F2
WHERE F1.A=F2.A and F1.B=F2.B

Чтобы удалить все дубликаты, вы можете, например, сделать

DELETE FOO WHERE NOT EXISTS
(SELECT 1 from
    (SELECT MIN(id) 'min_id' FROM FOO GROUP BY A, B HAVING COUNT(*)>1) UINIQUE_IDS 
 WHERE id = min_id)

В качестве альтернативы вы можете сделать

  SELECT MIN(id) 'id', A, B INTO TEMPDB..NEW_TABLE 
  FROM FOO GROUP BY A, B HAVING COUNT(*)>1

  TRUNCATE TABLE FOO
  // Drop indices on FOO
  INSERT FOO SELECT * FROM NEW_TABLE
  // Recreate indices on FOO
1 голос
/ 17 сентября 2009
SELECT * 
FROM foo first
JOIN foo second
  ON ( first.a = second.a
       AND first.b = second.b ) 
  AND (first.id <> second.id )

Должны появиться все строки, в которых более одной строки имеют одинаковую комбинацию a и b.

Просто надеюсь, что у вас есть индекс по столбцам a и b.

1 голос
/ 17 сентября 2009

разве это не должно работать?

SELECT * FROM foo WHERE a = b

=== edit ===

как насчет

SELECT a, b FROM foo GROUP BY a, b HAVING COUNT(*) > 1

=== окончательно отредактируйте, прежде чем я оставлю этот вопрос ===

SELECT foo.* FROM foo, (
   SELECT a, b FROM foo GROUP BY a, b HAVING COUNT(*) > 1
) foo2
WHERE foo.a = foo2.a AND foo.b = foo2.b
1 голос
/ 17 сентября 2009
select * from foo where a = b

Или я что-то упустил?

===

Обновление для ясности:

select * from 
foo as a
inner join foo as b
on a.a = b.a AND b.a = b.b
and a.id != b.id

++++++++++ После 3-й ясности отредактируйте:

select f1.id
FROM foo as f1
INNER JOIN foo as f2
ON f1.a = f2.a AND f1.b=f2.b AND f1.id != f2.id

Но я застрелен, так что проверь это сам.

0 голосов
/ 17 сентября 2009

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

0 голосов
/ 17 сентября 2009

Ваша заявленная цель - удалить все повторяющиеся комбинации (a,b). Для этого вы можете использовать мульти-таблицу DELETE:

DELETE t1
  FROM foo t1
  JOIN foo t2 USING (a, b)
 WHERE t2.id > t1.id

Перед запуском вы можете проверить, какие строки будут удалены с помощью:

SELECT DISTINCT t1.id
  FROM foo t1
  JOIN foo t2 USING (a, b)
 WHERE t2.id > t1.id

Предложение WHERE, являющееся t2.id > t1.id, удалит все, кроме одного с наибольшим значением для id. В вашем случае останутся только строки с id, равным 2, 5 или 6.

0 голосов
/ 17 сентября 2009

вот другой подход

select * from foo f1 where exists(
  select * from foo f2 where
    f1.id != f2.id and
    f1.a = f2.a and
    f1.b = f2.b )

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

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

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