sparqlstardog

SPARQL Query to find results which do not meet a certain criteria


I am trying to write a SPARQL query which will return a set of patient identifier codes (?Crid) which have associated with them a specific diagnosis code (?ICD9) and DO NOT have associated with them a specific medication AND which have an order date (?OrderDate) prior to their recruitment date (?RecruitDate). I have incorporated the OBIB ontology into my graph.

Here is what I have so far (a bit simplified and with a few steps through the graph omitted for readability/sensitivity):

SELECT DISTINCT ?Crid WHERE 
{?Crid a obib:CRID .

#-- Return CRIDs with a diagnosis
?Crid obib:hasPart ?ICD9 .
?ICD9 a obib:diagnosis .

#-- Return CRIDs with a medical prescription record
?Crid obib:hasPart ?medRecord .
?medRecord a obib:medicalRecord .

#-- Return CRIDs with an order date
?medRecord obib:hasPart ?OrderDate .
?OrderDate a obib:dateOfDataEntry .

#-- Return CRIDs with a recruitment date
?Crid obib:hasPart ?FormFilling .
?FormFilling a obib:formFilling .
?RecruitDate obib:isAbout ?FormFilling .
?RecruitDate a obib:dateOfDataEntry .

#-- Filter results for specific ICD9 codes
FILTER (?ICD9 = '1')

#-- Subtract Results with Certain Medication and Order Date Prior to Recruitment
#-- This is the part that I think is giving me a problem
MINUS {
    FILTER (regex (?medRecord, "medication_1", "i"))
    FILTER (?RecruitDate-?OrderDate < "P0D"^^xsd:dayTimeDuration)
      }
}

My gut feeling is that I am not using MINUS correctly. This query returns mostly the right results: I am expecting 10 results and it is returning 12. The extraneous 2 results did take "medication_1" and have order dates before their recruitment dates, so I do not want them to be included in the set.

In case it matters, I am using a Stardog endpoint to run this query and to store my graph data.


Solution

  • Instead of

    #-- Subtract Results with Certain Medication and Order Date Prior to Recruitment
    #-- This is the part that I think is giving me a problem
    MINUS {
        FILTER (regex (?medRecord, "medication_1", "i"))
        FILTER (?RecruitDate-?OrderDate < "P0D"^^xsd:dayTimeDuration)
          }
    }
    

    I'd probably just write this without MINUS as:

    FILTER (!regex(?medRecord, "medication_1", "i"))
    FILTER (?RecruitDate-?OrderDate >= "P0D"^^xsd:dayTimeDuration)
    

    I'd also probably consider whether REGEX is the right tool here (would a simple string comparison work?), but that's a different issue.