MySQL alt sorgusu ile ilgili sorun


16

Bu sorgu neden

DELETE FROM test 
WHERE id = ( SELECT id 
             FROM (SELECT * FROM test) temp 
             ORDER BY RAND() 
             LIMIT 1
           );

bazen 1 satır, bazen 2 satır ve bazen hiçbir şey silmek?

Bu formda yazarsam:

SET @var = ( SELECT id 
             FROM (SELECT * FROM test) temp 
             ORDER BY RAND() 
             LIMIT 1
           ); 
DELETE FROM test 
WHERE id=@var;

o zaman düzgün çalışır - alt sorguda sorun mu?

Yanıtlar:


13

İlk sorgunun tutarlı çalışmamasının nedeni, MySQL'in alt sorguları nasıl işlediği ile ilgilidir. Aslında, alt sorgular yeniden yazma ve dönüşümler yaşayacaktır .

Burada açıklanan dört (4) bileşen vardır:

  • Item_in_optimizer
  • Item_in_subselect
  • Item_ref
  • Left_expression_Cache

Gönderilen örneklerden, bir item_ref öğesinin kendi referansı olmasına izin vermek imkansızdır. Tek DELETE sorgunuz açısından, bir bütün olarak sınama tablosu tamamen kendini referans edemez, çünkü bazı anahtarlar dönüştürme sırasında kullanılabilir ve bazıları değildir. Bu nedenle, bir sorgu kendi kendine başvuru gerçekleştirdiğinde, gerçek kendinden başvurulan tablonun anahtarı olmasına rağmen bir anahtar (bu durumda id) bir dönüşümde kaybolabilir.

Mysql alt sorguları, yalnızca bir tabloya birden çok kez başvuruda bulunsa bile, alt SELECT'ler için mükemmeldir. Aynı durum SELECT olmayan sorgular için söylenemez.

Umarım bu açıklama yardımcı olur.


7

Bence neden beklendiği gibi çalışmıyor neden MySQL alt sorguları işleme değil, MySQL UPDATEifadeleri nasıl işlediğidir . İfade:

DELETE 
FROM test 
WHERE id = 
      ( SELECT id 
        FROM 
            ( SELECT * 
              FROM test
            ) temp 
        ORDER BY RAND() 
        LIMIT 1
      ) 

WHEREkoşulu satır satır işleyecek . Yani, her satır için alt sorguyu çalıştırır ve sonucu aşağıdakilere karşı test eder id:

  ( SELECT id 
    FROM 
        ( SELECT * 
          FROM test
        ) temp 
    ORDER BY RAND() 
    LIMIT 1
  ) 

Yani, zaman zaman 0, 1, 2 veya daha fazla satırı eşleştirecek (ve silecek)!


Bu şekilde yeniden yazabilirsiniz ve alt sorgu bir kez işlenir:

DELETE t
FROM 
      test t
  JOIN 
      ( SELECT id 
        FROM test  
        ORDER BY RAND() 
        LIMIT 1
      ) tmp
    ON tmp.id = t.id

1

İlk kurşunun itibaren bu sayfada , LIMITMySQL alt sorgular desteklenmez. Yine de neden senin için bir hata atmadığından emin değilim.


2
LIMITyalnızca kullanım için desteklenmez IN (<code>, ters tırnaklarla değiştirilir ~ drachenstern)
tomas.lang

şey ... Neden bir hata atmadığını açıklayan bir şey öğrendim!
Derek Downey

@ tomas.lang, sözcüğü çevreleyen <code> blokları yerine `(onay işaretleri) kullanabilirsiniz.
Derek Downey
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.