MySQL DELETE FROM ile alt sorgu koşul olarak


87

Bunun gibi bir sorgu yapmaya çalışıyorum:

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015
);

Muhtemelen anlayabileceğiniz gibi, aynı tid'in başka ebeveynleri varsa, 1015 ile ebeveyn ilişkisini silmek istiyorum. Ancak bu bana bir sözdizimi hatası veriyor:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS th
WHERE th.parent = 1015 AND th.tid IN (
  SELECT DISTINCT(th1.tid)
  FROM ter' at line 1

Belgeleri kontrol ettim ve alt sorguyu kendim çalıştırdım ve hepsi kontrol edilmiş gibi görünüyor. Burada neyin yanlış olduğunu bilen var mı?

Güncelleme : Aşağıda yanıtlandığı gibi, MySQL, silmekte olduğunuz tablonun koşul için bir alt sorguda kullanılmasına izin vermez.


3
Dikkat : En alttaki stackoverflow.com/a/4471359/956397 adresinde iyi yanıt , tablo diğer adınıDELETE t FROM table t ...
PiTheNumber

Yanıtlar:


40

Silme için hedef tablo belirleyemezsiniz.

Bir geçici çözüm

create table term_hierarchy_backup (tid int(10)); <- check data type

insert into term_hierarchy_backup 
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015;

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (select tid from term_hierarchy_backup);

ikimiz de haklıyız - aşağıdaki cevabıma yaptığı açıklamaya bakın. Takma ad sözdizimi ve mantığın her ikisi de sorun oldu :)
JNK

Evet, alt sorgu yoluyla silmek şu anda
MySQL'de

o son satırdaki "terim_hiyerarşisinden SİL" in de aynı problemi yok mu? OP ile aynı sözdizimi hatası alıyorum.
malhal

Term_hierarchy_backup.tid dosyasına Dizin eklemelisiniz.
Roman Newaza

1
Bunun 2019'da MariaDB 10.3.14 veya MySQL Community Server 5.7.27
alpham8

292

Bir alt sorgu kullanırken bu soruyu silmek isteyenler için, size MySQL'i alt etmek için bu örneği bırakıyorum (bazı insanlar bunun yapılamayacağını düşünse bile):

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM tableE
             WHERE arg = 1 AND foo = 'bar');

size bir hata verecektir:

ERROR 1093 (HY000): You can't specify target table 'e' for update in FROM clause

Ancak bu sorgu:

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM (SELECT id
                   FROM tableE
                   WHERE arg = 1 AND foo = 'bar') x);

gayet iyi çalışacak:

Query OK, 1 row affected (3.91 sec)

Alt sorgunuzu ek bir alt sorguya sarın (burada x olarak adlandırılır) ve MySQL istediğinizi mutlu bir şekilde yapacaktır.


10
Biraz zaman aldı ama işe yaradı. Önemli: 1) İlk tablonun diğer adı burada "e" ile gösterildiği gibi olmalıdır, 2) sondaki "x" bir yer tutucu değil, alt sorgu tarafından üretilen geçici tablo için takma addır "(SELECT id FROM tableE NEREDE arg = 1 VE foo = 'bar') ".
Tilman Hausherr

3
Bu neden işe yarıyor? Bu benim için çok değişiyor ama dahası işe yaramamalı. O does işi, ama bu olmamalıdır.
donatJ

1
Inanılmaz. bu gerçekten çalışıyor! ancak tabloya e ile takma ad vermek zorunda değilsiniz ... istediğiniz herhangi bir takma adı kullanabilirsiniz.
Andrei Sandulescu

1
@jakabadambalazs Bunu bulduğumdaki mantığım, "SELECT id" ile başlayan alt sorgunun bitmesi ve bir kimlik listesi döndürmesi ve bu nedenle silmek istediğiniz tablonun kilidini serbest bırakmasıydı.
CodeReaper

9
@jakabadambalazs: Aynı tabloyu ( e) bir DELETE'de ve alt SELECT'te kullanamayız . Biz edebilir , ancak geçici bir tablo (oluşturmak için bir alt alt SEÇ kullanmak x) ve kullanımını bu alt SEÇMEK için.
Steve Almond

40

Takma ad, DELETEanahtar kelimeden sonra eklenmelidir :

DELETE th
FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN 
(
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015
);

3
Bu iyi bir cevap. Doğru Takma Adlandırma, orijinal gönderiye benzer sorunları çözmek için uzun bir yol kat edecektir. (Mine gibi.)
usumoio

11

Silme ifadesinde takma ada tekrar başvurmanız gerekir, örneğin:

DELETE th FROM term_hierarchy AS th
....

Burada MySQL belgelerinde belirtildiği gibi.


takma adla ilgili değil, lütfen
OP'yi

@ajreal - Yaptım ve lütfen hatanın takma ad tanımında başladığına dikkat edin ve MySQL dokümantasyonu, hem DELETE deyiminde hem de FROM yan tümcesinde takma adı kullanmanız gerektiğini açıkça belirtir. Olumsuz oy için teşekkürler.
JNK

basitçe bunu delete from your_table as t1 where t1.id in(select t2.id from your_table t2);yaptın ne aldın?
ajreal

4
Belgeler açıkça belirtmektedir; Currently, you cannot delete from a table and select from the same table in a subquery. dev.mysql.com/doc/refman/5.5/en/delete.html
Björn

1
takma adı düzeltmeniz gerekmez, silme
işleminde

7

Buna biraz farklı bir şekilde yaklaştım ve benim için işe yaradı;

Artık koşul satırlarının kalmadığı tabloya secure_linksbaşvuran tablodan kaldırmam gerekiyordu conditions. Temelde bir temizlik senaryosu. Bu bana hatayı verdi - Silme için hedef tablo belirleyemezsiniz.

Bu yüzden ilham almak için buraya bakarken aşağıdaki sorguyu buldum ve gayet iyi çalışıyor. Bunun nedeni sl1, DELETE için referans olarak kullanılan geçici bir tablo oluşturmasıdır.

DELETE FROM `secure_links` WHERE `secure_links`.`link_id` IN 
            (
            SELECT
                `sl1`.`link_id` 
            FROM 
                (
                SELECT 

                    `sl2`.`link_id` 

                FROM 
                    `secure_links` AS `sl2` 
                    LEFT JOIN `conditions` ON `conditions`.`job` = `sl2`.`job` 

                WHERE 

                    `sl2`.`action` = 'something' AND 
                    `conditions`.`ref` IS NULL 
                ) AS `sl1`
            )

Benim için çalışıyor.


Yukarıdaki @CodeReaper'dan birinin kopyası ... iyi çağrı tho ...;)
jrypkahauer

5

Silme işlemindeki "in" cümlesi ... alt sorgudan çok sayıda değer döndürülecekse son derece verimsiz değil mi? Neden bizden "in (alt sorgu)" yerine silinecek kimlikteki alt sorgudan orijinal tabloya sadece iç (veya sağ) geri birleşmeyeceğinizden emin değil misiniz?

DELETE T FROM Target AS T
RIGHT JOIN (full subquery already listed for the in() clause in answers above) ` AS TT ON (TT.ID = T.ID)

Ve belki de "MySQL buna izin vermiyor" bölümünde yanıtlanmıştır, ancak benim için iyi çalışıyor SAĞLANMIŞ Neyi sileceğimi tam olarak açıkladığımdan eminim (T Hedef AS T SİL). Join ile Sil MySQL , DELETE / JOIN sorununu açıklığa kavuşturur.


2

Bunu 2 sorgu ile yapmak istiyorsanız, her zaman buna benzer bir şey yapabilirsiniz:

1) aşağıdaki tablodan kimlikleri alın:

SELECT group_concat(id) as csv_result FROM your_table WHERE whatever = 'test' ...

Ardından, sonucu fare / klavye veya programlama diliyle aşağıdaki XXX'e kopyalayın:

2) DELETE FROM your_table WHERE id IN ( XXX )

Belki bunu tek bir sorguda yapabilirsiniz, ama tercih ettiğim şey bu.


0

@CodeReaper, @BennyHill: Beklendiği gibi çalışıyor.

Bununla birlikte, tabloda milyonlarca satır olması için zaman karmaşıklığını merak ediyorum. Görünüşe göre, 5msdoğru şekilde indekslenmiş bir tabloda 5k kayıtlara sahip olmak için yürütülmesi gerekti.

Sorgum:

SET status = '1'
WHERE id IN (
    SELECT id
    FROM (
      SELECT c2.id FROM clusters as c2
      WHERE c2.assign_to_user_id IS NOT NULL
        AND c2.id NOT IN (
         SELECT c1.id FROM clusters AS c1
           LEFT JOIN cluster_flags as cf on c1.last_flag_id = cf.id
           LEFT JOIN flag_types as ft on ft.id = cf.flag_type_id
         WHERE ft.slug = 'closed'
         )
      ) x)```

Or is there something we can improve on my query above?

0

takma adı bu şekilde delete ifadesinde kullanabilirsiniz

DELETE  th.*
FROM term_hierarchy th
INNER JOIN term_hierarchy th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th.parent = 1015;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.