How to do natural join in XQuery
-
21-12-2019 - |
Question
My goal with this clause is to list the employees that live in San Fran but work in Silicon Valley. Right now my clause is working to find out which employees live in San Fran, but I am not sure how to join the two lists of EmployeeList and WorkInfo in order to take the employees that live in San Fran and find out which of these names also work in Silicon Valley.
Here's what I have so far in my clause:
for $x in /EmpDatabase/PersonList/Contents/Person
where $x/City='San Fran'
order by $x/Name
return $x/Name
And here's my XML data file:
<EmpDatabase>
<PersonList Type="Employee">
<Title Value="Employee List"/>
<Contents>
<Person>
<Name>Susan L. Anderson</Name>
<City>San Fran</City>
<Gender>F</Gender>
</Person>
<Person>
<Name>Dan L. Brady</Name>
<City>Sacramento</City>
<Gender>M</Gender>
</Person>
<Person>
<Name>Peter K. Chen</Name>
<City>San Fran</City>
<Gender>M</Gender>
</Person>
</Contents>
</PersonList>
<CompanyList Type="Company">
<Title Value="Company List"/>
<Contents>
<Company>
<Name>Google</Name>
<City>Silicon Valley</City>
</Company>
<Company>
<Name>Riot</Name>
<City>LA</City>
</Company>
</Contents>
</CompanyList>
<InfoList Type="Works">
<Title Value="Works List"/>
<Contents>
<Works>
<Name>Susan L. Anderson</Name>
<Company>Google</Company>
<Salary>48000</Salary>
</Works>
<Works>
<Name>Dan L. Brady</Name>
<Company>Google</Company>
<Salary>42000</Salary>
</Works>
<Works>
<Name>Peter K. Chen</Name>
<Company>Riot</Company>
<Salary>53000</Salary>
</Works>
</Contents>
</InfoList>
</EmpDatabase>
Is natural join the right way to go about this? How is natural join written in XQuery? Do I need to write a separate clause in a different file to list the employees that work in Silicon Valley and then somehow join the results of both clauses?
Any help is greatly appreciated!
Solution
I renamed $x
to $person
to give it a more meaningful name.
You could formulate an implicit join, but it's easier to formulate what you're actually looking for:
for $person in /EmpDatabase/PersonList/Contents/Person
(: retrieve company $person is working for :)
let $works := /EmpDatabase/InfoList/Contents/Works[Name=$person/Name]
where $person/City='San Fran'
(: See if the company has a department in Silicon Valley :)
where /EmpDatabase/CompanyList/Contents/Company[Name=$works/Company and City='Silicon Valley']
order by $person/Name
return $person/Name
If you prefer a "classic" join, just use multiple for
loops:
for $person in /EmpDatabase/PersonList/Contents/Person
for $works in /EmpDatabase/InfoList/Contents/Works
for $company in /EmpDatabase/CompanyList/Contents/Company
where $person/City='San Fran'
where $person/Name=$works/Name
where $works/Company=$company/Name
where $company/City='Silicon Valley'
order by $person/Name
return $person/Name