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. 我想按typeof过滤purchase
  5. 由于father_id关系在另一个表中,这意味着必须进行连接。这又是可怕的,但我无法更改数据库以在表中包含一个father_id字段。person
  6. 如果一个人没有父亲,则relationships表中没有条目。这会让事情变得更加复杂。

现在我已经阅读了这些示例,并且我了解了其中的一些:如何在查询SQL Server 递归查询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 中的谓词正在造成严重破坏。很多时候,你需要用递归和寻找树来做两件重要的事情:

  1. 您需要知道您在“位置”上的级别(在我的示例中为 pos)
  2. 您需要从递归中的位置确定关系以使递归有意义。否则,您将再次显示相同的值,而没有真正使用它可以做的递归功能。

这是一个可能适用于您的示例:

  1. 会给你一个层次结构
  2. 将找到一棵树的最远梯级(最低位置)
  3. 将后代和孩子的订单添加在一起。

递归的最大好处不是一层或两层,而是当你进行 5 层或更多层时,它有能力告诉表达式你想要它的哪一部分。当我做递归时,我通常会做 2 个 cte,一个做递归,另一个做递归,然后给我看。否则,每个人都会带着各个层次的等级返回。除非你真的想要那样,否则你应该用一个窗口表达式来限制它。

我希望这会有所帮助,有时您必须暂时根据自己的情况定制递归 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 以获取帐号,然后是 Purchases。

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 回答