【问题标题】:How to output using recursive (parents -> children -> grandchildren)如何使用递归输出(父母 -> 孩子 -> 孙子女)
【发布时间】:2023-12-28 23:22:02
【问题描述】:
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);

我试图列出所有有孙子的人以及他们每个人有多少个孙子。我想要这样的输出;

我尝试在下面执行此操作,但在尝试在 WHERE 子查询之外对孙子进行计数时遇到了困难。我是否走在正确的轨道上?

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

【问题讨论】:

  • 你能发布一些示例数据吗?
  • 对不起,我刚刚添加了它

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


【解决方案1】:

当您拥有像您这样的分层数据时,最好使用公用表表达式来处理。这将允许您将分层数据构建成您以后可以使用的表格 - 在您的示例中,计算孙辈。您可以利用按级别或距根的距离构建数据。

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

(注意:我把情侣表放在了外面,因为这里不需要)。

【讨论】:

    【解决方案2】:

    试试这个我只是用公用表表达式递归得到结果

    ;WITH Allpersons AS
    (
     SELECT persID AS Id
    ,persFName+' '+persLName AS Name 
    ,fatherID
    ,motherID
    FROM PERSON
    
    )
    SELECT
     GrandFatherCTE.Name 
     ,COUNT(GrandFatherCTE.Id ) AS CountOfChild
    FROM Allpersons AllPersonsCTE
    INNER JOIN
    Allpersons ParentsCte
    ON
    AllPersonsCTE.fatherID = ParentsCte.Id
    OR
    AllPersonsCTE.motherID = ParentsCte.Id
    INNER JOIN
    Allpersons GrandFatherCTE
    ON
    ParentsCte.fatherID = GrandFatherCTE.Id
    OR
    ParentsCte.motherID = GrandFatherCTE.Id
    INNER JOIN
    COUPLE 
    ON
    GrandFatherCTE.Id = COUPLE.alphaSpouse
    OR
    GrandFatherCTE.Id = COUPLE.omegaSpouse
    
    GROUP BY
    GrandFatherCTE.Name 
    ,COUPLE.coupleID
    ORDER BY 
     CountOfChild  ASC
    ,COUPLE.coupleID ASC
    

    【讨论】: