1

次のスキーマがあるとしましょう。

person (person_id, person_account, name)
relationships (person_id, father_id)
purchases(person_account, total, type)

免責事項:私はこのスキーマを設計していません。ひどいことを知っているので、お詫びします。また、これは例です。これははるかに複雑です。また、これはJDBCTemplateで使用するクエリであることに注意してください。これが、タグを含めた理由です。

count今、私は人の購入を取得したいと思います、そして彼または彼女の息子は購入し、彼らの息子は購入します。私は最初の人に特定の出発点が欲しいです。

これまでに見た例とは異なる点がいくつかあります。

  1. 特定の出発点(それがそうだとしましょうperson_account)。
  2. テーブルにはフィールドpurchasesがないため、作業が複雑になります。person_id
  3. countは他のものではなく、欲しいです。
  4. typeでフィルタリングしたいpurchase
  5. 関係は別のテーブルにあるためfather_id、結合を行う必要があることを意味します。繰り返しますが、それは恐ろしいことですが、テーブルにfather_idフィールドを含めるようにデータベースを変更することはできません。person
  6. relationships人に父親がいない場合、テーブルにエントリはありません。それはそれをさらに複雑にするでしょう。

今、私は例を読み、それらのいくつかを理解しました:クエリSQLServer再帰クエリhttp://msdn.microsoft.com/en-us/library
で再帰を使用して親のすべての子とその子を取得する方法/ms186243.aspx

しかし、私は開始点と終了点を理解するのに問題があります。私の出発点には父親がいる可能性があるので、それを無効にすることはできません。私のエンドポイントは、基本的purchasesにテーブルにエントリがない人から取得する必要があります。relationships

だから私が考えているのは:

declare @id int = 234 

;with CTEexample as (
     select p.person_account, p.person_id, p.type, r.father_id from purchases as s
         join person p on p.person_account = s.person_account
         join relationships r on r.person_id = p.person_id
         where r.person_id = @id
     union all
     select p.person_account, p.person_id, p.type, r_father_id from purchases as s
         join person p on p.person_account = s.person_account
         join relationships r on r.person_id = p.person_id
         join CTEexample c on p.person_id = r.father_id
 )
 select count(*) from CTEexample
      where type = 's'

ただし、まったく機能していません。

どんな助けでもいただければ幸いです。

4

2 に答える 2

2

非常に詳細な質問がありますが、再帰CTEの述語が大混乱を引き起こしていると思います。非常に多くの場合、再帰とツリーのハンティングで2つの重要なことを行う必要があります。

  1. あなたは自分がどのレベルにいるのかを知る必要があります'位置'(私の例では位置)
  2. 再帰を意味のあるものにするには、再帰内の位置から関係を判別する必要があります。そうでなければ、それができることの再帰的な力を実際に使用せずに、同じ値を再び表示しています。

これがあなたに当てはまるかもしれない例です:

  1. あなたに階層を与えるでしょう
  2. 木の最も遠いラング(最も低い位置)を見つけます
  3. 子孫と子の順序を一緒に追加します。

再帰の大きな利点は、1つまたは2つのレベルではなく、5つ以上のレベルに移動し、そのどの部分が必要かを表現に伝える力があることです。私は通常、再帰を実行するときに2つのcteを実行します。1つは再帰を実行し、もう1つは最大再帰を見つけてそれを表示します。そうでなければ、すべての人があらゆるレベルの階層で戻ってきます。本当に必要な場合を除いて、ウィンドウ式で制限する必要があります。

これがお役に立てば幸いです。しばらくの間、自分の状況に合わせて再帰CTEを調整する必要がある場合があります。

Declare @table table ( PersonId int identity, PersonName varchar(512), Account int, ParentId int, Orders int);

insert into @Table values ('Brett', 1, NULL, 1000),('John', 1, 1, 100),('James', 1, 1, 200),('Beth', 1, 2, 300),('John2', 2, 4, 400);

select 
    PersonID
,   PersonName
,   Account
,   ParentID
from @Table

; with recursion as 
    (
    select 
        t1.PersonID
    ,   t1.PersonName
    ,   t1.Account
    --, t1.ParentID
    ,   cast(isnull(t2.PersonName, '')
            + Case when t2.PersonName is not null then '\' + t1.PersonName else t1.PersonName end
            as varchar(255)) as fullheirarchy
    ,   1 as pos
    ,   cast(t1.orders + 
            isnull(t2.orders,0) -- if the parent has no orders than zero
            as int) as Orders
    from @Table t1
        left join @Table t2 on t1.ParentId = t2.PersonId
    union all
    select 
        t.PersonID
    ,   t.PersonName
    ,   t.Account
    --, t.ParentID
    ,   cast(r.fullheirarchy + '\' + t.PersonName as varchar(255))
    ,   pos + 1  -- increases
    ,   r.orders + t.orders
    from @Table t
        join recursion r on t.ParentId = r.PersonId
    )
, b as 
    (
    select *, max(pos) over(partition by PersonID) as maxrec  -- I find the maximum occurrence of position by person
    from recursion
    )
select *
from b
where pos = maxrec  -- finds the furthest down tree
-- and Account = 2  -- I could find just someone from a different department
于 2013-02-20T00:24:00.317 に答える
1

再帰を単純に保ち(他の人が将来管理しやすくする)、それを使用して関係を把握します。そこから、Personに参加してアカウント番号を取得し、次に購入を取得できます。

DECLARE @PersonID INT = 1

;WITH Family (PersonID, FatherID) AS (
  SELECT p.PersonID, null
  FROM Person p
  WHERE p.PersonID = @PersonID

  UNION ALL

  SELECT p.PersonID, r.FatherID
  FROM Person p
  INNER JOIN Relationships r
    ON r.PersonID = p.PersonID -- Me
  INNER JOIN Family f
    ON f.PersonID = r.FatherID -- Father
)
SELECT *
FROM Family f
JOIN Person p
  ON p.PersonID = f.PersonID
JOIN Purchases ps
  ON ps.PersonAccount = p.PersonAccount
WHERE ps.Type is null

SQLFiddle

于 2013-02-20T00:02:54.480 に答える