.. _example15: Example 15: Range queries ------------------------- In many of the previous examples we have used the :meth:`getStatements` method to find all triples conforming to a given pattern. The patterns we have used so far matched each triple component against a single value. It is possible to use more complex patterns that can match a range of values for each component. To illustrate this let us first create a connection: .. literalinclude:: doctest_setup.py :language: python_rdf :start-after: BEGIN-CONNECT :end-before: END-CONNECT and construct some data: .. testcode:: example15 conn.addData(""" @prefix : . :mercury a :planet ; :moons 0 . :venus a :planet ; :moons 0 . :earth a :planet ; :moons 1 . :mars a :planet ; :moons 2 . :jupiter a :planet ; :moons 67 . :saturn a :planet ; :moons 62 . :uranus a :planet ; :moons 27 . :neptune a :planet ; :moons 14 . :pluto a :dwarf_planet ; :moons 5 . """) Suppose that we want to locate all planets that have at least one, but no more than five moons. To issue such a query we need to create a :class:`.Range` object: .. testcode:: example15 one_to_five = conn.createRange(1, 5) We can pass the range object to :meth:`getStatements`: .. testcode:: example15 moons = conn.createURI('ex://moons') with conn.getStatements( None, moons, one_to_five) as result: for statement in result: print(statement.getSubject()) This will find two planets and one dwarf planet, as expected: .. testoutput:: example15 :options: +SORT The arguments to :meth:`createRange` can be either RDF terms or regular Python values that will be converted to typed :class:`literals `. In our example we used have used values of type ``int``, which will be mapped to literals of type ````. Range queries will only match values of exactly the same type. For instance if we add another triple to our store: .. testcode:: example15 conn.addData(""" @prefix : . @prefix xsd: . :coruscant a :planet ; :moons "4"^^xsd:long . """) And then reissue our query: .. testcode:: example15 with conn.getStatements( None, moons, one_to_five) as result: for statement in result: print(statement.getSubject()) we will find that the result has not changed: .. testoutput:: example15 :options: +SORT Range queries can also be performed with SPARQL, using ``FILTER``: .. testcode:: example15 conn.executeTupleQuery(''' SELECT ?planet { ?planet ?moons . filter (?moons <= 5 && ?moons >= 1) }''', output=True) The result is the same as in the previous example. .. testoutput:: example15 :options: +SORT ------------------ | planet | ================== | ex://coruscant | | ex://earth | | ex://mars | | ex://pluto | ------------------ When the filter expression is a simple set of inequalities, as it is in this case, the query engine will use indices to optimize the query execution, similaraly to the way :meth:`getStatements` does for range queries.