Як видалити з select у MySQL?


86

Цей код не працює для MySQL 5.0, як переписати його, щоб він працював

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

Я хочу видалити стовпці, які не мають унікального ідентифікатора. Додам, що більшу частину часу це єдиний ідентифікатор (я спробував in-синтаксис, і він теж не працює).

Відповіді:


212

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 рядок. Потім усі дублікати ключів куди зникли. Чому це?
— Олексій

Це відбувається, тому що ви SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
— вилучаєте

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

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

1
Поясніть, будь ласка, що означає "Як 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
@Andrew: Так. Функціонально ці об'єднання абсолютно однакові.
— 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.