I want to fetch the population of the most and least populated state. I know how to use ORDER BY (ASC and DESC). How can I combine these two (ASC and DESC) in a single query?
SELECT ?population
{
?state rdf:type :State
?state :hasPopulation ?population.
} ORDER BY DESC(?population) LIMIT 1
AND
SELECT ?population
{
?state rdf:type :State
?state :hasPopulation ?population.
} ORDER BY ASC(?population) LIMIT 1
SELECT ?population_max ?population_min {
?state_max rdf:type :State .
?state_max :hasPopulation ?population_max .
?state_min rdf:type :State .
?state_min :hasPopulation ?population_min .
} ORDER BY DESC(?population_max) ASC(?population_min) LIMIT 1
Perhaps more efficient:
SELECT * {
{
SELECT (?population AS ?population_max) {
?state rdf:type :State .
?state :hasPopulation ?population .
} ORDER BY DESC(?population) LIMIT 1
}
{
SELECT (?population AS ?population_min) {
?state rdf:type :State .
?state :hasPopulation ?population .
} ORDER BY ASC(?population) LIMIT 1
}
}
With AnzoGraph or Blazegraph, one could use named subqueries in such a case:
SELECT *
WITH {
SELECT ?pop { [] a :State ; :hasPopulation ?pop }
} AS %unsorted
WHERE {
{ SELECT (?pop AS ?max) { INCLUDE %unsorted } ORDER BY DESC(?pop) LIMIT 1 }
{ SELECT (?pop AS ?min) { INCLUDE %unsorted } ORDER BY ASC(?pop) LIMIT 1 }
}
Finally, rather rewriting than combining:
SELECT (MAX(?population) AS ?population_max) (MIN(?population) AS ?population_min) {
?state rdf:type :State .
?state :hasPopulation ?population
}
If aggregates are used... but the GROUP BY term is not used, then this is taken to be a single implicit group, to which all solutions belong.
You could perhaps use UNION to combine 'max' and 'min' population. Here is AnzoGraph syntax:
WITH (
SELECT ?pop
WHERE {
?state a :State ;
:hasPopulation ?pop
}
as <unsorted_pop>
)
SELECT *
WHERE {
{ SELECT (max(?pop) as ?population)
WHERE { QUERY <unsorted_pop> }
}
UNION
{ SELECT (min(?pop) as ?population)
WHERE { QUERY <unsorted_pop> }
}
}
Related
I'm trying to get some data from Wikidata. I've got a simple query which fetches information about universities:
SELECT ?item ?itemLabel ?site WHERE {
?item (p:P31/ps:P31/(wdt:P279*)) wd:Q38723;
wdt:P17 ?country;
wdt:P856 ?site.
SERVICE wikibase:label { bd:serviceParam wikibase:language "ru,en". }
}
And another query, which gets list of members of the CIS:
SELECT DISTINCT ?state WHERE {
?state wdt:P31/wdt:P279* wd:Q3624078;
p:P463 ?memberOfStatement.
?memberOfStatement a wikibase:BestRank;
ps:P463 wd:Q7779
MINUS { ?memberOfStatement pq:P582 ?endTime. }
MINUS { ?state wdt:P576|wdt:P582 ?end. }
}
Both work fine. But now I want to combine them to get list of universities which are located in the CIS. I try to do it like shown in the answer to this question:
SELECT ?item ?itemLabel ?site WHERE {
?item (p:P31/ps:P31/(wdt:P279*)) wd:Q38723;
wdt:P17 ?country;
wdt:P856 ?site.
FILTER(EXISTS {
SELECT DISTINCT ?state WHERE {
{
?state (wdt:P31/(wdt:P279*)) wd:Q3624078;
p:P463 ?memberOfStatement.
?memberOfStatement rdf:type wikibase:BestRank;
ps:P463 wd:Q7779.
MINUS { ?memberOfStatement pq:P582 ?endTime. }
MINUS { ?state (wdt:P576|wdt:P582) ?end. }
}
FILTER(?country = ?state)
}
})
SERVICE wikibase:label { bd:serviceParam wikibase:language "ru,en". }
}
But, for some reason, I get zero results. What am I doing wrong here?
In SPARQL I can perform the following query in order to retrieve the fields and the total count in one query result:
SELECT ?total ?s
WHERE
{
{ SELECT (COUNT(?s) AS ?total)
WHERE
{ ?s <https://some/predicate/for/var1> ?var1 ;
<https://some/predicate/for/var1> ?var2
FILTER ( ( ?var1 = "something" ) && ( ?var2 = "something2" ) )
}
}
{ SELECT ?s
WHERE
{ ?s <https://some/predicate/for/var1> ?var1 ;
<https://some/predicate/for/var1> ?var2
FILTER ( ( ?var1 = "something" ) && ( ?var2 = "something2" ) )
}
LIMIT 3
}
}
Which returns something like this (s fields matched the specific predicate and filter I provided on the query):
+-------+----------------------------------------+
| total | s |
+-------+----------------------------------------+
| 150 | http://the/path/to/the/subject |
| 150 | http://the/path/to/another/subject |
| 150 | http://the/path/to/yet/another/subject |
+-------+----------------------------------------+
I want to do the same for full text search queries, which can be used as follows ?s bds:search “something” .
However, composing a query with the same structure as the previous one, does not work:
PREFIX bds: <http://www.bigdata.com/rdf/search#>
SELECT ?total ?s ?org
WHERE
{
{ SELECT (COUNT(?s) AS ?total)
WHERE{
?matchedValue
bds:search "something" ;
bds:relevance ?score ;
bds:rank ?rank .
?s ?matchedProperty ?matchedValue
FILTER ( ! isBlank(?s) )
}
}
{ SELECT ?s ?matchedProperty ?score ?rank
WHERE{
?matchedValue
bds:search "something" ;
bds:relevance ?score ;
bds:rank ?rank .
?s ?matchedProperty ?matchedValue
FILTER ( ! isBlank(?s) )
}
LIMIT 10
}
}
Even though, those subqueries return the correct result separately.
As correctly mentioned by #stanislav-kralin and coming from the issue in Jira, you have to explicitly use SERVICE clause:
PREFIX bds: <http://www.bigdata.com/rdf/search#>
SELECT ?total ?s ?org
WHERE
{
{ SELECT (COUNT(?s) AS ?total)
WHERE {
SERVICE <http://www.bigdata.com/rdf/search#search> {
?matchedValue
bds:search "something" ;
bds:relevance ?score ;
bds:rank ?rank .
}
?s ?matchedProperty ?matchedValue
FILTER ( ! isBlank(?s) )
}
}
{ SELECT ?s ?matchedProperty ?score ?rank
WHERE {
SERVICE <http://www.bigdata.com/rdf/search#search> {
?matchedValue
bds:search "something" ;
bds:relevance ?score ;
bds:rank ?rank .
}
?s ?matchedProperty ?matchedValue
FILTER ( ! isBlank(?s) )
}
LIMIT 10
}
}
Have the following working SPARQL query that selects items from DBpedia that include the string "fish" in their name.
SELECT ?name, ?kingdom, ?phylum, ?class, ?order, ?family, ?genus, ?species, ?subspecies, ?img, ?abstract
WHERE {
?s dbpedia2:regnum ?hasValue;
rdfs:label ?name
FILTER regex( ?name, "fish", "i" )
FILTER ( langMatches( lang( ?name ), "EN" ))
?animal dbpedia2:name ?name;
foaf:depiction ?img;
dbpedia2:regnum ?kingdom
OPTIONAL { ?animal dbpedia2:ordo ?order . }
OPTIONAL { ?animal dbpedia2:phylum ?phylum . }
OPTIONAL { ?animal dbpedia2:classis ?class . }
OPTIONAL { ?animal dbpedia2:familia ?family . }
OPTIONAL { ?animal dbpedia2:genus ?genus . }
OPTIONAL { ?animal dbpedia2:species ?species . }
OPTIONAL { ?animal dbpedia2:subspecies ?subspecies . }
OPTIONAL {
FILTER ( langMatches( lang( ?abstract ), "EN" ))
}
}
GROUP BY ?name
LIMIT 500
Here is the result on SNORQL.
This approach finds animals with the word "fish" in their name (example: "starfish" which is not a fish but member of the phylum Echinoderm).
Would like a more precise query that selects DBpedia items by phylum, or by class, or by order, etc.
How to change the query to search only on dbpedia2:phylum (Chordata); on dbpedia2:classis (Actinopterygii); on dbpedia2:familia; etc. ?
Looking at Tuna, I see that there is a rdf:type assertion for the class
http://umbel.org/umbel/rc/Fish
that looks useful. E.g.,
select ?fish { ?fish a <http://umbel.org/umbel/rc/Fish> }
SPARQL results (10,000)
There's also the dbpedia-owl:Fish class, which gets more results:
select (count(*) as ?nFish) where {
?fish a dbpedia-owl:Fish .
}
SPARQL results (17,420)
While Wikipedia has lots of scientific classification information, I don't see much of it reflected in DBpedia. E.g,. while the Wikipedia article for Tuna has kingdom, phylum, class, order, etc., I don't see that data in the corresponding DBpedia resource.
Notes
Note that your query, as written, isn't actually legal SPARQL (even if Virtuoso, the SPARQL endpoint that DBpedia uses, accepts it). You can't have commas between the projection variables. Also, once you group by one variable, the non-group variables can't appear in the variable list. You could sample the other values though. E.g., you should end up with something like:
SELECT
?name
(sample(?kingdom) as ?kingdom_)
(sample(?phylum) as ?phylum_)
#-- ...
(sample(?img) as ?img_)
(sample(?abstract) as ?abstract_)
WHERE {
?s dbpedia2:regnum ?hasValue;
rdfs:label ?name
FILTER regex( ?name, "fish", "i" )
FILTER ( langMatches( lang( ?name ), "EN" ))
?animal dbpedia2:name ?name;
foaf:depiction ?img;
dbpedia2:regnum ?kingdom
OPTIONAL { ?animal dbpedia2:ordo ?order . }
OPTIONAL { ?animal dbpedia2:phylum ?phylum . }
OPTIONAL { ?animal dbpedia2:classis ?class . }
OPTIONAL { ?animal dbpedia2:familia ?family . }
OPTIONAL { ?animal dbpedia2:genus ?genus . }
OPTIONAL { ?animal dbpedia2:species ?species . }
OPTIONAL { ?animal dbpedia2:subspecies ?subspecies . }
OPTIONAL {
FILTER ( langMatches( lang( ?abstract ), "EN" ))
}
}
GROUP BY ?name
LIMIT 500
I have a list of dbpedia URI's and I want to get some informations (categories, label) about each of them in one query:
SELECT ?category ?label where {
{
dbpedia:Financial_Times dcterms:subject ?category .
dbpedia:Financial_Times rdfs:label ?label .
FILTER ( lang(?label) = 'en' )
}
UNION
{
dbpedia:London dcterms:subject ?category .
dbpedia:London rdfs:label ?label .
FILTER ( lang(?label) = 'en' )
}
}
This query works fine, but I'd need to add the URI's themself into the result to be able identify which result row is for which URI.
you can do something like
SELECT distinct ?who ?category ?label where {
{
?who dcterms:subject ?category .
?who rdfs:label ?label .
FILTER ( lang(?label) = 'en' ).
FILTER(?who = dbpedia:Financial_Times or ?who = dbpedia:London )
}}
or use a trick like this
SELECT ?who ?category ?label where {
{
dbpedia:Financial_Times dcterms:subject ?category .
dbpedia:Financial_Times rdfs:label ?label .
FILTER ( lang(?label) = 'en' ).
VALUES ?who { dbpedia:Financial_Times}
}
UNION
{
dbpedia:London dcterms:subject ?category .
dbpedia:London rdfs:label ?label .
FILTER ( lang(?label) = 'en' ) .
VALUES ?who { dbpedia:London }
}}
the second one probably is faster but needs SPARQL 1.1
I have two SPARQL updates.First one:
INSERT
{ GRAPH <[http://example/bookStore2]> { ?book ?p ?v } }
WHERE
{ GRAPH <[http://example/bookStore]>
{ ?book dc:date ?date .
FILTER ( ?date > "1970-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
} }
Second:
INSERT
{ GRAPH <[http://example/bookStore2]> { ?book ?p ?v } }
WHERE
{ GRAPH <[http://example/bookStore3]>
{ ?book dc:date ?date .
FILTER ( ?date > "1980-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
} }
Can i combine them with the UNION operator? And if yes, is it an equivalent result? Is it possible to use UNION in SPARQL updates such as in "Select"?
AndyS's answer is correct; you can combine them, and the description of UNION is found in section 7 Matching Alternatives of the SPARQL specification. The combined query would be:
INSERT {
GRAPH <[http://example/bookStore2]> { ?book ?p ?v }
}
WHERE{
{
GRAPH <[http://example/bookStore]> {
?book dc:date ?date .
FILTER ( ?date > "1970-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
}
}
UNION
{
GRAPH <[http://example/bookStore3]> {
?book dc:date ?date .
FILTER ( ?date > "1980-01-01T00:00:00-02:00"^^xsd:dateTime )
?book ?p ?v
}
}
}
In this particular case where the patterns are so similar, you could also just abstract out the differing parts with VALUES:
INSERT {
GRAPH <[http://example/bookStore2]> { ?book ?p ?v }
}
WHERE{
values (?graph ?startDate) {
(<[http://example/bookStore]> "1970-01-01T00:00:00-02:00"^^xsd:dateTime)
(<[http://example/bookStore3]> "1980-01-01T00:00:00-02:00"^^xsd:dateTime)
}
GRAPH ?graph {
?book dc:date ?date .
FILTER ( ?date > ?startDate )
?book ?p ?v
}
}
The WHERE clause is the same as SPARQL Query - you can use UNION.