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
中明确定义。
有关完整描述,请参见修饰符 章节。
另一种删除重复项的方法是只显示一个可能的值,方法是使用聚合函数 MIN
、MAX
、SUM
或 AVG
之一。
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
子句(如果存在多个属性)。