問題の説明が長くなって申し訳ありませんが、これ以上分解することはできませんでした。読み進める前に、私の最終目標は T-SQL (再帰的な CTE でしょうか?) であることを覚えておいてください。ただし、正しい方向への押し込みは大歓迎です (私は何百万ものことを試し、何時間も頭を悩ませてきました)。
次の問題を考えてみましょう: ParentCategoryID->CategoryID を介して自己参照するカテゴリのテーブルがあります。
----------------------- | | カテゴリー | ----------------------- | | *カテゴリーID | | | 名前 | | | 親カテゴリ ID | -----------------------
このタイプのテーブルを使用すると、ツリー構造を構築できます。たとえば、次のようになります。
----------------- | | 親カテゴリ| ----------------- / | \ child(1) 子 子 / \ 子(2) 子(3)
ここで、「子」は「子カテゴリ」を意味します (数字は無視してください。後で説明します)。もちろん、どのレベルでも好きなだけ子供を持つことができます。
毎日、私が書いたプログラムは、次のように「Category」に接続されているテーブル「ValueRegistration」に値を保存します。
------------------------ ---------------------- ---- ------------------ | | 値登録 | | | アイテム | | | カテゴリー | ------------------------ ---------------------- ---- ------------------ | | *RegID | | | *アイテムID | | | *カテゴリーID | | | 日付 |>-------| カテゴリーID |>---------| 名前 | | | アイテム ID | | | アイテム タイプ ID | | | 親カテゴリ ID | | | 値 | ---------------------- ---------------------- ------------------------ や | | | | ---------------------- | | アイテムタイプ | ---------------------- | | *アイテムタイプID | | | アイテムタイプ | ----------------------
ご覧のとおり、ValueRegistration は特定のカテゴリに属する特定のアイテムに関係しています。カテゴリには、親 (および祖父母と曽祖父母など) がある場合とない場合があります。たとえば、上に示したツリーの左下 (番号 2) までずっと子である可能性があります。また、Item は特定の ItemType のものです。
私の目標:
毎日 ValueRegistration テーブルに値を登録します (つまり、Date と ItemID の組み合わせも主キーです)。次のフォームで結果セットを取得できるようにしたい:
[ValueRegistration.Date, ItemType.ItemTypeID, Category.CategoryID, Value]
これは十分に単純に思えます (明らかに単なる結合の集まりです)。ただし、ValueRegistration テーブルに実際には存在しない行の結果、つまり、特定の日付と itemID の兄弟ノードの値が合計され、 ValueRegistration.DateとItemType の場所に新しい行が生成される結果も必要です。 ItemTypeIDは子ノードと同じですが、 CategoryIDは子ノードの親のものです。結果セットのこのタイプの行には項目が存在しないことに注意してください。
たとえば、一連の日付と一連の ItemID で子 2 と 3 の ValueRegistrations があるシナリオを考えてみましょう。明らかに、各登録は特定の ItemType と Category に属します。読者には明らかなはずです。
ValueRegistration.Date, ItemType.ItemTypeID, Category.CategoryID
は、特定の ValueRegistration を識別するのに十分なキーです (つまり、一時アイテム行を作成しなくても問題を解決できます)。そのため、すべてのテーブルを内部結合して、たとえば次の結果を得ることができます。
ValueReg.Date, ItemType.ItemTypeID, Category.CategoryID, ValueReg.Value
08-mar-2013, 1, 5, 200
08-mar-2013, 1, 6, 250
次のような 4 つのカテゴリ行があるとします。
1, category1, NULL
2, category2, 1
5, category5, 2
6, category6, 2
つまり、カテゴリ 1 はカテゴリ 2 の親であり、カテゴリ 2 はカテゴリ 5 と 6 の親です。カテゴリ 1 には親がありません。結果セットに次の行を追加したいと思います。
08-mar-2013, 1, 2, (200+250)
08-mar-2013, 1, 1, (200+250+sum(values in all other childnodes of node 1)
覚えて:
- 解決策は再帰的である必要があるため、ツリーの上方に向かって (NULL に到達するまで) 実行されます。
- 計算されるツリー ノードにはアイテム行が存在しないため、CategoryID と ItemTypeID を使用する必要があります。
- はい、単純に「仮想」アイテム行を作成し、最初にデータベースに INSERT するときに ValueRegistrations を追加できることはわかっていますが、その解決策はエラーが発生しやすく、特に他のプログラマーが私のデータベースに対してコードを作成しているが、結果が必要であることを忘れているか認識していない場合親ノードに渡されます。リクエストに応じてこれを計算するソリューションは、はるかに安全で、率直に言って、はるかにエレガントです。
thisの行に沿って何かを設定しようとしましたが、Date と ItemTypeID でグループ化する必要があり、CTE では許可されていないようです。私のプログラマーは再帰関数を作成したいだけですが、SQL でそれを行うのに本当に苦労しています。
どこから始めるべきか、何を試すべきか、または (指を交差させて) 解決策を知っている人はいますか?
ありがとう!
アレクサンダー
編集:SQLフィドル
CREATE TABLE ItemType(
ItemTypeID INT PRIMARY KEY,
ItemType VARCHAR(50)
);
CREATE TABLE Category(
CategoryID INT PRIMARY KEY,
Name VARCHAR(50),
ParentCategoryID INT,
FOREIGN KEY(ParentCategoryID) REFERENCES Category(CategoryID)
);
CREATE TABLE Item(
ItemID INT PRIMARY KEY,
CategoryID INT NOT NULL,
ItemTypeID INT NOT NULL,
FOREIGN KEY(CategoryID) REFERENCES Category(CategoryID),
FOREIGN KEY(ItemTypeID) REFERENCES ItemType(ItemTypeID)
);
CREATE TABLE ValueRegistration(
RegID INT PRIMARY KEY,
Date DATE NOT NULL,
Value INT NOT NULL,
ItemID INT NOT NULL,
FOREIGN KEY(ItemID) REFERENCES Item(ItemID)
);
INSERT INTO ItemType VALUES(1, 'ItemType1');
INSERT INTO ItemType VALUES(2, 'ItemType2');
INSERT INTO Category VALUES(1, 'Category1', NULL); -- Top parent (1)
INSERT INTO Category VALUES(2, 'Category2', 1); -- A child of 1
INSERT INTO Category VALUES(3, 'Category3', 1); -- A child of 1
INSERT INTO Category VALUES(4, 'Category4', 2); -- A child of 2
INSERT INTO Category VALUES(5, 'Category5', 2); -- A child of 2
INSERT INTO Category VALUES(6, 'Category6', NULL); -- Another top parent
INSERT INTO Item VALUES(1, 4, 1); -- Category 4, ItemType 1
INSERT INTO Item VALUES(2, 5, 1); -- Category 5, ItemType 1
INSERT INTO Item VALUES(3, 3, 1); -- Category 3, ItemType 1
INSERT INTO Item VALUES(4, 1, 2); -- Category 1, ItemType 2
INSERT INTO ValueRegistration VALUES(1, '2013-03-08', 100, 1);
INSERT INTO ValueRegistration VALUES(2, '2013-03-08', 200, 2);
INSERT INTO ValueRegistration VALUES(3, '2013-03-08', 300, 3);
INSERT INTO ValueRegistration VALUES(4, '2013-03-08', 400, 4);
INSERT INTO ValueRegistration VALUES(5, '2013-03-09', 120, 1);
INSERT INTO ValueRegistration VALUES(6, '2013-03-09', 220, 2);
INSERT INTO ValueRegistration VALUES(7, '2013-03-09', 320, 3);
INSERT INTO ValueRegistration VALUES(8, '2013-03-09', 420, 4);
-- -------------------- RESULTSET I WANT ----------------------
-- vr.Date | ItemType | CategoryTypeID | Value
-- ------------------------------------------------------------
-- 2013-03-08 | 'ItemType1' | 'Category4' | 100 Directly available
-- 2013-03-08 | 'ItemType1' | 'Category5' | 200 Directly available
-- 2013-03-08 | 'ItemType1' | 'Category3' | 300 Directly available
-- 2013-03-08 | 'ItemType1' | 'Category2' | 100+200 Calculated tree node
-- 2013-03-08 | 'ItemType1' | 'Category1' | 100+200+300 Calculated tree node
-- 2013-03-08 | 'ItemType2' | 'Category1' | 400 Directly available
-- 2013-03-09 | 'ItemType1' | 'Category4' | 120 Directly available
-- 2013-03-09 | 'ItemType1' | 'Category5' | 220 Directly available
-- 2013-03-09 | 'ItemType1' | 'Category3' | 320 Directly available
-- 2013-03-09 | 'ItemType1' | 'Category2' | 120+220 Calculated tree node
-- 2013-03-09 | 'ItemType1' | 'Category1' | 120+220+320 Calculated tree node
-- 2013-03-09 | 'ItemType2' | 'Category1' | 420 Directly available