首页 > 解决方案 > 计算孩子的数量和这些孩子的孩子

问题描述

假设我有一个祖父母的列表,每个人都有孩子,并且递归地每个人都有自己的孩子。就像家谱一样。

假设其中一位祖父母是 Aerys Targaryen。

伊里斯·坦格利安有 3 个孩子,雷加、韦赛里斯和丹妮莉丝。

雷加有 1 个孩子,约翰·斯诺。

韦赛里斯有 0 个孩子。

丹妮莉丝有 3 个孩子,卓耿、雷格尔和韦赛利昂。

我想做一个表格显示:

第一栏:祖父母的姓名

第 2 列:祖父母的孩子数(第 1 列)

第三栏:孩子的名字

第 4 列:父母拥有的孩子数(第 3 列)

第五栏:孩子的名字

我想要这样的结果:

+-----------------+--------+----------+--------+-----------+
|     GPName      | PCount |  PName   | CCount |   CName   |
+-----------------+--------+----------+--------+-----------+
| Aerys Targaryen |      3 | Rhaegar  |      1 | John Snow |
| Aerys Targaryen |      3 | Viserys  |      0 |           |
| Aerys Targaryen |      3 | Daenerys |      3 | Drogon    |
| Aerys Targaryen |      3 | Daenerys |      3 | Rhaegal   |
| Aerys Targaryen |      3 | Daenerys |      3 | Viserion  |
+-----------------+--------+----------+--------+-----------+

我已经设法进行了这些查询,但没有一个是我想要的。

    1.
SELECT ?GPName (count(?PName) as ?number)(group_concat(?PName;separator=",") as ?PName)
WHERE
{
     ?gp rdf:type gag:GrandParent .
     ?gp gag:name ?GPName .
     ?p gag:has_parent ?gp .
     ?p rdf:type gag:Parent .
     ?p gag:name ?PName
} group by ?GPName 

我只得到前 3 列,而不是我想要的形式。

    2.
SELECT ?GPName 
       (count(?PName) as ?PCount)
       ?PName
       (count(?CName) as ?CCount)
WHERE
{
      ?gp rdf:type gag:GrandParent .
      ?gp gag:name ?GPName .
      ?p rdf:type gag:Parent .
      ?p gag:name ?PName.
      ?p gag:has_parent ?gp .
      ?c rdf:type gag:Child .
      ?c gag:name ?CName.
      ?c gag:has_parent ?p.
} GROUP BY ?GPName ?PName

它只显示我想要的第 1、3、4 列。

标签: sparql

解决方案


正如所指出的,您需要两个单独的子查询来计算每个解决方案所需的聚合。添加一个OPTIONAL以防父级没有子级,并coalesce在投影中使用表达式将其设置为零(如果是这种情况)。

例如,类似于以下查询的内容(我已经根据http://geo.linkedopendata.gr/gag-endpoint的数据集对其进行了检查):

PREFIX gag: <http://geo.linkedopendata.gr/gag/ontology/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?gpName ?cnt ?PName (coalesce(?cc, 0) as ?cnt2) ?CName
WHERE 
{
    {
        select ?gp (count(?pe1) as ?cnt) {
            ?gp a gag:Περιφέρεια .
            ?pe1 a gag:Περιφερειακή_Ενότητα  .
            ?pe1 gag:ανήκει_σε ?gp .
        }group by ?gp 
    }
    ?gp gag:έχει_επίσημο_όνομα ?gpName .
    ?pe a gag:Περιφερειακή_Ενότητα  .
    ?pe gag:ανήκει_σε ?gp .
    ?pe gag:έχει_επίσημο_όνομα ?PName .
    optional {
        ?c rdf:type gag:Δήμος .
        ?c gag:έχει_επίσημο_όνομα ?CName.
        ?c gag:ανήκει_σε ?pe .
        {
            select ?pe (count(?c1) as ?cc) {
                ?c1 rdf:type gag:Δήμος .
                ?c1 gag:ανήκει_σε ?pe .
            } group by ?pe
        }
    }
}

ps 作为子查询的替代方案,您可以为子孙创建笛卡尔积并计算不同的绑定,例如:

PREFIX gag: <http://geo.linkedopendata.gr/gag/ontology/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?gpName ?PName ?CName (count(distinct ?p1) as ?cnt1) (count(distinct ?c1) as ?cnt2) 
    WHERE 
    {
        ?gp a gag:Περιφέρεια .
        ?gp gag:έχει_επίσημο_όνομα ?gpName .
        ?pe gag:ανήκει_σε ?gp .
        ?pe a gag:Περιφερειακή_Ενότητα  .
        ?pe gag:έχει_επίσημο_όνομα ?PName .
        ?p1 gag:ανήκει_σε ?gp . # cartesian product with ?pe and ?p1
        ?c gag:ανήκει_σε ?pe .
        ?c gag:έχει_επίσημο_όνομα ?CName .
        ?c1 gag:ανήκει_σε ?pe . # cartesian product with ?c and ?c1

    } group by ?gpName ?PName ?CName
    order by ?gpName ?PName 

推荐阅读