web-dev-qa-db-ja.com

すべての子の外部キーの総数を取得します

私はこれをSQL EXPRESS 2016で試しました。これが私の問題です:

構造DB(親>子>孫> ...)のようなツリーがあり、下位レベルには別のテーブルとの関係があります。

表1

CREATE TABLE [dbo].[Equipament]
    [ID] [nvarchar](50) NOT NULL,
    [AL] [nvarchar](50) NULL,
    [Lvl] [nvarchar](50) NULL,
    [IDParent] [nvarchar](50) NULL,

表2

CREATE TABLE [dbo].[Conns]
    [Conns] [nvarchar](50) NOT NULL,
    [IDEquip] [nvarchar](50) NOT NULL,
FOREIGN KEY([IDEquip])
REFERENCES [dbo].[Equipament] ([ID])

私が取得しようとしているのは、再帰的に取得するCTEです。

  1. 各子の接続の合計数(たとえば、そのレベル3など)
  2. 各lvl2機器について、そのlvl3の子接続の合計
  3. 各lvl1機器について、その子の合計

主にConnsテーブルにレベル1および2の機器がなく、LEFT JOIN再帰CTE。

私が得た最も近いものはこれです:

;WITH QUERY AS
(
    SELECT E.ID,E.IDParent,L.conns
    FROM Equipament E
    LEFT JOIN conns L ON E.ID=L.IDEquip
    WHERE E.IDParent IS NULL

    UNION ALL

    SELECT E.ID,E.IDParent,L.conns
    FROM Equipament E
    JOIN conns L ON E.ID = L.IDEquip
    JOIN QUERY P on P.ID = E.IDParent
)
SELECT
    E.ID,
    SUM(S.Total) AS LTotal
FROM Equipament E
LEFT JOIN ( SELECT Q.ID, COUNT(Q.conns) AS Total
                FROM QUERY Q
                GROUP BY Q.ID
            ) as S 
ON E.ID = S.ID
GROUP BY E.ID
ORDER BY E.ID
option (maxrecursion 0)

[〜#〜] edit [〜#〜]要求されたフィドル: dbfiddle link

サンプルデータでは、予想される出力は次のようになります。

+---+-------------------------------------+
|ID |   Total Conections Dependancy       |
+---+-------------------------------------+
|AA |   1 (CE + BA)                       |
|AB |   4 ( BB + BC)                      |
|BA |   0                                 |
|BB |   0                                 |
|BC |   4 ( CD + CB)                      |
|CA |   0                                 |
|CB |   3                                 |
|CD |   1                                 |
|CE |   1                                 |
+---+-------------------------------------+

Cレベルの機器のみに接続があり、レベルAからレベルCに直接ジャンプする可能性があります。

これは可能ですか?誰かが私を正しい方向に向けることができますか?

ありがとうございました、

3
CromixPT

はい、再帰的なCTEまたは再帰的な関数のいずれかを使用してそれを行うことが可能です(最初はCTEを使用してそれを解決する方法を理解できなかったため、関数を使用してソリューションをコーディングしました。 、私もそれを答えに留めています)。方法は次のとおりです。

再帰CTE

;WITH QUERY AS
(
    SELECT IDEquip, 1 AS Quantity
    FROM Conns

    UNION ALL

    SELECT E.IDParent AS IDEquip, 1 AS Quantity
    FROM Equipament E
        INNER JOIN QUERY Q ON E.ID = Q.IDEquip
)
SELECT E.ID, ISNULL(SUM(Q.Quantity), 0) AS Total 
FROM Equipament E
    LEFT JOIN QUERY Q ON E.ID = Q.IDEquip
GROUP BY E.ID;

再帰的なCTEを使用してそれを解決するコツは、値を後ろから前にクエリすることでした。

再帰関数

CREATE FUNCTION dbo.GetAllDescendants(@id nvarchar(100))
RETURNS INT
AS 
BEGIN
    RETURN(
        SELECT SUM(Total + ISNULL(dbo.GetAllDescendants(ID), 0)) 
        FROM (
            SELECT ID, IDParent, COUNT(IDEquip) AS Total
            FROM Equipament 
                LEFT JOIN Conns ON ID = IDEquip
            GROUP BY ID, IDParent
        ) AS TotalConns
        WHERE IDParent = @id
    )
END;

このクエリを使用すると、子孫の合計を取得できますが、ID自体の接続は取得できません。

SELECT ID, ISNULL(dbo.GetAllDescendants(ID), 0) AS [Total Conections Dependancy]
FROM Equipament
ORDER BY ID;

説明したとおりの結果を得るには、次のように実行する必要があります。

SELECT ID, IIF(COUNT(IDEquip) > 0, COUNT(IDEquip), ISNULL(dbo.GetAllDescendants(ID), 0)) AS [Total Conections Dependancy]
FROM Equipament 
    LEFT JOIN Conns ON ID = IDEquip
GROUP BY ID, IDParent
ORDER BY ID;
2
Ronaldo