Làm cách nào để xóa khỏi nhiều bảng bằng INNER JOIN trong máy chủ SQL


117

Trong MySQL, bạn có thể sử dụng cú pháp

DELETE t1,t2 
FROM table1 AS t1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

Làm cách nào để làm điều tương tự trong SQL Server?

Câu trả lời:


119

Bạn có thể tận dụng bảng giả "đã xóa" trong ví dụ này. Cái gì đó như:

begin transaction;

   declare @deletedIds table ( id int );

   delete from t1
   output deleted.id into @deletedIds
   from table1 as t1
    inner join table2 as t2
      on t2.id = t1.id
    inner join table3 as t3
      on t3.id = t2.id;

   delete from t2
   from table2 as t2
    inner join @deletedIds as d
      on d.id = t2.id;

   delete from t3
   from table3 as t3 ...

commit transaction;

Rõ ràng là bạn có thể thực hiện một 'đầu ra đã bị xóa.' trong lần xóa thứ hai, nếu bạn cần một cái gì đó để tham gia vào bảng thứ ba.

Lưu ý thêm, bạn cũng có thể chèn. * Trên câu lệnh chèn, và cả chèn. * Và xóa. * Trên câu lệnh cập nhật.

CHỈNH SỬA: Ngoài ra, bạn đã xem xét việc thêm trình kích hoạt trên table1 để xóa khỏi table2 + 3 chưa? Bạn sẽ ở bên trong một giao dịch ngầm và cũng sẽ có sẵn các bảng giả "đã chèn. " Và "đã xóa. ".


2
Có phải tốt hơn là chỉ XÓA TỪ table1 WHERE id = x và sau đó xóa khỏi bảng tiếp theo thay vì sử dụng kết nối bên trong và xem qua tất cả văn bản bổ sung này không ?? Về cơ bản, bỏ qua phép nối bên trong, tôi chỉ cần 2 truy vấn đơn giản .... Hay phương pháp này có hiệu quả hơn không?
Colandus

Tôi nghĩ nó phụ thuộc vào mức độ phức tạp của mệnh đề where của bạn. Đối với một phức tạp, điều này sẽ tốt hơn vì nó chỉ xảy ra một lần. Nhưng đối với một mệnh đề where đơn giản hơn có ảnh hưởng đến nhiều hàng, đề xuất của bạn có thể sẽ hiệu quả hơn vì nó không phải chứa nhiều id trong một biến bảng.
John Gibb

@JohnGibb, Câu trả lời này hoạt động như thế nào? Bạn có thể giải thích câu trả lời này để một nhà phát triển MySQL có thể hiểu nó không?
Pacerier

@Pacerier Tôi không quen lắm với MySQL. Ý tưởng là lần xóa đầu tiên chỉ xóa khỏi table1, nhưng nó lưu các ID đã bị xóa vào một biến. Hai câu lệnh tiếp theo cách sử dụng biến đó để xóa các hàng được liên kết khỏi bảng 2 và bảng 3.
John Gibb

@JohnGibb, Giờ thì đã rõ. Bạn nên bao gồm điều đó trong câu trả lời.
Pacerier

15
  1. Bạn luôn có thể thiết lập xóa theo tầng trên các mối quan hệ của các bảng.

  2. Bạn có thể gói gọn nhiều lần xóa trong một quy trình được lưu trữ.

  3. Bạn có thể sử dụng một giao dịch để đảm bảo một đơn vị công việc.


3
Chắc chắn có thể xóa trên một câu lệnh tham gia, tôi chỉ muốn xóa khỏi nhiều bảng cùng một lúc.
Byron Whitlock

Câu trả lời sai, tham gia có thể được sử dụng với delete
rboarman

ad 1.) Điều đó không đúng, không phải lúc nào cũng có thể thực hiện được. Có một số tình huống mà bạn không thể thiết lập xóa theo tầng, ví dụ: chu kỳ hoặc nhiều đường dẫn tầng. ( ví dụ: xem stackoverflow.com/a/3548225/108374 )
Tom Pažourek,

15

Bạn có thể sử dụng cú pháp JOIN trong mệnh đề FROM trong DELETE trong SQL Server nhưng bạn vẫn chỉ xóa khỏi bảng đầu tiên và đó là phần mở rộng Transact-SQL độc quyền thay thế cho truy vấn phụ.

Từ ví dụ ở đây :

 -- Transact-SQL extension
 DELETE 
   FROM Sales.SalesPersonQuotaHistory 
     FROM Sales.SalesPersonQuotaHistory AS spqh INNER JOIN 
          Sales.SalesPerson AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID
    WHERE sp.SalesYTD > 2500000.00;

3
Ví dụ D: XÓA KHỎI Sales.SalesPersonQuotaHistory TỪ Sales.SalesPersonQuotaHistory AS spqh INNER JOIN Sales.SalesPerson AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID WHERE sp.SalesYTD> 2500000.00;
Đánh dấu A

11

Ví dụ để xóa một số bản ghi khỏi bảng chính và các bản ghi tương ứng từ hai bảng chi tiết:

BEGIN TRAN

  -- create temporary table for deleted IDs
  CREATE TABLE #DeleteIds (
    Id INT NOT NULL PRIMARY KEY
  )

  -- save IDs of master table records (you want to delete) to temporary table    
  INSERT INTO #DeleteIds(Id)
  SELECT DISTINCT mt.MasterTableId
  FROM MasterTable mt 
  INNER JOIN ... 
  WHERE ...  

  -- delete from first detail table using join syntax
  DELETE d
  FROM DetailTable_1 D
  INNER JOIN #DeleteIds X
    ON D.MasterTableId = X.Id


  -- delete from second detail table using IN clause  
  DELETE FROM DetailTable_2
  WHERE MasterTableId IN (
    SELECT X.Id
    FROM #DeleteIds X
  )


  -- and finally delete from master table
  DELETE d
  FROM MasterTable D
  INNER JOIN #DeleteIds X
    ON D.MasterTableId = X.Id

  -- do not forget to drop the temp table
  DROP TABLE #DeleteIds

COMMIT

1
Bạn có thể sử dụng SELECT INTO #DeleteIdsthay vì CREATE TABLE 'DeleteIdstheo sau bởi INSERT INTO 'DeleteIds...?
Caltor

9

Chỉ tự hỏi .. điều đó có thực sự khả thi trong MySQL không? nó sẽ xóa t1 và t2? hoặc tôi chỉ hiểu sai câu hỏi.

Nhưng nếu bạn chỉ muốn xóa table1 với nhiều điều kiện tham gia, chỉ cần không đặt bí danh cho bảng bạn muốn xóa

điều này:

DELETE t1,t2 
FROM table1 AS t1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

nên được viết như thế này để hoạt động trong MSSQL:

DELETE table1
FROM table1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

để đối chiếu cách hai RDBMS phổ biến khác thực hiện thao tác xóa:

http://mssql-to-postgresql.blogspot.com/2007/12/deleting-duplicates-in-postgresql-ms.html


Cảm ơn về mẹo SQL Server ở đó, tôi đã phải chỉnh sửa SQL theo những dòng đó.
Pauk

7

Về cơ bản, bạn không phải thực hiện ba tuyên bố xóa trong một giao dịch, trước tiên là trẻ em và sau đó là cha mẹ. Thiết lập xóa theo tầng là một ý tưởng hay nếu đây không phải là việc xảy ra một lần và sự tồn tại của nó sẽ không xung đột với bất kỳ thiết lập trình kích hoạt hiện có nào.


Tôi đã hy vọng mình không phải làm điều đó, tôi cho rằng tôi sẽ phải chọn ID vào một bảng tạm thời vì mối quan hệ không phải là quan hệ cha mẹ. một khi các hàng từ một bảng đã biến mất thì không có cách nào để lấy các hàng khác.
Byron Whitlock

3

Trong máy chủ SQL không có cách nào để xóa nhiều bảng bằng phép nối. Vì vậy, bạn phải xóa từ con trước khi xóa biểu mẫu cha.


2

Đây là một cách thay thế để xóa hồ sơ mà không để lại trẻ mồ côi.

Khai báo bảng @user (int keyValue, someString varchar (10))
chèn vào @user
giá trị (1, '1 giá trị')

chèn vào @user
giá trị (2, '2 giá trị')

chèn vào @user
giá trị (3, '3 giá trị')

Khai báo bảng @password (int keyValue, chi tiết varchar (10))
chèn vào @password
giá trị (1, '1 Mật khẩu')
chèn vào @password
giá trị (2, '2 Mật khẩu')
chèn vào @password
giá trị (3, '3 Mật khẩu')

        - trước khi xóa
  chọn * từ @password a tham gia bên trong @user b
                trên a.keyvalue = b.keyvalue
  chọn * thành #deletedID từ @user trong đó keyvalue = 1 - điều này hoạt động giống như ví dụ đầu ra
  xóa @user trong đó keyvalue = 1
  xóa @password trong đó keyvalue (chọn keyvalue từ #deletedid)

  --Sau khi xóa--
  chọn * từ @password a tham gia bên trong @user b
                trên a.keyvalue = b.keyvalue


2

Tất cả đã được chỉ ra. Chỉ cần sử dụng DELETE ON CASCADEtrên phụ huynh tablehoặc xóa từ child-tableđến parent.


Ý bạn là gì khi xóa khỏi bảng con đối với phụ huynh? ý bạn là bằng cách sử dụng kỹ thuật nối giống như kỹ thuật được hiển thị trong câu hỏi hoặc các câu trả lời đã nói ở trên?
Imran Faruqi

1

Như Aaron đã chỉ ra, bạn có thể đặt hành vi xóa thành CASCADE và điều đó sẽ xóa các bản ghi con khi bản ghi mẹ bị xóa. Trừ khi bạn muốn một số loại phép thuật khác xảy ra (trong trường hợp đó điểm 2, 3 trong câu trả lời của Aaron sẽ hữu ích), tôi không hiểu tại sao bạn cần phải xóa bằng các phép nối bên trong.


0

Để dựa trên câu trả lời của John Gibb, để xóa một tập dữ liệu trong hai bảng có mối quan hệ FK:

--*** To delete from tblMain which JOINs to (has a FK of) tblReferredTo's PK  
--       i.e.  ON tblMain.Refer_FK = tblReferredTo.ID
--*** !!! If you're CERTAIN that no other rows anywhere also refer to the 
--      specific rows in tblReferredTo !!!
BEGIN TRAN;

    --*** Keep the ID's from tblReferredTo when we DELETE from tblMain
    DECLARE @tblDeletedRefs TABLE ( ID INT );
    --*** DELETE from the referring table first
    DELETE FROM tblMain 
    OUTPUT DELETED.Refer_FK INTO @tblDeletedRefs  -- doesn't matter that this isn't DISTINCT, the following DELETE still works.
    WHERE ..... -- be careful if filtering, what if other rows 
                --   in tblMain (or elsewhere) also point to the tblReferredTo rows?

    --*** Now we can remove the referred to rows, even though tblMain no longer refers to them.
    DELETE tblReferredTo
    FROM   tblReferredTo INNER JOIN @tblDeletedRefs Removed  
            ON tblReferredTo.ID = Removed.ID;

COMMIT TRAN;

-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION

nó sẽ không xóa từ hai hoặc nhiều table.Please hiểu câu hỏi
Kamran Shahid

-5

$ sql = "DELETE FROM basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl SỬ DỤNG basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl Ở ĐÂU b_id= e_id= p_id= a_id= d_id= '" $ id.. "' "; $ rs = mysqli_query ($ con, $ sql);


Vui lòng sửa định dạng của bạn và cung cấp mô tả ngắn gọn về lý do tại sao mã của bạn hoạt động.
Bryan Herbst
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.