解决多个多次排除的算法

时间:2016-07-06 09:09:14

标签: sql algorithm

我想查找并删除满足依赖关系的行,但前提是所有兄弟节点都满足该依赖关系。孩子也可以有多个父母,这使得这种毛茸茸但是这里有完整的解释:

我正在开发一个遗留系统,其数据结构非常糟糕,我无从事任何选择。以下是问题的简化,但我认为这是解释问题的最佳方式。

关于我正在做的事情:

在数据库中,我有货运记录A - G

我想删除所有已完成的货件。出货A - E已完成,但不是F或G.

系统中还有几个发票。

规则:

  1. 如果已完成的货件是包含的其他货件的发票的一部分,则无法将其删除

  2. 如果已完成的货件是包含其他无法删除的货件的发票的一部分,则无法将其删除

    问题:

    • 发票I1包含货件A,B和C.由于这些都已完成,我可以全部删除

    • 发票I2包含货件A,F和G.作为F& G 已完成,我无法删除

    • 但是,因为A不能被规则1删除,因为它是发票I1的一部分,B或C也不能

  3. ...然后我们需要检查任何其他发票B& C是......的一部分。

    ...等等到无限......

    ...对于我的生活,我想不出一个简单,快速的SQL语句或算法,而不是通过强力矿石递归 - 直到结束

    感激地收到任何其他建议!

2 个答案:

答案 0 :(得分:0)

我想我有个主意。假设您从描述中得到类似这三个表的内容(下面的SQL Server语法):

CREATE TABLE Invoice
(
   Id INT PRIMARY KEY
)

CREATE TABLE Shipment
(
   Id INT PRIMARY KEY,
   Completed BIT
)

CREATE TABLE Invoice_Shipment
(
   InvoiceId INT FOREIGN KEY REFERENCES Invoice(Id),
   ShipmentId INT FOREIGN KEY REFERENCES Shipment(Id)
)

然后你可以:

  1. 删除"不必要的"来自Invoice_Shipment

    的连接

    从Invoice_Shipment删除 WHERE InvoiceId不在    (从Invoice_Shipment中选择InvoiceId     在哪里ShipmentId IN      (SELECT Id FROM Shipment WHERE Completed = 0))

  2. 删除"未使用"来自Shipment

    的货件

    从货件中删除 WHERE完成= 1并且不在    (从Invoice_Shipment中选择InvoiceId)

  3. 重新编写此内容以满足您的需求,并且不要忘记包装交易。

答案 1 :(得分:0)

我尝试过这样的事情 - 这是导致我头疼的递归:

TRUNC Shipments_To_Delete

-- Grab all the 'Complete' Shipments
INSERT INTO Shipments_To_Delete
  ( SELECT * FROM Shipment WHERE Complete )

-- Make sure we iterate at least once
Shipments_To_Remove = True

WHILE Shipments_To_Remove

  -- Test if there's anything left to do..
  Shipments_To_Remove = 
    (
      -- Count if there are any Shipments marked for deletion..
      --   ..which can't be because they're part of an Invoice..
      --   ..which contains *other* Shipments that *can't* be deleted
      --
      SELECT COUNT(1) FROM Shipments_To_Delete WHERE Shipment_ID IN

        -- Find all the Shipments on Invoices that have Shipments that can't be deleted
        ( SELECT Shipment_ID FROM Invoice_Shipments WHERE Invoice_ID IN 

          -- Find all the Invoices that have Shipments which can't be deleted
          ( SELECT Invoice_ID FROM Invoice_Shipments WHERE Shipment_ID NOT IN
            ( SELECT Shipment_ID FROM Shipments_To_Delete )
          )

        )
     ) > 0

  IF Shipments_To_Remove THEN

    -- Reuse the query above to make it a DELETE
    --
    DELETE FROM Shipments_To_Delete WHERE Shipment_ID IN
      ( SELECT Shipment_ID FROM Invoice_Shipments WHERE Invoice_ID IN 
        ( SELECT Invoice_ID FROM Invoice_Shipments WHERE Shipment_ID NOT IN
          ( SELECT Shipment_ID FROM Shipments_To_Delete )
        )
      )

  ENDIF

-- If we've changed anything, loop around again and check whether there's anything left to do
DO