PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/include/SQL/SQL_Query/Query/Join.php

https://github.com/radicaldesigns/amp
PHP | 237 lines | 46 code | 8 blank | 183 comment | 4 complexity | cb7148994c5733cecc622a87817c9ad7 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, BSD-3-Clause, LGPL-2.0, CC-BY-SA-3.0, AGPL-1.0
  1. <?php
  2. /**
  3. *
  4. *
  5. * thanks to those guys who wrote this great book<br/>
  6. * [1] http://www.oldenbourg.de/frame0.htm?http://www.oldenbourg.de/cgi-bin/rotitel?T=25706<br/>
  7. * at least the sql92 spec<br/>
  8. * [2] http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt<br/>
  9. * <br>
  10. * SQL 92 defines a join as this, from [2]
  11. * it needs to be verified if all kinds of joins can be represented by the current strucutre of this class
  12. * <br/>
  13. * <pre>
  14. * &lt;joined table&gt; ::=
  15. * &lt;cross join&gt;
  16. * | &lt;qualified join&gt;
  17. * | &lt;left paren&gt; &lt;joined table&gt; &lt;right paren&gt;
  18. *
  19. * &lt;cross join&gt; ::=
  20. * &lt;table reference&gt; CROSS JOIN &lt;table reference&gt;
  21. *
  22. * &lt;qualified join&gt; ::=
  23. * &lt;table reference&gt; [ NATURAL ] [ &lt;join type&gt; ] JOIN
  24. * &lt;table reference&gt; [ &lt;join specification&gt; ]
  25. *
  26. * &lt;join specification&gt; ::=
  27. * &lt;join condition&gt;
  28. * | &lt;named columns join&gt;
  29. *
  30. * &lt;join condition&gt; ::= ON &lt;search condition&gt;
  31. *
  32. * &lt;named columns join&gt; ::=
  33. * USING &lt;left paren&gt; &lt;join column list&gt; &lt;right paren&gt;
  34. *
  35. * &lt;join type&gt; ::=
  36. * INNER
  37. * | &lt;outer join type&gt; [ OUTER ]
  38. * | UNION
  39. *
  40. * &lt;outer join type&gt; ::=
  41. * LEFT
  42. * | RIGHT
  43. * | FULL
  44. *
  45. * &lt;join column list&gt; ::= &lt;column name list&gt;
  46. * </pre>
  47. *
  48. we also have to be able to build complicated joins like that. the following ones might make
  49. no sense, but are executable. I just added them to show how complicated only the join expression might
  50. become :-)
  51. // simple nested join clauses
  52. SELECT * FROM
  53. uuser u LEFT JOIN
  54. (time t RIGHT JOIN
  55. (time t1 RIGHT JOIN uuser u2 ON t1.user_id=u2.id)
  56. ON t.user_id=u2.id)
  57. ON u.id=t.user_id
  58. // this query is fully outspelled, with all the JOIN-clauses and no commas in the join
  59. select * from
  60. uuser u
  61. INNER JOIN time t ON u.id=t.user_id
  62. INNER JOIN time t1 ON t1.id=u.id
  63. // this has join clauses and a comma seperation
  64. select * from
  65. uuser u INNER JOIN time t ON u.id=t.user_id,
  66. uuser u1 INNER JOIN time t1 ON t1.id=u1.id
  67. // this assigns an alias to a join clause
  68. SELECT * FROM
  69. uuser u LEFT JOIN
  70. (time t RIGHT JOIN uuser u1 ON t.user_id=u1.id) j1 // here we give an alias to a join expression
  71. ON u.id=j1.user_id
  72. // building this would be done like this
  73. // 1. build this: time t RIGHT JOIN uuser u1 ON t.user_id=u1.id
  74. $join1 = new SQL_Query_Join();
  75. $join1->addRightJoin(array('t'=>'time','u1'=>'uuser'),new SQL_Condition('t.user_id','=','u1.id'));
  76. // 2. build the actual join
  77. // uuser u LEFT JOIN (<$join1>) j1 ON u.id=j1.user_id
  78. $join = new SQL_Query_Join();
  79. $join->addLeftJoin(array('u'=>'uuser','j1'=>&$join1)),
  80. new SQL_Condition('u.id','=','j1.user_id'));
  81. or even more complex ....
  82. SELECT * FROM
  83. uuser u LEFT JOIN
  84. (time t RIGHT JOIN
  85. (time t1 RIGHT JOIN uuser u2 ON t1.user_id=u2.id)
  86. ON t.user_id=u2.id)
  87. ON u.id=t.user_id,
  88. time,
  89. uuser u3 LEFT JOIN time t3 ON t3.user_id=u3.id,
  90. uuser u4 LEFT JOIN time t4 ON t4.user_id=u4.id
  91. to build it we would call the following:
  92. // we build it inside out
  93. // 1. build this: time t1 RIGHT JOIN uuser u2 ON t1.user_id=u2.id
  94. $join1 = new SQL_Query_Join();
  95. $join1->addRightJoin(array('t1'=>'time','u2'=>'uuser'),new SQL_Condition('t1.user_id','=','u2.id'));
  96. // 2. (time t RIGHT JOIN (<$join1>) ON t.user_id=u2.id)
  97. $join2 = new SQL_Query_Join();
  98. $join2->addRightJoin(array('t'=>'time',$join1),new SQL_Condition('t.user_id','=','u2.id'));
  99. // 3. uuser u LEFT JOIN (<$join2>) ON u.id=t.user_id
  100. $join3 = new SQL_Query_Join();
  101. $join3->addRightJoin(array('u'=>'uuser',$join2),new SQL_Condition('u.id','=','t.user_id'));
  102. // 4. time,
  103. // uuser u3 LEFT JOIN time t3 ON t3.user_id=u3.id,
  104. // uuser u4 LEFT JOIN time t4 ON t4.user_id=u4.id
  105. $join3->addJoin('time');
  106. $join3->addLeftJoin(array('u3'=>'uuser','t3'=>'time'),new SQL_Condition('t3.user_id','=','u3.id'));
  107. $join3->addLeftJoin(array('u4'=>'uuser','t4'=>'time'),new SQL_Condition('t4.user_id','=','u4.id'));
  108. * @package SQL_Query
  109. * @author Wolfram Kriesing <wk@visionp.de>
  110. */
  111. class SQL_Query_Join
  112. {
  113. /**
  114. * @var array stores the join this class works on
  115. */
  116. var $_joins = array();
  117. /**
  118. * Set the table(s) and the condition to the join.
  119. *
  120. * Example usage:
  121. * <code>
  122. * $cond = new SQL_Condition('time.user_id','=','user.id');
  123. * // rendered SQL: INNER JOIN time ON <$cond>
  124. * $join->addJoin('time',$cond);
  125. * // rendered SQL: time INNER JOIN time ON <$cond>
  126. * $join->addJoin(array('time','user'),$cond);
  127. * // rendered SQL: time t INNER JOIN user ON <$cond>, use the alias t
  128. * $join->addJoin(array('t'=>'time','user'),$cond);
  129. * // rendered SQL: time t INNER JOIN user u ON <$cond>
  130. * $join->addJoin(array('t'=>'time','u'=>'user'),$cond);
  131. * // rendered SQL: time t INNER JOIN (<$joinX>) j ON <$cond>
  132. * // where <$joinX> is this: table1 INNER JOIN table2 table1.id=table2.xid
  133. * $joinX = new SQL_Query_Join();
  134. * $joinX->addJoin(array('table1','table2'),new SQL_Condition('table1.id','=','table2.xid'))
  135. * $join->addJoin(array('t'=>'time','j'=>&$joinX),$cond);
  136. * </code>
  137. *
  138. * @param mixed either a string, for one table
  139. * or an array which contains two tables.
  140. * @param object the condition that applies to this join
  141. * @param string the type of join, either 'inner', 'right', 'left'
  142. */
  143. function addJoin( $tables, $condition, $type='inner')
  144. {
  145. settype($tables,'array');
  146. $addTables = array();
  147. foreach ($tables as $alias=>$table) {
  148. if (!is_string($alias)) {
  149. $addTables[] = array($table);
  150. } else {
  151. $addTables[] = array($table,$alias);
  152. }
  153. }
  154. $addJoin = array('tables'=>$addTables,'condition'=>&$condition,'type'=>$type);
  155. /*FIXXXME do the checks properly
  156. // dont add exactly the same join twice, i am pretty sure this is not a wanted behaviour ...
  157. if (!in_array($addJoin,$this->_joins)) {
  158. $this->_joins[] = $addJoin;
  159. }
  160. */
  161. $this->_joins[] = $addJoin;
  162. }
  163. /**
  164. *
  165. *
  166. *
  167. */
  168. function addRightJoin( $tables, $condition=null)
  169. {
  170. $this->addJoin($tables,$condition,'right');
  171. }
  172. /**
  173. *
  174. *
  175. *
  176. */
  177. function addLeftJoin( $tables, $condition=null)
  178. {
  179. $this->addJoin($tables,$condition,'left');
  180. }
  181. /**
  182. * This method returns all the tables and their aliases if given.
  183. * It returns all the tables that are given in this join, no matter how deep they
  184. * are nested.
  185. *
  186. * @return array this array contains all the tables in the order as added to this join.
  187. * If a table has an alias, then the element is an array itself, where key [0] contains
  188. * the table name and [1] the alias name.
  189. */
  190. function getTables()
  191. {
  192. $tables = array();
  193. foreach ($this->_joins as $aJoin) {
  194. //FIXXXME test this properly for all the possible cases ...
  195. foreach ($aJoin['tables'] as $aTable) {
  196. if (is_a($aTable[0],__CLASS__)) {
  197. $tables = array_merge($tables,$aTable[0]->getTables());
  198. } else {
  199. $tables[] = $aTable;
  200. }
  201. }
  202. }
  203. return $tables;
  204. }
  205. /**
  206. * Return the internal join structure as it is.
  207. *
  208. */
  209. function getJoins()
  210. {
  211. return $this->_joins;
  212. }
  213. }
  214. ?>