Search code examples
sparqlrdfblaze

RDF SPARQL Query - Find tuples that are not part of both conditions (LEFT JOIN in SQL)


Below is the data set I have:

:project#1   :hasRevision        :revision#1
:revision#1  :hasRevisionNumber  1 
:project#1   :hasRevision        :revision#2
:revision#2  :hasRevisionNumber  2
:project#1   :hasRevision        :revision#3
:revision#3  :hasRevisionNumber  3
:revision#1  :committed          :A1
:A1          :hasId              1
:revision#2  :committed          :A2
:A2          :hasId              2
:revision#3  :reverted           :A1

Use case:

Need to fetch attributes committed in each revision.
- If the user asks for :revision#1, A1 should be returned.
- If the user asks for :revision#2, A1 and A2 should be returned.
- If the user asks for :revision#3, only A2 should be returned as A1 is :reverted in :revision#3.

The closest query I could come up with is below which is not working:

select ?attribute ?id WHERE { 
    :project1  :hasRevision       ?revision . 
    ?revision  :hasRevisionNumber ?revNum ; 
               :committed         ?attribute . 
   ?attribute  :hasId             ?id . 
   FILTER NOT EXISTS { ?revision :reverted ?attribute } 
   FILTER ( ( ?revNum <= 3 && ?revNum > 0 ) && ?id in (1,2) ) 
}

Actual Output:

A1 & A2 

Expected Output:

A2

I understand the issue. Not able to come up with a proper query. Can any of you please help.

Thanks in advance.


Solution

  • Make use of different variable in the FILTER NOT EXISIT, e.g.

    FILTER NOT EXISTS { ?otherRevision :reverted ?attribute } 
    

    Edit: after the additional comment from @Linz and adding a filter to look only for revisions with smaller revison numbers.

    prefix : <http://base.org/>
    select ?attribute ?id WHERE { 
        bind (3 as ?targetRevisionNum )
        :project1  :hasRevision       ?revision . 
        ?revision  :hasRevisionNumber ?revNum ; 
                   :committed         ?attribute . 
       ?attribute  :hasId             ?id . 
        FILTER NOT EXISTS { 
            ?other :reverted ?attribute . 
            ?other :hasRevisionNumber ?otherRevNum .
            filter (?otherRevNum <= ?targetRevisionNum )
        } 
       FILTER ( ( ?revNum <= ?targetRevisionNum && ?revNum > 0 ) && ?id in (1,2) ) 
    }