跳转到内容

SPARQL/SELECT

来自维基教科书,开放的书籍,开放的世界

SELECT 语句包含 2 或 3 个部分。

SELECT  ... query result variables ...
WHERE {
        ... query pattern ...
}
        ... optional query modifiers ...
GROUP BY ...
HAVING ...
ORDER BY ...
LIMIT ...

第一部分是查询结果变量。这些将在查询执行时显示。第二部分是包含查询模式的 WHERE 子句。这定义了数据选择并生成变量,最后一部分是可选修饰符。

示例

SELECT ?child ?childLabel
WHERE
{
# ?child  father   Bach
  ?child wdt:P22 wd:Q1339.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

试试看!

查询结果变量

[编辑 | 编辑源代码]

SELECT ?child ?childLabel ... 在上面的示例中,?child?childLabel 是变量。变量用空格隔开。可以使用 AS 为变量显示另一个名称(别名),例如 (?child AS ?Child_of_Bach)。注意,别名也应该是一个变量,并且组合应该以括号 (?a AS ?b) 开头和结尾。
PS。对于标签的别名,标签应该在 SERVICE 中明确定义。或者,变量也可以根据那里的要求命名。

SELECT (?child AS ?Child_of_Bach) (?childLabel AS ?Name)
WHERE
{
# ?child  father   Bach
  ?child wdt:P22 wd:Q1339.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". 
                           ?child rdfs:label ?childLabel.
                         }
}

试试看!

查询模式

[编辑 | 编辑源代码]

查询模式指定数据选择并生成变量。

# ?child  father   Bach
  ?child wdt:P22 wd:Q1339.

在本例中,三元组 ?child wdt:p22 wd:Q1339 指定变量 ?child 必须具有父/父亲巴赫。

三元组的任何部分(主体、谓词和宾语)都可以是变量。这使得这种选择非常灵活。

可以添加更多三元组,例如显示性别、出生日期和死亡日期。每个句子 应该以句号结尾。新变量应该添加到顶部(查询结果变量)以显示它们。

SELECT ?child ?childLabel ?genderLabel ?birth_date ?date_of_death
WHERE
{
  ?child wdt:P22 wd:Q1339.# ?child  has father   Bach
  ?child wdt:P21 ?gender.
  ?child wdt:P569 ?birth_date.
  ?child wdt:P570 ?date_of_death.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

试试看!

可选查询修饰符

[编辑 | 编辑源代码]

有关完整描述,请参见修饰符 章节。

通过在 WHERE { } 子句的最后一个大括号后添加 ORDER BY ?birth_date,可以按出生日期对上述查询进行排序。

SELECT ?child ?childLabel ?genderLabel ?birth_date ?date_of_death
WHERE
{
  ?child wdt:P22 wd:Q1339.# ?child  has father   Bach
  ?child wdt:P21 ?gender.
  ?child wdt:P569 ?birth_date.
  ?child wdt:P570 ?date_of_death.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?birth_date

试试看!

删除重复项

[编辑 | 编辑源代码]

您可能已经注意到,上述查询产生了 21 条记录,而巴赫只有 20 个孩子。这是由于约翰·克里斯托夫·弗里德里希·巴赫 有 2 个条目,因为有 2 个不同的出生日期,分别为 1732 年 6 月 21 日和 23 日。

通常建议在结果变量中使用 DISTINCT,例如

SELECT DISTINCT ?child ?childLabel ?genderLabel ?birth_date ?date_of_death
WHERE
{
  ?child wdt:P22 wd:Q1339.# ?child  has father   Bach
  ?child wdt:P21 ?gender.
  ?child wdt:P569 ?birth_date.
  ?child wdt:P570 ?date_of_death.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?child

试试看!

DISTINCT 删除重复条目,但在本例中没有帮助,因为条目是不同的。为了有所帮助,所有参数都应该相等。

有帮助的是按孩子分组,并合并 ?birth_date 的值。同样,?date_of_death?genderLabel 也被分组以保持一致。

SELECT ?child ?childLabel 
       (GROUP_CONCAT(DISTINCT ?genderLabel;   SEPARATOR=", ") AS ?genderLabels)
       (GROUP_CONCAT(DISTINCT ?birth_date;    SEPARATOR=", ") AS ?birth_dates)
       (GROUP_CONCAT(DISTINCT ?date_of_death; SEPARATOR=", ") AS ?dates_of_death)
WHERE
{
  ?child wdt:P22 wd:Q1339.# ?child  has father   Bach
  ?child wdt:P21 ?gender.
  ?child wdt:P569 ?birth_date.
  ?child wdt:P570 ?date_of_death.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". 
                           ?child  rdfs:label ?childLabel.
                           ?gender rdfs:label ?genderLabel.
                         }
}
GROUP BY ?child ?childLabel
ORDER BY ?birth_dates

试试看!

使用的可选查询修饰符是 GROUP BY,变量通过使用 (GROUP_CONCAT(DISTINCT ?var1; SEPARATOR=", ") AS ?var2) 来合并。ORDER BY 已通过使用合并后的变量 ?birth_dates 而不是 ?birth_date 进行修改。所有标签都应该在 SERVICE 中明确定义。

有关完整描述,请参见修饰符 章节。

另一种删除重复项的方法是只显示一个可能的值,方法是使用聚合函数 MINMAXSUMAVG 之一。

SELECT ?child ?childLabel 
       (MIN(?genderLabel)   AS ?genderlabel1) 
       (MIN(?birth_date)    AS ?birth_date1) 
       (MAX(?date_of_death) AS ?date_of_death1)
WHERE
{
  ?child wdt:P22 wd:Q1339.# ?child  has father   Bach
  ?child wdt:P21 ?gender.
  ?child wdt:P569 ?birth_date.
  ?child wdt:P570 ?date_of_death.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". 
                           ?child  rdfs:label ?childLabel.
                           ?gender rdfs:label ?genderLabel.
                         }
}
GROUP BY ?child ?childLabel
ORDER BY ?birth_date1

试试看!

使用的可选查询修饰符也是 GROUP BY,变量通过使用 (MIN(?var) AS ?var1) 来合并。ORDER BY 已通过使用第一个出生日期 ?birth_date1 而不是 ?birth_date 进行修改。所有标签也应该在 SERVICE 中明确定义。

添加缺失条目

[编辑 | 编辑源代码]

让我们尝试对奥巴马 (Q76) 的上述查询之一。

SELECT DISTINCT ?child ?childLabel ?genderLabel ?birth_date ?date_of_death
WHERE
{
  ?child wdt:P22 wd:Q76.# ?child  has father   Obama
  ?child wdt:P21 ?gender.
  ?child wdt:P569 ?birth_date.
  ?child wdt:P570 ?date_of_death.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?child

试试看!

这将导致没有结果,尽管奥巴马有两个孩子。原因是,为了匹配这个查询,一个潜在的结果(孩子)必须匹配我们列出的所有三元组:它必须有性别、出生日期和死亡日期。如果其中一个或多个属性不存在,它将不会匹配。这不是我们想要的结果:我们主要想要所有孩子的列表——如果其他数据可用,我们希望将其包含在内,但我们不希望它限制我们的结果列表。

解决方案是告诉 WDQS 这些三元组是 OPTIONAL

SELECT DISTINCT ?child ?childLabel ?genderLabel ?birth_date ?date_of_death
WHERE
{
  ?child wdt:P22 wd:Q76.# ?child  has father   Obama
  OPTIONAL{ ?child wdt:P21 ?gender. }
  OPTIONAL{ ?child wdt:P569 ?birth_date. }
  OPTIONAL{ ?child wdt:P570 ?date_of_death. }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?child

试试看!

现在显示了两个孩子,很明显死亡日期还没有填写,因为这些孩子还活着。

有关完整描述,请参见可选 章节。

万无一失:添加缺失条目并删除重复条目

[编辑 | 编辑源代码]

任何给定父亲的孩子及其详细信息的万无一失列表将是

SELECT ?child ?childLabel 
       (GROUP_CONCAT(DISTINCT ?genderLabel;   SEPARATOR=", ") AS ?genderLabels)
       (GROUP_CONCAT(DISTINCT ?birth_date;    SEPARATOR=", ") AS ?birth_dates)
       (GROUP_CONCAT(DISTINCT ?date_of_death; SEPARATOR=", ") AS ?dates_of_death)
WHERE
{
  ?child wdt:P22 wd:Q76.# ?child  has father   Obama
  OPTIONAL{ ?child wdt:P21 ?gender. }
  OPTIONAL{ ?child wdt:P569 ?birth_date. }
  OPTIONAL{ ?child wdt:P570 ?date_of_death. }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". 
                           ?child  rdfs:label ?childLabel.
                           ?gender rdfs:label ?genderLabel.
                         }
}
GROUP BY ?child ?childLabel
ORDER BY ?birth_dates

试试看!

这结合了 OPTIONAL 子句(如果属性不存在)和 GROUP_CONCAT 子句(如果存在多个属性)。


华夏公益教科书