跳转到内容

XQuery/SPARQL 教程

来自维基教科书,开放世界中的开放书籍
(重定向自 XQuery/RDF 和 Emp-Dept 案例研究)

SPARQL 接口

[编辑 | 编辑源代码]

emp-dept RDF 可以通过 XQuery 前端 使用 SPARQL 查询 存储,由 Talis 提供。该脚本支持 SPARQL 查询和浏览 RDF 图。


该接口扩展了查询,例如

  select ?name ?job where {
   ?emp rdf:type  f:emp.
   ?emp foaf:surname ?name.
   ?emp f:Job ?job.
  }

您可以在 此处 [失效链接] 运行

 prefix foaf: <http://xmlns.com/foaf/0.1/>
 prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
 prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
 prefix f: <http://www.cems.uwe.ac.uk/empdept/concept/>
 prefix xs: <http://www.w3.org/2001/XMLSchema#>
 select ?name ?job 
  where {
   ?emp rdf:type  f:emp.
   ?emp foaf:surname ?name.
   ?emp f:Job ?job.
 }

并将其发送到 Talis 服务,该服务以可运行的形式提供,您可以在 此处 运行。生成的 SPARQLQuery Results XML 会被转换为 HTML。

示例查询

[编辑 | 编辑源代码]

列出所有员工

[编辑 | 编辑源代码]
 select ?emp where {
  ?emp  rdf:type  f:emp.
 }

运行 [失效链接]

按字母顺序列出所有员工姓名

[编辑 | 编辑源代码]
 select ?name where {
  ?emp  rdf:type  f:emp.
  ?emp  foaf:surname ?name. 
 }
 ORDER BY ?name

运行 [失效链接]

列出员工的姓名、薪资、部门编号和职位

[编辑 | 编辑源代码]
 select ?name ?sal ?dno ?job where {
  ?emp  rdf:type  f:emp;
        foaf:surname ?name;
        f:Sal ?sal;
        f:Dept ?dept;
        f:Job ?job.  
  ?dept f:DeptNo ?dno. 
 }

请注意,; 代替 . 用于重复主体。

请在 此处 [失效链接] 尝试此查询和后续查询。

列出前 5 名员工

[编辑 | 编辑源代码]
select ?ename where {
  ?emp  rdf:type  f:emp;
        foaf:surname ?ename.
} 
ORDER BY ?ename
LIMIT 5

列出薪资最高的 5 名员工

[编辑 | 编辑源代码]
select ?ename ?sal where {
 ?emp  rdf:type  f:emp;
       foaf:surname ?ename;
       f:Sal ?sal.
} 
ORDER BY DESC(?sal)
LIMIT 5

列出部门

[编辑 | 编辑源代码]
select ?dept where {
  ?dept  rdf:type  f:dept.  
}

列出所有部门和所有员工

[编辑 | 编辑源代码]
select ?dept ?emp where {
  {?dept  rdf:type  f:dept }
  UNION
  {?emp rdf:type f:emp}
}

列出薪资超过 1000 的员工

[编辑 | 编辑源代码]

如果 RDF 文字类型,例如 xs:integer,就像此生成的 RDF 一样,则以下查询将选择薪资大于 1000 的员工


select ?emp ?sal where {
  ?emp  rdf:type  f:emp;
        f:Sal ?sal.
  FILTER (?sal > 1000)
}

如果 RDF 文字没有类型,则必须强制转换变量

 select ?emp ?sal where {
  ?emp  rdf:type  f:emp;
        f:Sal ?sal.
  FILTER (xs:integer(?sal) > 1000)
}

列出员工及其所在地

[编辑 | 编辑源代码]
select ?emp ?loc where {
  ?emp  rdf:type  f:emp.
  ?emp f:Dept ?dept.
  ?dept f:Location ?loc.
}

列出员工姓名及其经理

[编辑 | 编辑源代码]
select ?ename ?mname where {
  ?emp  rdf:type  f:emp;
        f:Mgr ?mgr;
        foaf:surname ?ename.
  ?mgr foaf:surname ?mname.
} 

包括没有经理的员工

[编辑 | 编辑源代码]
select ?ename ?mname where {
  ?emp  rdf:type  f:emp;
        foaf:surname ?ename.
  OPTIONAL {?emp f:Mgr ?mgr.
            ?mgr foaf:surname ?mname.
           }
}

列出没有经理的员工

[编辑 | 编辑源代码]
select ?ename where {
  ?emp  rdf:type  f:emp;
        foaf:surname ?ename.
  OPTIONAL {?emp f:Mgr ?mgr}
  FILTER (!bound(?mgr))
}

列出员工的不同所在地

[编辑 | 编辑源代码]
select distinct ?loc  where {
  ?emp  rdf:type  f:emp.
  ?emp  f:Dept ?dept.
  ?dept f:Location ?loc.
} 


列出所有分析师的详细信息

[编辑 | 编辑源代码]
select * where {
  ?emp  rdf:type  f:emp.
  ?emp  f:Dept ?dept.
  ?dept f:Location ?loc.
  ?emp f:Job ?job.
  FILTER (?job = "ANALYST")
} 


列出既是分析师又是经理的员工

[编辑 | 编辑源代码]
select ?emp where {
  ?emp  rdf:type  f:emp;
        f:Job ?job.
  FILTER (?job = "ANALYST"  || ?job = "MANAGER")
}

列出既不是分析师也不是经理的员工

[编辑 | 编辑源代码]
select * where {
   ?emp  rdf:type  f:emp;
         f:Job ?job.
   FILTER (?job != "ANALYST"  && ?job != "MANAGER")
}

列出姓氏以“S”开头的员工

[编辑 | 编辑源代码]
select * where {
  ?emp  rdf:type  f:emp.
  ?emp foaf:surname ?ename.
  FILTER (regex(?ename, "^S"))
} 

列出姓氏包含“AR”的员工

[编辑 | 编辑源代码]
select * where {
  ?emp  rdf:type  f:emp.
  ?emp foaf:surname ?ename.
  FILTER (regex(?ename, "AR"))
} 

列出姓氏包含“M”后跟“R”的员工,不区分大小写

[编辑 | 编辑源代码]
select * where {
  ?emp  rdf:type  f:emp.
  ?emp foaf:surname ?ename.
  FILTER (regex(?ename, "m.*r","i"))
}

计算最高薪水

[编辑 | 编辑源代码]

SPARQL 1.0 缺乏 min() 或 max(),虽然它们被添加到了某些实现中。以下方法,由 Dean Allemang 提供,可以用来实现。

select ?maxemp ?maxsal where {
 ?maxemp  rdf:type  f:emp.
 ?maxemp  f:Sal ?maxsal.
 OPTIONAL { ?emp rdf:type f:emp.
            ?emp f:Sal ?sal.
            FILTER ( ?sal > ?maxsal)
          }.
 FILTER (!bound (?sal))
}


这是如何工作的?我们寻找 **最高** 员工的最高薪水。对于这样的员工,OPTIONAL 子句将不匹配,因为没有员工的薪水更高,因此 ?sal 将不会绑定。

在 SPARQL 1.1 中,允许使用 max() 和 min(),所以返回最高薪水的查询变为

select (max(?sal) as ?maxsal) where {
  ?maxemp  rdf:type  f:emp.
  ?maxemp  f:Sal ?sal.
}

计算具有相同薪水的员工

[编辑 | 编辑源代码]
 select * where {
    ?emp1 f:Sal ?sal.
    ?emp2 f:Sal ?sal.
    FILTER (?emp1 != ?emp2)
 }

获取 SMITH 所在的部门

[编辑 | 编辑源代码]
select ?dname  where {
  ?emp  rdf:type  f:emp.
  ?emp f:Dept ?dept.
  ?emp foaf:surname "SMITH".
  ?dept f:Dname ?dname.
}

列出会计部门员工的姓名

[编辑 | 编辑源代码]
select ?ename  where {
  ?emp  rdf:type  f:emp.
  ?emp f:Dept ?dept.
  ?emp foaf:surname ?ename.
  ?dept f:Dname "Accounting".
} 


本世纪雇用的员工

[编辑 | 编辑源代码]
select ?ename ?hire where {
 ?emp  rdf:type  f:emp.
 ?emp f:HireDate ?hire.
 ?emp foaf:surname ?ename.
 FILTER (?hire > "2000-01-01"^^xs:date) 
}

请注意,需要对字面量进行类型化才能使比较工作正常。

列出其经理在不同部门的员工姓名

[编辑 | 编辑源代码]
select ?name ?edname ?mdname {
  ?emp  rdf:type  f:emp;
        foaf:surname ?name;
        f:Dept ?dept;
        f:Mgr ?mgr.
  
   ?mgr f:Dept ?mdept. 
   ?dept f:Dname ?edname.
   ?mdept f:Dname ?mdname.
   FILTER (?dept != ?mdept)
}

列出员工的等级

[编辑 | 编辑源代码]

在关系术语中,这是员工和 salgrade 表之间的 theta 连接。

select ?ename ?grade where {
 ?emp  rdf:type  f:emp;
       foaf:surname ?ename;
       f:Sal ?sal.
 ?salgrade rdf:type f:salgrade; 
       f:LoSal ?low; 
       f:HiSal ?high;
       f:Grade ?grade.
   
 FILTER (?sal >= ?low && ?sal <= ?high)
 }

简化查询语法

[编辑 | 编辑源代码]

一个新的前缀简化了通过 URI 引用单个资源的过程。

 prefix e: <http://www.cems.uwe.ac.uk/empdept/emp/>
 select ?sal  where {
    e:7900 f:Sal ?sal.
 }

是 的简写。

 select ?sal  where {
    <http://www.cems.uwe.ac.uk/empdept/emp/7900> f:Sal ?sal.
 }

我们也可以引入一个默认命名空间

prefix : <http://www.cems.uwe.ac.uk/empdept/concept/>
select ?name ?sal ?dno ?job where {
 ?emp  rdf:type  :emp;
       foaf:surname ?name;
       :Sal ?sal;
       :Dept ?dept;
       :Job ?job.  
 ?dept :DeptNo ?dno. 
}

并使用缩写 **a** 代表 rdf:type

prefix : <http://www.cems.uwe.ac.uk/empdept/concept/>
select ?name ?sal ?dno ?job where {
 ?emp  a :emp;
       foaf:surname ?name;
       :Sal ?sal;
       :Dept ?dept;
       :Job ?job.  
 ?dept :DeptNo ?dno. 
}

如果我们不需要返回资源本身,它可以是匿名的

prefix : <http://www.cems.uwe.ac.uk/empdept/concept/>
select ?name ?sal ?dno ?job where {
 [ a :emp;
   foaf:surname ?name;
   :Sal ?sal;
   :Dept ?dept;
   :Job ?job
 ].
 ?dept :DeptNo ?dno. 
}

聚合功能

[编辑 | 编辑源代码]

聚合函数,如 count() 和 sum() 以及 GROUP BY 子句,在 SPARQL 1.0 中没有定义,尽管它们在某些服务(例如 Talis 平台)中可用,以先于 SPARQL 1.1 中的标准化。


计算部门数量

[编辑 | 编辑源代码]
select (count(?dept) as ?count) where {
  ?dept  rdf:type  f:dept.

}

计算每个部门的员工数量

[编辑 | 编辑源代码]
select distinct ?dept (count(?emp) as ?count) where {
  ?dept a f:dept.
  ?emp f:Dept ?dept.
} group by ?dept

通用查询

[编辑 | 编辑源代码]

三元组数据模型的统一性使我们能够以非常通用的方式查询数据集,这在我们对数据一无所知时非常有用。

列出所有数据

[编辑 | 编辑源代码]
select * where {
 ?s ?p ?o
}

这对真实数据集来说是不切实际的,但可以通过限制返回的三元组数量来获取三元组样本。

select * where {
 ?s ?p ?o
} LIMIT 20 

列出所有员工数据

[编辑 | 编辑源代码]
select ?prop ?val where {
  ?emp  rdf:type  f:emp.
  ?emp ?prop ?val.
}

有哪些类型?

[编辑 | 编辑源代码]
select distinct ?type where {
  ?s a ?type
}

这表明定义 emp 词汇的三元组在同一个数据集中。

有哪些属性?

[编辑 | 编辑源代码]
select distinct ?prop where {
   ?s ?prop ?o
}

属性的域(或域)是什么?

[编辑 | 编辑源代码]
select distinct ?type where {
    ?s f:Sal ?v.
    ?s a ?type.
}

属性的范围是什么?

[编辑 | 编辑源代码]
select distinct ?type where {
    ?s f:Sal ?o.
    ?o a ?type.
}


此查询仅查找数据集中作为类型实例的范围。Sal 的范围是 xs:integer,但用 SPARQL 查询很难发现这一点。


select distinct ?type where {
    ?s f:Mgr ?o.
    ?o a ?type.
}

哪些属性具有给定类型作为其域?

[edit | edit source]
select distinct ?prop where {
     ?s a f:salgrade.
     ?s ?prop [].
}

模式查询

[edit | edit source]

模式数据的存在使 SPARQL 可以用来查询这些元数据。结果可以与直接查询数据的结果进行比较。

哪些属性具有给定类型的域?

[edit | edit source]
select ?prop  where {
   ?prop rdfs:domain f:emp.
}


请注意,这仅返回了 empdept 词汇表中的属性,而不是原始数据中使用的 foaf name 属性。

员工有哪些整数属性?

[edit | edit source]
select ?prop  where {
   ?prop rdfs:domain f:emp.
   ?prop rdfs:range xs:integer.
}

哪些类型的资源有薪资?

[edit | edit source]
select ?type where {
  f:Sal rdfs:domain ?type.
}


可以对数据和词汇表进行查询


MANAGER 有哪些字面属性?

[edit | edit source]
select DISTINCT ?prop  where {
   ?x f:Job "MANAGER".
   ?x a ?type. 
   ?prop rdfs:domain ?type.
   ?prop rdfs:range rdfs:literal.
}

待办事项

[edit | edit source]
  • 示例 RDF 缺少语言标签,这些标签是说明 lang() 函数所必需的
  • 所有查询应与 SQL 和 XQuery 等效项一起移至代码列表
华夏公益教科书