Vấn đề với truy vấn con MySQL


16

Tại sao truy vấn này

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

đôi khi xóa 1 hàng, đôi khi 2 hàng và đôi khi không có gì?

Nếu tôi viết nó dưới dạng này:

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

Sau đó, nó hoạt động chính xác - là vấn đề trong truy vấn con?

Câu trả lời:


13

Lý do truy vấn đầu tiên không hoạt động nhất quán phải liên quan đến cách MySQL xử lý các truy vấn con. Trong thực tế, các truy vấn con sẽ trải nghiệm viết lại và biến đổi .

Có bốn (4) thành phần được giải thích ở đây:

  • Mục_in_optimizer
  • Item_in_subelect
  • Mục numf
  • Left_expression_Cache

Từ các ví dụ được đăng, sẽ không thể cho phép một item_Vf trở thành một tài liệu tham khảo tự. Đối với truy vấn XÓA đơn của bạn, toàn bộ bảng thử nghiệm không thể tự tham chiếu hoàn toàn vì một số khóa có sẵn trong quá trình chuyển đổi và một số thì không. Do đó, khi truy vấn thực hiện tự tham chiếu, một khóa (trong trường hợp này là id) có thể biến mất trong một biến đổi mặc dù bảng tự tham chiếu thực tế có khóa.

Các truy vấn con Mysql chỉ tuyệt vời cho các CHỌN phụ, thậm chí tự tham chiếu một bảng nhiều lần. Điều tương tự không thể được nói cho các truy vấn không CHỌN.

Tôi hy vọng giải thích này sẽ giúp.


7

Tôi nghĩ rằng lý do tại sao nó không hoạt động như mong đợi không phải là cách MySQL xử lý các truy vấn con mà là cách MySQL xử lý các UPDATEcâu lệnh. Tuyên bố:

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

sẽ xử lý WHEREhàng điều kiện theo hàng. Có nghĩa là, đối với mỗi hàng, nó sẽ chạy truy vấn con và kiểm tra kết quả dựa trên id:

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

Vì vậy, đôi khi nó sẽ khớp (và xóa) 0, 1, 2 hoặc thậm chí nhiều hàng hơn!


Bạn có thể viết lại nó như thế này và truy vấn con sẽ được xử lý một lần:

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

1

Từ viên đạn đầu tiên trên trang này , LIMITkhông được hỗ trợ trong các truy vấn con mysql. Tôi không chắc tại sao nó không gây ra lỗi cho bạn.


2
LIMITkhông chỉ được hỗ trợ khi sử dụng IN (<code> được thay thế bằng backticks ~ drachenstern)
tomas.lang

tốt ... tôi đã học được điều gì đó, điều này giải thích tại sao nó không gây ra lỗi!
Derek Downey

@ tomas.lang bạn có thể sử dụng `(đánh dấu) xung quanh từ, thay vì các khối <code>.
Derek Downey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.