Problem with IF in SPARQL

77 views
Skip to first unread message

Jack Hodges

unread,
Feb 9, 2015, 3:16:20 PM2/9/15
to topbrai...@googlegroups.com
I was testing a simple conditional in SPARQL and it wasn't working. So I went to the documentation and wrote the test conditional and it worked, but do not understand why mine isn't working. The test conditional compares 2 integers and displays 2 strings. I augmented that test to have another nested IF and it still works.

My query is based on a BIND of 2 expressions to strings. Here is what it looks like:

SELECT ?res
WHERE {
    BIND ("foo" AS ?f) .
    BIND ("bar" AS ?b) .
    BIND ((IF(?f, ?f, IF(?b, ?b, "NA"))) AS ?res) .
}

This returns "foo". If I remove the first BIND statement there is no result. I tried changing this test to:

SELECT ?res
WHERE {
    BIND ("foo" AS ?f) .
    BIND ("bar" AS ?b) .
    BIND ((IF(fn:string-length(?f) > 0, ?f, IF(fn:string-length(?b) > 0, ?b, "NA"))) AS ?res) .
}

and it returns "foo". If I change the first size to 3, then it returns "bar". If I change the second size to 3 it returns "NA".

But in 'my' query this doesn't work. Here is the query:

SELECT DISTINCT *
WHERE {
    BIND (act:commonSubclassLabel("http://developer.runkeeper.com/healthgraph#Spinning") AS ?res1) .
    BIND (act:commonSuperclassLabel("http://developer.runkeeper.com/healthgraph#Spinning") AS ?res2) .
    BIND ((IF(fn:string-length(?res2) > 0, ?res2,  IF(fn:string-length(?res1) > 0, ?res1, "NA"))) AS ?res) .
}

The function calls to 'commonSubclassLabel' and 'commonSuperclassLabel" work fine on their own (both return strings), and the result returned is ?res2 if its length exceeds 0. If not, there is a value for ?res1 but it doesn't ever get bound to ?res. If I swap ?res2 and ?res1 in the last BIND the same query works for ?res1 but not ?res2, so there is something in my IF statements 'THEN' block that doesn't work. If I replace the THEN block with just ?res1 (or ?res2 as the case may be), nothing changes in the result.

As you can see, I have worked myself into a lather over this by making it more complex than it should have to be, but as is normal in such cases when the simple logic didn't work I began more and more convoluted things.

Any pointers would be greatly appreciated!

These queries are being executed in TBCME v4.2.

Jack

Scott Henninger

unread,
Feb 9, 2015, 6:38:13 PM2/9/15
to topbrai...@googlegroups.com
Jack; The problem may be that SPARQL's declarative nature does not impose any ordering on its statements.  One should be able to place the statements in any order and the result will be the same.

In your case, you need to make sure the ?res1 and ?res2 binding are performed before the IF statement, so you can include this in a graph statement.  The SPARQL engine will execute the graphs inside-out.  (If you're interested in the actual ordering of the clauses, and don't mind a bit of Lisp-like syntax, then you can take a look at the query in the "Debug query".  This will at least let you know whether or not an ordering is being sent to the SPARQL engine.)

So, the following ought to do what you need by specifying that the first two statements are executed before the rest.


SELECT DISTINCT *
WHERE {
    {  BIND (act:commonSubclassLabel("http://developer.runkeeper.com/healthgraph#Spinning") AS ?res1) .
       BIND (act:commonSuperclassLabel("http://developer.runkeeper.com/healthgraph#Spinning") AS ?res2) .
    }
    BIND ((IF(fn:string-length(?res2) > 0, ?res2,  IF(fn:string-length(?res1) > 0, ?res1, "NA"))) AS ?res) .
}


-- Scott
--
You received this message because you are subscribed to the Google Group "TopBraid Suite Users", the topics of which include Enterprise Vocabulary Network (EVN), Reference Data Manager (RDM), TopBraid Composer, TopBraid Live, TopBraid Insight, SPARQLMotion, SPARQL Web Pages and SPIN.
To post to this group, send email to topbrai...@googlegroups.com
---
You received this message because you are subscribed to the Google Groups "TopBraid Suite Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to topbraid-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Holger Knublauch

unread,
Feb 9, 2015, 6:44:24 PM2/9/15
to topbrai...@googlegroups.com
Another thing to keep in mind is that IF will return nothing if the condition is returning "unbound" (fail). For example,

    IF(strlen(?a) > 0, "1", "2")

will return nothing if ?a is not a string - it will fail and return unbound - not "2". A safer way of expressing this would be

    IF(bound(?a) && strlen(?a) > 0, "1", "2")

For some use cases, the COALESCE keyword is a better option than IF.

Not sure if this is on topic for your specific scenario.

Holger

Jack Hodges

unread,
Feb 9, 2015, 6:59:57 PM2/9/15
to topbrai...@googlegroups.com
Holger and Scott,

Thank you very much for looking at this. Scott, I tried the scoping (as per your suggestion) and it didn't change anything. I must admit that I had not thought to run the query debugger, but I do not really understand how it works anyway.

Holger, I tried using bound(?res2) and it worked! Thank you for pointing this out. Incidentally, I had already tried COALESCE and it didn't work for me (but that was several cycles ago so the logic I was working with was perhaps different then too).

Thanks again, both of you!!!

Jack

You received this message because you are subscribed to a topic in the Google Groups "TopBraid Suite Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/topbraid-users/Qb4p-4rJgqk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to topbraid-user...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Jack
Reply all
Reply to author
Forward
0 new messages