如何使用递归输出(父母 - >孩子 - >孙子女)

时间:2015-12-08 04:15:00

标签: sql-server sql-server-2012 subquery recursive-query

CREATE TABLE PERSON
(
    persID      INT IDENTITY(1,1)   PRIMARY KEY,
    persFName   VARCHAR(30) NOT NULL,
    persLName   VARCHAR(30) NOT NULL, 
    persDOB     DATE,
    motherID    INT FOREIGN KEY REFERENCES person(persID),
    fatherID    INT FOREIGN KEY REFERENCES person(persID),
    persDOD     DATE,
    persGender  CHAR(1),
)

CREATE TABLE COUPLE
(
    coupleID    INT     IDENTITY(1,1)   PRIMARY KEY,
    alphaSpouse INT     NOT NULL    FOREIGN KEY REFERENCES person(persID),
    omegaSpouse INT     NOT NULL    FOREIGN KEY REFERENCES person(persID),
    coupleStart DATE    NOT NULL,
    coupleEnd   DATE,
)

INSERT INTO person (persFName, persLName, persDOB, motherID, fatherID, persDOD, persGender) VALUES
('Jim', 'Smith', '1920-05-15', NULL, NULL, '2001-04-21','M'),
('Agnes', 'Smith', '1922-09-21', NULL, NULL, '2003-06-01','F'),
('Linda', 'Howard', '1949-03-20', 2, 1, NULL,'F'),
('Helen', 'Bradley', '1942-11-28', 2, 1, NULL,'F'),
('Jim', 'Smith', '1953-02-10', 2, 1, NULL,'M'),
('Stephen', 'Smith', '1957-01-13', 2, 1, '2005-05-25','M'),
('Daniel', 'Smith', '1961-11-28', 2, 1, NULL,'M'),
('Michelle', 'Smith', '1963-07-02', NULL, NULL, NULL,'F'),
('Anne', 'Smith', '1958-04-22', NULL, NULL, NULL,'F'),
('Josh', 'Smith', '1990-01-28', 8, 7, NULL,'M'),
('Stephanie', 'Smith', '1992-05-18', 8, 7, NULL,'F'),
('Rachel', 'Smith', '1996-11-05', 8, 7, NULL,'F'),
('Reg', 'Howard', '1949-07-07', NULL, NULL, NULL,'M'),
('Richard', 'Howard', '1972-12-26', 3, 13, NULL,'M'),
('Phillip', 'Howard', '1975-06-01', 3, 13, NULL,'M'),
('Robert', 'Bradley', '1939-03-07', NULL, NULL, NULL,'M'),
('Matthew', 'Bradley', '1964-10-26', 4, 16, '2001-04-27','M'),
('Yvonne', 'Bradley', '1966-11-28', 4, 16, NULL,'F'),
('James', 'Bradley', '1971-01-26', 4, 16, NULL,'M'),
('Anna', 'Reuper', '1918-01-27', NULL, NULL, NULL,'F'),
('Ludwig', 'Reuper', '1923-07-01', NULL, NULL, '2001-07-01','M'),
('Heinz', 'Reuper', '1965-01-28', 20, 21, NULL,'M'),
('Veronica', 'Reuper', '1959-04-01', 20, 21, NULL,'F'),
('Marco', 'Johnson', '1958-09-04', NULL, NULL, NULL,'M'),
('Francesca', 'Reuper', '1990-11-01', 23, 24, NULL,'F'),
('Lou', 'Jung', '1940-02-03', NULL, NULL, NULL,'M'),
('Tammi', 'Sinclair', '1971-02-03', NULL, NULL, NULL,'F'),
('Lori', 'Navarro', '1973-12-15', NULL, NULL, NULL,'F'),
('Kattie', 'Paine', '1980-10-31', NULL, NULL, NULL,'F');


INSERT INTO couple (alphaSpouse,omegaSpouse, coupleStart, coupleEnd) VALUES
(1,2,'1940-05-22', NULL),
(3,13,'1969-07-30', '1973-10-01'),
(3,26,'1980-01-10', '1982-12-01'),
(4,16,'1963-04-05', NULL),
(6,9,'1979-06-21', NULL),
(7,8,'1987-09-14', NULL),
(20,21,'1936-10-26', NULL),
(23,24,'1988-05-01', '1997-07-01'),
(19,27,'1992-10-31', '1993-01-31'),
(19,28,'1995-08-18', '1997-04-27'),
(19,29,'2015-09-19', NULL);

我试图列出所有有孙子孙女的人以及他们每个人有多少孙子孙女。我喜欢这样的输出; an output like this

我尝试在下面进行此操作,但是我试图在WHERE子查询之外尝试COUNT孙子陷阱...我是否在正确的轨道上?

SELECT grandp.persFName + ' ' + grandp.persLName, COUNT(grandkids.persID) 
FROM person grandp
JOIN person child ON grandp.persID = child.motherID OR  grandp.persID = child.fatherID
WHERE child.persID IN (SELECT grandkids.motherID
                        FROM person grandkids
                        union
                        SELECT grandkids.fatherID
                        FROM person grandkids)
GROUP BY grandp.persFName + ' ' + grandp.persLName

2 个答案:

答案 0 :(得分:2)

当您拥有像您这样的分层数据时,最好使用公用表表达式。这将允许您将分层数据构建为您稍后可以使用的表单 - 在您的示例中,计算孙子。您可以按照与根目录的级别或距离来构建数据。

with temp (persid, ancestorid, level) as (
  select persid, persid as ancestorid, 0 as level
  from person
  where motherid is null and fatherid is null

  union all

  select person.persid, temp.ancestorid, temp.level + 1 as level
  from person
  inner join temp on temp.persid = person.motherid or temp.persid = person.fatherid
)

select temp.ancestorid as persid, 
  person.persFName + ' ' + person.persLName as name,
  count(*)
from temp
inner join person
on temp.ancestorid = person.persid
where level = 2
group by temp.ancestorid, person.persFName, person.persLName

查询构建每个人的CTE,它的祖先和级别(0 =祖父母,2 =孙子)。然后,您可以轻松地计算每个祖先的孙子。

SQL小提琴:http://sqlfiddle.com/#!3/99c97/2

(注意:因为这里不需要,所以我离开了几张桌子。)

答案 1 :(得分:1)

试试这个我只是递归地使用公共表表达式来获得结果

x, y,xmin,ymin