SPARQL 在将 MIN(?date1) 从子查询传递到外部查询时返回空结果,使用 BIND((YEAR(?minDate) - YEAR(?date2)) AS ?diffDate)

SPARQL returning empty result when passing MIN(?date1) from subquery into outer query, with BIND((YEAR(?minDate) - YEAR(?date2)) AS ?diffDate)

<此问题现已解决,请参阅 Valerio Cocchi 的评论>

我正在尝试从子查询传递一个变量,该变量采用属于 ?p 的一组日期 ?date1 中的最小日期,并将其传递给外部查询,然后外部查询采用属于 ?date2 的另一个日期? p(每个 ?p 最多可以有 1 个 ?date2)并从 ?date2 中减去 ?minDate 得到一个整数值,表示两者之间的年数。我为此得到一个空白值,即 ?diffDate returns no value.

我使用的是 Fuseki 4.3.2 版。以下是查询示例:

SELECT ?p ?minDate ?date2 ?diffDate 
  {        
  ?p a abc:P;
    abc:hasAnotherDate ?date2.      
    BIND((YEAR(?minDate) - YEAR(?date2)) AS ?diffDate)      
  {
  SELECT ?p (MIN(?date1) as ?minDate) 
  WHERE 
  { 
  ?p a abc:P;
    abc:hasDate ?date1. 

  } group by ?p 
    }                                 
  } 

以及我得到的那种结果的示例:

|-?p----|----------------?minDate------------|--- --------------?date2------------ |?diffDate|

|<123>|20012-11-22T00:00:00"^^xsd:dateTime|2008-08-18T00:00:00"^^xsd:dateTime| |

我希望 ?diffDate 会给我一个整数值。我是否遗漏了有关子查询在 SPARQL 中的工作原理的一些基本知识?

您似乎遇到了 SPARQL 规范中相当晦涩的部分,即 BIND 的工作原理。

通常 SPARQL 的计算不考虑原子的位置,即

SELECT *
WHERE {
?a :p1 ?b .
?b :p2 ?c .}

与以下查询相同:

SELECT *
WHERE {
?b :p2 ?c .
?a :p1 ?b .}

但是,BIND 位置依赖的,所以例如:

SELECT *
WHERE {
?a :p1 ?b .
BIND(:john AS ?a)}

不是有效查询,而:

SELECT *
WHERE {
BIND(:john AS ?a)
?a :p1 ?b .
}

完全有效。这同样适用于 BIND 内部使用的变量,这些变量必须在 BIND 出现之前声明。 有关更多信息,请参阅 here

回到您的问题,您的 BIND 在绑定之前使用 ?minDate 变量,这就是它无法为 ?diffDate 生成值的原因。

这个查询应该可以解决问题:

SELECT ?p ?minDate ?date2 ?diffDate 
  {        
  ?p a abc:P;
    abc:hasAnotherDate ?date2.      
       
  {
  SELECT ?p (MIN(?date1) as ?minDate) 
  WHERE 
  { 
  ?p a abc:P;
    abc:hasDate ?date1. 

  } group by ?p 
    }
BIND((YEAR(?minDate) - YEAR(?date2)) AS ?diffDate)   #Put the BIND after all the variables it uses are bound.
                             
  } 

或者,您可以评估 SELECT 中的差异,如下所示:

SELECT ?p ?minDate ?date2 (YEAR(?minDate) - YEAR(?date2) AS ?diffDate)
  {        
  ?p a abc:P;
    abc:hasAnotherDate ?date2.      

  {
  SELECT ?p (MIN(?date1) as ?minDate) 
  WHERE 
  { 
  ?p a abc:P;
    abc:hasDate ?date1. 

  } group by ?p 
    }

  }