문제

I have a table like this:

table item
(
   id    int,
   quantity float,
   father int, -- refer to item itself in case of subitem
)

I need to sum al quantity plus sons quantity like this way:

select i.id, max(i.quantity)+sum(ft.quantity) as quantity
from item i
left join item ft on ft.id=i.id
group by i.id

My trouble is because relationship between father-son is recursive so I would like to sum also his grandfather quantity and so on... and i don't know the maximum deepness, than I can not join many times.

What can i do? Thank you.

도움이 되었습니까?

해결책

You have to use a recursive CTE. Somthing like this:

;WITH FathersSonsTree
AS
(
  SELECT Id, quantity, 0 AS Level
  FROM Items WHERE fatherid IS NULL
  UNION ALL
  SELECT c.id, c.quantity, p.level+1
  FROM FathersSonsTree p
  INNER JOIN items c ON c.fatherid = p.id
 ), ItemsWithMaxQuantities
AS
(
  SELECT *,
  ROW_NUMBER() OVER(PARTITION BY level 
                    ORDER BY quantity DESC) rownum
  FROM FathersSonsTree
  )
SELECT 
  ID,  
  (SELECT MAX(Quantity) 
   FROM FathersSonsTree t3 
   WHERE t3.level = t1.level
  ) + 
  ISNULL((SELECT SUM(t2.Quantity) 
   FROM FathersSonsTree t2
   WHERE t1.level - t2.level = 1), 0)
FROM FathersSonsTree t1
ORDER BY ID;

SQL Fiddle Demo

This will give you something like:

| ID | QUANTITY |
-----------------
|  1 |       10 |
|  2 |       20 |
|  3 |       20 |
|  4 |       20 |
|  5 |       32 |
|  6 |       32 |
|  7 |       32 |
|  8 |       32 |

다른 팁

You might try building a recursive CTE (common table expression) as described in this article on SQLAuthority:

http://blog.sqlauthority.com/2012/04/24/sql-server-introduction-to-hierarchical-query-using-a-recursive-cte-a-primer/

The author, Pinal Dave, discusses using a recursive CTE on an employees table that has a self referencing foreign key for ManagerID to return a list of employees with a count of how many levels are between them and the top of the hierarchy where the employee has no manager (ManagerID = NULL). That's not exactly what you're wanting but it might get you started.

I did a little experimentation and ended up with something very similar to Mahmoud Gamal's solution but with a slight difference to include the not just the parent, grandparents, great-grandparents, etc. quantity but also the child quantity.

Here's the test table I used:

CREATE TABLE Items(ID int IDENTITY
                      CONSTRAINT PK_Items PRIMARY KEY,
               Quantity int NOT NULL,
               ParentID int NULL
                            CONSTRAINT FK_Item_Parents REFERENCES Items(ID));

And the data:

ID                  Quantity            ParentID            
------------------------------------------------------------
1                   10                  {NULL}
2                   10                  1
3                   10                  2
4                   10                  3
5                   10                  2

Here's my recursive query:

WITH cteRecursiveItems
AS (SELECT Id,
           quantity,
           0
          AS Level
    FROM Items
    WHERE ParentID IS NULL
    UNION ALL
    SELECT i.id,
           i.quantity,
           cri.level + 1
    FROM
         cteRecursiveItems cri
         INNER JOIN items i ON i.ParentID = cri.id)
SELECT ID,
       Quantity + (
                   SELECT MAX(Quantity)
                   FROM cteRecursiveItems cri3
                   WHERE cri3.level = cri1.level) + (
                                                 SELECT SUM(cri2.Quantity)
                                                 FROM cteRecursiveItems cri2
                                                 WHERE cri1.level - cri2.level = 1) as Total
FROM cteRecursiveItems cri1
ORDER BY ID;

And here's the results I get from running it against the test table:

ID                  Total             
----------------------------------------
1                   {NULL}
2                   30
3                   30
4                   40
5                   30

It still needs a little tweaking because the first and 2nd row are off by 10. Row 1 should have a total of 10 and row 2 should have a total of 20. I'm making a note to try and fix that when I get home. Can't spend too much of my employer's time on this right now. :) The other rows have the value I was expecting.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top