tredecoppe
tredecoppe

Reputation: 3

XQuery 1.0 is not printing what I expect - Wrong use of FLWR

I'd like to get a list of doctors without ill patients. (ill means with at least one Value in Outcome outside MinVal and MaxVal)

I've understood that the value is printed twice because there are 2 Exams made by Doctor Stack Overflow.

Moreover in $doc-ill there are only Doctor that have an Exam with the first Outcome out of range. Instead what I wanted to do is put in $doc-ill all the Doctor with at least one Outcome out of range.

Can someone highlight what I am doing wrong?

declare function local:outRange($x as element()) as xs:boolean{
  boolean( $x/Value < $x/MinVal or $x/Value > $x/MaxVal )
};

(: List of all doctors :)
let $alldoc := distinct-values(//Exam/Doctor)

(: List of doctors with at least 1 ill patient :)
    for $exam in //Exam
    let $doc-ill := $exam/Doctor
    where some $outc in $exam/Outcome satisfies local:outRange($outc)
    return (

(: List of doctors without hill patients :)
        let $ok := (
            for $doc in $alldoc
            return if( some $doc2 in $doc-ill satisfies $doc2 = $doc)
            then ()
            else( $doc )
        )
        return <HealthyDoctors> {
        $ok
        }</HealthyDoctors>
    )

A small sample of XML is this:

<Exam>
    <Outcome>
      <Value>90</Value>
      <MinVal>100</MinVal>
      <MaxVal>150</MaxVal>
    </Outcome>
    <Outcome>
      <Value>15</Value>
      <MinVal>1</MinVal>
      <MaxVal>20</MaxVal>
    </Outcome>
    <Outcome>
      <Value>1</Value>
      <MinVal>1</MinVal>
      <MaxVal>5</MaxVal>
    </Outcome>
    <Doctor>Stack Overflow</Doctor>
   </Exam>
  <Exam>
    <Outcome>
      <Value>190</Value>
      <MinVal>100</MinVal>
      <MaxVal>150</MaxVal>
    </Outcome>
    <Outcome>
      <Value>10</Value>
      <MinVal>1</MinVal>
      <MaxVal>5</MaxVal>
    </Outcome>
    <Doctor>Stack Overflow</Doctor>
   </Exam>
  <Exam>
    <Outcome>
      <Value>120</Value>
      <MinVal>100</MinVal>
      <MaxVal>150</MaxVal>
    </Outcome>
    <Outcome>
      <Value>4</Value>
      <MinVal>1</MinVal>
      <MaxVal>5</MaxVal>
    </Outcome>
    <Doctor>Health</Doctor>
   </Exam>
  <Exam>
    <Outcome>
      <Value>120</Value>
      <MinVal>100</MinVal>
      <MaxVal>150</MaxVal>
    </Outcome>
    <Outcome>
      <Value>10</Value>
      <MinVal>1</MinVal>
      <MaxVal>5</MaxVal>
    </Outcome>
    <Doctor>OneIll</Doctor>
   </Exam>

What I am expecting as a result is:

<HealthyDoctors>
<Doctor>Health</Doctor>
</HealthyDoctors>

Upvotes: 0

Views: 39

Answers (1)

dirkk
dirkk

Reputation: 6218

I am not sure what a "hill patient" is, but guessing from your code I would say it is an Outcome element, where the value is outside the minimal or maximum value.

I am not sure about your whole code, as it is very complicated for the result you want to achieve. At first you try to get all doctors with one hill patient and then it seems you want to get the difference of the whole set an the set of doctors with one hill patient to get your actual result. But in fact it is much simpler to simply get all doctors without a hill patient, without all the re-directions:

declare function local:in-range($x as element(Outcome)) as xs:boolean{
  xs:int($x/Value) >= xs:int($x/MinVal) and xs:int($x/Value) <= xs:int($x/MaxVal)
};

<HealthyDoctors> {
  for $doc in distinct-values(//Exam/Doctor)
  where every $outcome in //Exam[Doctor = $doc]/Outcome satisfies local:in-range($outcome)
  return <Doctor>{ $doc }</Doctor>
}</HealthyDoctors>

So this code basically says give me every doctor where each Outcome element he/she is assigned to satisfies all the range requirements. That your outRange function did not work properly was because the values were compared as strings (i.e. "9" > "10"), so you have to explicitly cast them to be an int.

Also, I renamed your function to in-range, because it is XQuery convention to not use camel case, but a hyphen instead.

Upvotes: 1

Related Questions