Sql-Server

以聲明方式從所有(動態數量)相關實體中選擇一個需要關係的實體

  • August 28, 2017

我正在嘗試建構一個 where 子句,該子句需要 X 個子節點與具有 N 對 N 關係的特定父節點建立關係。類似於“獲取這些產品一起銷售的所有收據”。一個範例場景更容易解釋:

DECLARE @Nodes TABLE(
 Id INT
);

DECLARE @Arc TABLE(
 Id INT IDENTITY(1,1),
 Source INT, -- FK @Nodes.Id
 Dest INT    -- FK @Nodes.Id
);

INSERT INTO @Nodes (Id) VALUES (1),(2),(3),(4);

INSERT INTO @Arc (Source, Dest) VALUES
  (1, 2)
 ,(1, 3)
 ,(1, 3)
 ,(2, 1)
 ,(2, 3)
 ,(2, 4);

在 SP 中,輸入被預處理成如下表:

DECLARE @InputConnectedNodes TABLE ( Id INT );
INSERT INTO @InputConnectedNodes (Id) VALUES (3),(4); -- not a fixed number of nodes

在本例中,我們希望所有節點都與節點 3 和 4 有弧(上例中只有節點 2)。目前我們有這個:

SELECT DISTINCT Source 
   FROM @Arc
   WHERE Dest IN (SELECT Id FROM @InputConnectedNodes);

然後我們有一些醜陋的程式碼循環輸入和(嵌套)輸出檢查所有關係。我想用聲明性的東西代替它。到目前為止,我想出的最好的是:

SELECT Source 
   FROM @Arc 
   WHERE Dest IN (SELECT Id FROM @InputConnectedNodes) 
   GROUP BY Source
   HAVING COUNT(Source) = (SELECT COUNT(*) FROM @InputConnectedNodes)

但在我的範例中,當節點具有多個(相同的)弧(如 (1->3))時,它將失敗。

我也可以通過動態生成 where 子句來解決這個問題,但我更喜歡完全聲明性的解決方案。

我建議放鬆你對完全聲明性解決方案的決心。可能沒有一種聲明式的方式來解決您的問題,並且在許多情況下,動態 SQL 在性能方面是一個更好的解決方案——即使它缺乏可讀性。

動態 SQL 使優化器有機會使用針對不同參數優化的不同計劃,而不必提出一個可以很好地解決所有排列的計劃。後者很難實現。

您的問題稱為關係除法。查看該標籤中的問題並:

大多數 Stack Overflow 解決方案都可以按原樣工作,或者對 SQL Server 稍作修改。請注意,具有多個連接或子查詢的更複雜的查詢EXISTS(對於任意情況需要動態生成的程式碼)比GROUP BY查詢更有效。

引用自:https://dba.stackexchange.com/questions/155153