Làm thế nào SQL có thể xóa bằng cách sử dụng một truy vấn phụ


15

Mã sau đây đã được một trong các nhà phát triển của chúng tôi thêm vào để xóa các bản ghi trùng lặp khỏi bảng:

DELETE  SubQuery

FROM
(
    SELECT  ID
            ,FK1
            ,FK2
            ,CreatedDateTime
            ,ROW_NUMBER() OVER(PARTITION BY FK1, FK2 ORDER BY CreatedDateTime) AS RowNumber

    FROM    Table
)
AS SubQuery

WHERE   RowNumber > 1

Khi xem xét mã, tôi cho rằng nó sẽ không hoạt động, tuy nhiên việc kiểm tra nó trong môi trường thử nghiệm của chúng tôi (SQL 2014) cho thấy rằng nó hoạt động!

Làm thế nào để SQL biết để giải quyết các truy vấn phụ và xóa các bản ghi từ đó table?

Câu trả lời:


14

subquerybạn có trong mã của bạn được gọi là bảng dẫn xuất . Đó không phải là một bảng cơ sở mà là một bảng "sống" trong suốt thời gian truy vấn chạy. Giống như các khung nhìn (còn được gọi là các bảng đã xem ) - và trong các phiên bản gần đây, CTE là một cách khác, cách thứ 4 để "xác định" một bảng bên trong một truy vấn - chúng tương tự như một bảng theo nhiều cách. Bạn có thể selecttừ chúng, bạn có thể sử dụng chúng trong fromhoặc cho joinchúng vào các bảng khác (cơ sở hoặc không!).

Trong một số DBMS, (không phải tất cả DBMS đều thực hiện theo cách tương tự) các bảng / khung nhìn này có thể cập nhật được . Và "cập nhật" có nghĩa là chúng ta cũng có thể update, insertvào hoặc deletetừ chúng.

Có những hạn chế mặc dù và điều này được mong đợi. Hãy tưởng tượng nếu subquerylà một tham gia của 2 (hoặc 17 bảng). Điều đó deletecó nghĩa là gì? (từ những bảng nào nên xóa hàng?) Lượt xem cập nhật là một vấn đề rất phức tạp . Có một cuốn sách gần đây (2012), hoàn toàn về chủ đề này, được viết bởi Chris Date, chuyên gia nổi tiếng về lý thuyết quan hệ: Xem Cập nhật và Lý thuyết quan hệ .

Khi bảng dẫn xuất (hoặc dạng xem) là một truy vấn rất đơn giản, giống như nó chỉ có một bảng cơ sở (có thể bị giới hạn bởi a WHERE) và không GROUP BY, thì mỗi hàng của bảng dẫn xuất tương ứng với một hàng trong bảng cơ sở bên dưới, vì vậy nó là dễ dàng * để cập nhật, chèn hoặc xóa từ này.

Khi mã bên trong truy vấn con phức tạp hơn, nó phụ thuộc vào việc các hàng của bảng / khung nhìn dẫn xuất có thể được theo dõi / phân giải thành các hàng từ một trong các bảng cơ sở bên dưới hay không.

Đối với SQL Server, bạn có thể đọc thêm trong đoạn Lượt xem cập nhật trong MSDN : CREATE VIEW.

Lượt xem cập nhật

Bạn có thể sửa đổi dữ liệu của bảng cơ sở bên dưới thông qua chế độ xem, miễn là các điều kiện sau là đúng:

  • Mọi sửa đổi, bao gồm UPDATE, INSERTvà các DELETEcâu lệnh, phải tham chiếu các cột từ chỉ một bảng cơ sở.

  • Các cột được sửa đổi trong dạng xem phải tham chiếu trực tiếp dữ liệu cơ bản trong các cột của bảng. Các cột không thể được dẫn xuất theo bất kỳ cách nào khác, chẳng hạn như thông qua các điều sau đây:

  • Một chức năng tổng hợp: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR, và VARP.

  • Một tính toán. Cột không thể được tính từ một biểu thức sử dụng các cột khác. Cột được hình thành bằng cách sử dụng các toán tử set UNION, UNION ALL, CROSSJOIN, EXCEPT, và INTERSECT số tiền một tính toán và cũng không thể cập nhật.

  • Các cột được sửa đổi không bị ảnh hưởng bởi GROUP BY, HAVINGhoặc DISTINCTmệnh đề.

  • TOPkhông được sử dụng ở bất cứ đâu trong select_statement của khung nhìn cùng với WITH CHECK OPTIONmệnh đề.

Các hạn chế trước đó áp dụng cho bất kỳ truy vấn con nào trong FROMmệnh đề của khung nhìn, giống như chúng áp dụng cho chính khung nhìn. Nói chung, Công cụ cơ sở dữ liệu phải có khả năng theo dõi rõ ràng các sửa đổi từ định nghĩa khung nhìn sang một bảng cơ sở.


Thật ra deletethì dễ hơn, ít phức tạp hơn update. SQL Server chỉ cần các khóa chính hoặc một số cách khác để xác định các hàng của bảng cơ sở sẽ bị xóa. Đối với update, có một hạn chế bổ sung (khá rõ ràng) mà chúng tôi không thể cập nhật một cột được tính toán. Bạn có thể cố gắng sửa đổi truy vấn của mình để thực hiện cập nhật. Cập nhật CreatedDateTimecó thể sẽ hoạt động tốt nhưng cố gắng cập nhật RowNumbercột được tính toán sẽ gây ra lỗi. Và insertthậm chí còn phức tạp hơn, vì chúng ta phải cung cấp các giá trị cho tất cả các cột của bảng cơ sở không có DEFAULTràng buộc.


4

Thật dễ dàng để xem khi bạn nhìn vào kế hoạch truy vấn. Trong trường hợp của bạn, gói chỉ chứa toán tử Dự án Phân đoạn và Dự án bổ sung để xử lý số hàng. Kiểu hoạt động này chỉ hoạt động khi SQL Server thực sự có thể giải quyết bảng bên dưới.

Xóa khỏi các truy vấn con và CTE được hỗ trợ đầy đủ và rất hiệu quả, đặc biệt là để loại bỏ các bản sao. Tôi dường như cũng nhớ lại việc sử dụng nó trên các phiên bản SQL Server cũ hơn.

Thêm trong một bài viết blog cũ của tôi.

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.