Often you join multiple table in SQL queries. What about XQuery, how can we perform joins in XQuery? This is what this third post in the XQuery for the SQL programmer series is all about.
A first example Assume you want to get all users with their bids. In SQL one could write,1 2 3 | SELECT u.NAME, b.ITEMNO, b.BID FROM USERS u, BIDS b WHERE u.USERID = b.USERID |
1 2 3 4 5 6 7 8 9 | for $user in collection("USERS")/USERS for $bid in collection("BIDS")/BIDS where $user/USERID = $bid/USERID return <result>{ $user/NAME, $bid/ITEMNO, $bid/BID }</result> |
Note XQuery doesn’t have the concept of result sets, everything is XML. We create a small XML fragment in the return-clause, combining the user’s name with the bid’s information. The example above showed a join between two tables. But just like in SQL, XQuery allows to have more complex joins. Simply add additional for-clauses to your FLWOR expression. The next example is based on the previous, but in addition the bids are joined with items to retrieve the corresponding item description,
1 2 3 4 5 6 7 8 9 10 11 12 | for $user in collection("USERS")/USERS for $bid in collection("BIDS")/BIDS for $item in collection("ITEMS")/ITEMS where $user/USERID = $bid/USERID and $bid/ITEMNO = $item/ITEMNO return <result>{ $user/NAME, $bid/ITEMNO, $bid/BID, $item/DESCRIPTION }</result> |
1 2 3 | SELECT u.NAME, b.ITEMNO, b.BID FROM USERS u LEFT OUTER JOIN BIDS b ON u.USERID = b.USERID |
1 2 3 4 5 6 7 8 9 10 11 12 | for $user in collection("USERS")/USERS return <user>{ $user/NAME, for $bid in collection("BIDS")/BIDS where $user/USERID = $bid/USERID return <bid>{ $bid/ITEMNO, $bid/BID }</bid> }</user> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ... <user> <NAME>Jack Sprat</NAME> <bid> <ITEMNO>1003</ITEMNO> <BID>20</BID> </bid> <bid> <ITEMNO>1007</ITEMNO> <BID>200</BID> </bid> </user> <user> <NAME>Rip Van Winkle</NAME> </user> ... |
Remember the first join example in this post,
1 2 3 4 5 6 7 8 9 | for $user in collection("USERS")/USERS for $bid in collection("BIDS")/BIDS where $user/USERID = $bid/USERID return <result>{ $user/NAME, $bid/ITEMNO, $bid/BID }</result> |
1 2 3 4 5 6 | for $user in collection("USERS")/USERS where fn:empty(collection("BIDS")/BIDS[USERID = $user/USERID]) return <result>{ $user/NAME }</result> |
1 | where fn:empty(collection("BIDS")/BIDS[USERID = $user/USERID]) |
1 2 3 | where fn:empty(for $bid in collection("BIDS")/BIDS where $bid/USERID = $user/USERID return $bid) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | for $user in collection("USERS")/USERS for $bid in collection("BIDS")/BIDS where $user/USERID = $bid/USERID return <result>{ $user/NAME, $bid/ITEMNO, $bid/BID }</result> , for $user in collection("USERS")/USERS where fn:empty(collection("BIDS")/BIDS[USERID = $user/USERID]) return <result>{ $user/NAME }</result> |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <result> <NAME>Jack Sprat</NAME> <ITEMNO>1003</ITEMNO> <BID>20</BID> </result> <result> <NAME>Jack Sprat</NAME> <ITEMNO>1007</ITEMNO> <BID>200</BID> </result> <result> <NAME>Rip Van Winkle</NAME> </result> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | for $result in (for $user in collection("USERS")/USERS for $bid in collection("BIDS")/BIDS where $user/USERID = $bid/USERID return <result>{ $user/NAME, $bid/ITEMNO, $bid/BID }</result> , for $user in collection("USERS")/USERS where fn:empty(collection("BIDS")/BIDS[USERID = $user/USERID]) return <result>{ $user/NAME }</result>) order by $result/NAME return $result |
1 2 3 4 | select (select u.NAME from USERS u where u.USERID = b.USERID), b.ITEMNO, b.BID from BIDS b |
1 2 3 4 5 6 7 8 9 10 | for $bid in collection("BIDS")/BIDS return <bid>{ for $user in collection("USERS")/USERS where $user/USERID = $bid/USERID return $user/NAME, $bid/ITEMNO, $bid/BID }</bid> |
1 2 3 4 5 6 7 | for $bid in collection("BIDS")/BIDS return <bid>{ collection("USERS")/USERS[USERID = $bid/USERID]/NAME, $bid/ITEMNO, $bid/BID }</bid> |
1 2 3 4 5 | SELECT (SELECT u.NAME FROM USERS u WHERE u.USERID = b.USERID), b.ITEMNO, b.BID FROM BIDS b ORDER BY (SELECT u.NAME FROM USERS u WHERE u.USERID = b.USERID)<p/> |
Rather than repeating the expression twice, use a let-clause in XQuery,
1 2 3 4 5 6 7 8 9 | for $bid in collection("BIDS")/BIDS let $name := collection("USERS")/USERS[USERID = $bid/USERID]/NAME order by $name return <bid>{ $name, $bid/ITEMNO, $bid/BID }</bid> |

