4

When running the following query I get only one result as expected

SELECT DISTINCT ?city ?country WHERE {
  FILTER (?city = wd:Q1748) .

  # Primary country
  ?city p:P17 ?c .
  ?c ps:P17 ?country ;
     wikibase:rank ?rank .
  FILTER NOT EXISTS { ?c pq:P582 [] . } # Existing countries only
  FILTER NOT EXISTS {
    ?city p:P17 [ wikibase:rank ?rank2 ] .
    FILTER (?rank2 = wikibase:PreferredRank && ?rank != wikibase:PreferredRank) .
  }
  FILTER (?rank != wikibase:DeprecatedRank) .
}

However, I get two results if I query the same code as a subquery:

SELECT * WHERE {
  {
    SELECT DISTINCT ?city ?country WHERE {
      FILTER (?city = wd:Q1748) .

      # Primary country
      ?city p:P17 ?c .
      ?c ps:P17 ?country ;
         wikibase:rank ?rank .
      FILTER NOT EXISTS { ?c pq:P582 [] . } # Existing countries only
      FILTER NOT EXISTS {
        ?city p:P17 [ wikibase:rank ?rank2 ] .
        FILTER (?rank2 = wikibase:PreferredRank && ?rank != wikibase:PreferredRank) .
      }
      FILTER (?rank != wikibase:DeprecatedRank) .
    }
  }
}

According to the documentation the subquery is executed first and the result is then transferred to the outer query, so why does SELECT * not give the same result?

Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
Bjørn RL
  • 55
  • 1
  • 6

1 Answers1

1

As explained in the Wikidata documentation here :

The “filter not exists” clause seems to often be inefficient for unclear reasons. To work fine, queries with “filter not exists” often seem to have to be rewritten.

I modified your query and now both queries return the same results :

SELECT * WHERE {
  {
    SELECT DISTINCT ?city ?country WHERE {
      FILTER (?city = wd:Q1748) .

      # Primary country
      ?city p:P17 ?c .
      ?c ps:P17 ?country ;
         wikibase:rank ?rank .
      FILTER NOT EXISTS { ?c pq:P582 [] . } # Existing countries only
      OPTIONAL {?city p:P17 [ wikibase:rank ?rank2 ] .}
      FILTER (?rank2 = wikibase:PreferredRank && ?rank != wikibase:PreferredRank) .
      FILTER (?rank != wikibase:DeprecatedRank) .
    }
  }
}

I also checked the ranks of p17 using the following query and wikibase:DeprecatedRank is not the results:

SELECT * WHERE {
wd:Q1748 p:P17 ?o. ?o ?p ?q.
}

wd:Q35 wikibase:PreferredRank
wd:Q756617 wikibase:NormalRank
Arby Sidi
  • 56
  • 4
  • Your answer to why it happens is accepted. However, your query using `OPTIONAL` is not equivalent to the `FILTER NOT EXISTS` since it picks a random rank for `?rank2` which could be the same as `?rank`. In this case it returns the preferred value but for e.g. Q165413 it returns the wrong value. – Bjørn RL Jan 08 '23 at 17:35
  • I think replacing it with this should make it equivalent `OPTIONAL { ?city p:P17 [ wikibase:rank ?rank2 ] . FILTER (?rank2 = wikibase:PreferredRank && ?rank != wikibase:PreferredRank) . } FILTER (!BOUND(?rank2))` – Bjørn RL Jan 08 '23 at 17:41