2013-02-19 91 views
1

可以说我有以下模式:CTE递归查询和内部连接

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. 我想过滤typepurchase
  5. 由于father_id关系在另一个表中,这意味着必须进行连接。再次,它是可怕的,但我不能改变数据库,以包括在personfather_id字段。
  6. 如果一个人没有父亲,relationships表中没有条目。这会使它更加复杂。

现在我读过的例子中,我知道他们夫妇:
How to get all children of a parent and then their children using recursion in query
SQL Server recursive query
http://msdn.microsoft.com/en-us/library/ms186243.aspx

不过,我有问题理解出发点和落脚点。我的出发点可能有一个父亲,所以不能为空。基本上,我的终点应该从relationships表中没有条目的人那里得到purchases

那么我现在的想法是:

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' 

但是,它是不工作的。

任何帮助,将不胜感激。

+0

不能肯定,但尝试扭转你的加盟CTEexample。因此,在p.person_id = r.father_id上加入CTEexample c变为在r.person_id = p.father_id上加入CTEexample c – 2013-02-19 23:15:20

回答

2

你有一个非常详细的问题,但我的猜测是你在递归CTE谓词造成破坏。很多时候,你需要做的2件重要的事情递归和追捕一棵树:

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