Как удалить из выбора в MySQL?


86

Этот код не работает для MySQL 5.0, как его переписать, чтобы он работал

DELETE FROM posts where id=(SELECT id FROM posts GROUP BY id  HAVING ( COUNT(id) > 1 ))

Я хочу удалить столбцы, у которых нет уникального идентификатора. Я добавлю, что в большинстве случаев это только один идентификатор (я пробовал синтаксис in, и он тоже не работает).

Ответы:


213

SELECT(под) запросы возвращают наборы результатов . Так что вам нужно использовать IN, а не =в вашем WHEREпредложении.

Кроме того, как показано в этом ответе, вы не можете изменить ту же таблицу из подзапроса в том же запросе. Тем не менее, вы можете SELECTзатем DELETEв отдельных запросах, или гнездо другого подзапроса и псевдоним в результате внутреннего подзапроса (выглядит довольно Hacky, хотя):

DELETE FROM posts WHERE id IN (
    SELECT * FROM (
        SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
    ) AS p
)

Или используйте объединения, как предлагает Mchl .


1
У меня была таблица со 150 дублирующими ключами. Я выполнил вышеуказанный запрос, и он сказал: «Затронуто 144 строки», но там все еще есть повторяющиеся ключи. Итак, я снова выполнил запрос, и он снова говорит, что затронуты 5 строк: затронута 1 строка. Потом все дубликаты ключей пропали. Почему это?
Alex

Это происходит, потому что вы SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
удаляете только одну

# 1248 - Каждая производная таблица должна иметь свой собственный псевдоним
Тханг

@thang: Вот почему я сказал использовать псевдоним внутреннего подзапроса.
BoltClock

1
Не могли бы вы объяснить, что делает "As p"?
Игрок в крикет,

22
DELETE 
  p1
  FROM posts AS p1 
CROSS JOIN (
  SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1
) AS p2
USING (id)

Кажется, это работает, но меня смущает синтаксис, и я не могу найти никаких ресурсов, чтобы объяснить это. CROSS JOINпо-видимому, выполняет декартово соединение, поэтому кажется, что это может сделать ненужную работу или выполнить неоптимально? Кто-нибудь может объяснить?
wintron

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

Могли бы вы сделать то же самое с внутренним соединением? IEDELETE p1 FROM posts AS p1 INNER JOIN ( SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1 ) AS p2 ON p2.ID=p1.ID
Кодос Джонсон

1
@ Андрей: Да. Функционально эти соединения абсолютно одинаковы.
Mchl

5

вы можете использовать внутреннее соединение:

DELETE 
    ps 
FROM 
    posts ps INNER JOIN 
         (SELECT 
           distinct id 
         FROM 
             posts 
         GROUP BY id  
      HAVING COUNT(id) > 1 ) dubids on dubids.id = ps.id  

0

Если вы хотите удалить все дубликаты, но по одному из каждого набора дубликатов, это одно из решений:

DELETE posts
FROM posts
LEFT JOIN (
    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) = 1

    UNION

    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) != 1
) AS duplicate USING (id)
WHERE duplicate.id IS NULL;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.