mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-24 02:58:43 +02:00
N°1161 - Add functions, order by and limits to DBSearch::MakeGroupByQuery()
SVN:trunk[5350]
This commit is contained in:
@@ -1434,7 +1434,7 @@ class DBObjectSearch extends DBSearch
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null)
|
||||
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null)
|
||||
{
|
||||
// Hide objects that are not visible to the current user
|
||||
//
|
||||
@@ -1517,7 +1517,15 @@ class DBObjectSearch extends DBSearch
|
||||
$sRawId .= 'g:'.$sAlias.'!'.$oExpr->Render();
|
||||
}
|
||||
}
|
||||
if (!is_null($aSelectExpr))
|
||||
{
|
||||
foreach($aSelectExpr as $sAlias => $oExpr)
|
||||
{
|
||||
$sRawId .= 'se:'.$sAlias.'!'.$oExpr->Render();
|
||||
}
|
||||
}
|
||||
$aContextData['aGroupByExpr'] = $aGroupByExpr;
|
||||
$aContextData['aSelectExpr'] = $aSelectExpr;
|
||||
$sRawId .= $bGetCount;
|
||||
$aContextData['bGetCount'] = $bGetCount;
|
||||
if (is_array($aSelectedClasses))
|
||||
@@ -1542,6 +1550,7 @@ class DBObjectSearch extends DBSearch
|
||||
|
||||
// Query caching
|
||||
//
|
||||
$sOqlAPCCacheId = null;
|
||||
if (self::$m_bQueryCacheEnabled)
|
||||
{
|
||||
// Warning: using directly the query string as the key to the hash array can FAIL if the string
|
||||
@@ -1581,7 +1590,7 @@ class DBObjectSearch extends DBSearch
|
||||
if (!isset($oSQLQuery))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oSQLQuery = $oSearch->BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr, $aSelectedClasses);
|
||||
$oSQLQuery = $oSearch->BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr, $aSelectedClasses, $aSelectExpr);
|
||||
$oKPI->ComputeStats('BuildSQLQueryStruct', $sOqlQuery);
|
||||
|
||||
if (self::$m_bQueryCacheEnabled)
|
||||
@@ -1601,16 +1610,17 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aAttToLoad
|
||||
* @param $bGetCount
|
||||
* @param $aModifierProperties
|
||||
* @param null $aGroupByExpr
|
||||
* @param null $aSelectedClasses
|
||||
* @param array $aAttToLoad
|
||||
* @param bool $bGetCount
|
||||
* @param array $aModifierProperties
|
||||
* @param array $aGroupByExpr
|
||||
* @param array $aSelectedClasses
|
||||
* @param array $aSelectExpr
|
||||
* @return null|SQLObjectQuery
|
||||
*/
|
||||
protected function BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null)
|
||||
protected function BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null)
|
||||
{
|
||||
$oBuild = new QueryBuilderContext($this, $aModifierProperties, $aGroupByExpr, $aSelectedClasses);
|
||||
$oBuild = new QueryBuilderContext($this, $aModifierProperties, $aGroupByExpr, $aSelectedClasses, $aSelectExpr);
|
||||
|
||||
$oSQLQuery = $this->MakeSQLObjectQuery($oBuild, $aAttToLoad, array());
|
||||
$oSQLQuery->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
@@ -1624,6 +1634,17 @@ class DBObjectSearch extends DBSearch
|
||||
{
|
||||
$oSQLQuery->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
}
|
||||
if ($aSelectExpr)
|
||||
{
|
||||
// Get the fields corresponding to the select expressions
|
||||
foreach($oBuild->m_oQBExpressions->GetSelect() as $sAlias => $oExpr)
|
||||
{
|
||||
if (key_exists($sAlias, $aSelectExpr))
|
||||
{
|
||||
$oSQLQuery->AddSelect($sAlias, $oExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aMandatoryTables = null;
|
||||
if (self::$m_bOptimizeQueries)
|
||||
|
||||
@@ -429,8 +429,53 @@ abstract class DBSearch
|
||||
protected static $m_aQueryStructCache = array();
|
||||
|
||||
|
||||
public function MakeGroupByQuery($aArgs, $aGroupByExpr, $bExcludeNullValues = false)
|
||||
/** Generate a Group By SQL request from a search
|
||||
* @param array $aArgs
|
||||
* @param array $aGroupByExpr array('alias' => Expression)
|
||||
* @param bool $bExcludeNullValues
|
||||
* @param array $aSelectExpr array('alias' => Expression) Additional expressions added to the request
|
||||
* @param array $aOrderBy array('alias' => bool) true = ASC false = DESC
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
* @return string SQL query generated
|
||||
* @throws Exception
|
||||
*/
|
||||
public function MakeGroupByQuery($aArgs, $aGroupByExpr, $bExcludeNullValues = false, $aSelectExpr = array(), $aOrderBy = array(), $iLimitCount = 0, $iLimitStart = 0)
|
||||
{
|
||||
// Sanity check
|
||||
foreach($aGroupByExpr as $sAlias => $oExpr)
|
||||
{
|
||||
if (!($oExpr instanceof Expression))
|
||||
{
|
||||
throw new CoreException("Wrong parameter for 'Group By' for [$sAlias] (an array('alias' => Expression) is awaited)");
|
||||
}
|
||||
}
|
||||
foreach($aSelectExpr as $sAlias => $oExpr)
|
||||
{
|
||||
if (array_key_exists($sAlias, $aGroupByExpr))
|
||||
{
|
||||
throw new CoreException("Alias collision between 'Group By' and 'Select Expressions' [$sAlias]");
|
||||
}
|
||||
if (!($oExpr instanceof Expression))
|
||||
{
|
||||
throw new CoreException("Wrong parameter for 'Select Expressions' for [$sAlias] (an array('alias' => Expression) is awaited)");
|
||||
}
|
||||
}
|
||||
foreach($aOrderBy as $sAlias => $bAscending)
|
||||
{
|
||||
if (!array_key_exists($sAlias, $aGroupByExpr) && !array_key_exists($sAlias, $aSelectExpr) && ($sAlias != '_itop_count_'))
|
||||
{
|
||||
$aAllowedAliases = array_keys($aSelectExpr);
|
||||
$aAllowedAliases = array_merge($aAllowedAliases, array_keys($aGroupByExpr));
|
||||
$aAllowedAliases[] = '_itop_count_';
|
||||
throw new CoreException("Wrong alias [$sAlias] for 'Order By'. Allowed values are: ", null, implode(", ", $aAllowedAliases));
|
||||
}
|
||||
if (!is_bool($bAscending))
|
||||
{
|
||||
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value for '$sAlias''");
|
||||
}
|
||||
}
|
||||
|
||||
if ($bExcludeNullValues)
|
||||
{
|
||||
// Null values are not handled (though external keys set to 0 are allowed)
|
||||
@@ -448,15 +493,15 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
$aAttToLoad = array();
|
||||
$oSQLQuery = $oQueryFilter->GetSQLQuery(array(), $aArgs, $aAttToLoad, null, 0, 0, false, $aGroupByExpr);
|
||||
$oSQLQuery = $oQueryFilter->GetSQLQuery(array(), $aArgs, $aAttToLoad, null, 0, 0, false, $aGroupByExpr, $aSelectExpr);
|
||||
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams());
|
||||
try
|
||||
{
|
||||
$bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries;
|
||||
$sRes = $oSQLQuery->RenderGroupBy($aScalarArgs, $bBeautifulSQL);
|
||||
$sRes = $oSQLQuery->RenderGroupBy($aScalarArgs, $bBeautifulSQL, $aOrderBy, $iLimitCount, $iLimitStart);
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
catch (Exception $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $this->ToOQL());
|
||||
@@ -563,9 +608,9 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
|
||||
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null)
|
||||
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
|
||||
{
|
||||
$oSQLQuery = $this->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr);
|
||||
$oSQLQuery = $this->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, null, $aSelectExpr);
|
||||
$oSQLQuery->SetSourceOQL($this->ToOQL());
|
||||
|
||||
// Join to an additional table, if required...
|
||||
@@ -587,7 +632,7 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
public abstract function GetSQLQueryStructure(
|
||||
$aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null
|
||||
$aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -143,7 +143,7 @@ class DBUnionSearch extends DBSearch
|
||||
|
||||
/**
|
||||
* Limited to the selected classes
|
||||
*/
|
||||
*/
|
||||
public function GetClassName($sAlias)
|
||||
{
|
||||
if (array_key_exists($sAlias, $this->aSelectedClasses))
|
||||
@@ -474,15 +474,17 @@ class DBUnionSearch extends DBSearch
|
||||
throw new Exception('MakeUpdateQuery is not implemented for the unions!');
|
||||
}
|
||||
|
||||
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null)
|
||||
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null)
|
||||
{
|
||||
if (count($this->aSearches) == 1)
|
||||
{
|
||||
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr);
|
||||
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, $aSelectExpr);
|
||||
}
|
||||
|
||||
$aSQLQueries = array();
|
||||
$aAliases = array_keys($this->aSelectedClasses);
|
||||
$aQueryAttToLoad = null;
|
||||
$aUnionQuerySelectExpr = array();
|
||||
foreach ($this->aSearches as $iSearch => $oSearch)
|
||||
{
|
||||
$aSearchAliases = array_keys($oSearch->GetSelectedClasses());
|
||||
@@ -544,7 +546,43 @@ class DBUnionSearch extends DBSearch
|
||||
$aQueryGroupByExpr[$sExpressionAlias] = $oExpression->Translate($aTranslationData, false, false);
|
||||
}
|
||||
}
|
||||
$oSubQuery = $oSearch->GetSQLQueryStructure($aQueryAttToLoad, false, $aQueryGroupByExpr, $aSearchSelectedClasses);
|
||||
|
||||
if (is_null($aSelectExpr))
|
||||
{
|
||||
$aQuerySelectExpr = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQuerySelectExpr = array();
|
||||
$aTranslationData = array();
|
||||
$aQueryColumns = array_keys($oSearch->GetSelectedClasses());
|
||||
foreach($aAliases as $iColumn => $sAlias)
|
||||
{
|
||||
$sQueryAlias = $aQueryColumns[$iColumn];
|
||||
$aTranslationData[$sAlias]['*'] = $sQueryAlias;
|
||||
}
|
||||
foreach($aSelectExpr as $sExpressionAlias => $oExpression)
|
||||
{
|
||||
$oExpression->Browse(function ($oNode) use (&$aQuerySelectExpr, &$aTranslationData)
|
||||
{
|
||||
if ($oNode instanceof FieldExpression)
|
||||
{
|
||||
$sAlias = $oNode->GetParent()."__".$oNode->GetName();
|
||||
if (!key_exists($sAlias, $aQuerySelectExpr))
|
||||
{
|
||||
$aQuerySelectExpr[$sAlias] = $oNode->Translate($aTranslationData, false, false);
|
||||
}
|
||||
$aTranslationData[$oNode->GetParent()][$oNode->GetName()] = new FieldExpression($sAlias);
|
||||
}
|
||||
});
|
||||
// Only done for the first select as aliases are named after the first query
|
||||
if (!array_key_exists($sExpressionAlias, $aUnionQuerySelectExpr))
|
||||
{
|
||||
$aUnionQuerySelectExpr[$sExpressionAlias] = $oExpression->Translate($aTranslationData, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
$oSubQuery = $oSearch->GetSQLQueryStructure($aQueryAttToLoad, false, $aQueryGroupByExpr, $aSearchSelectedClasses, $aQuerySelectExpr);
|
||||
if (count($aSearchAliases) > 1)
|
||||
{
|
||||
// Necessary to make sure that selected columns will match throughout all the queries
|
||||
@@ -554,7 +592,7 @@ class DBUnionSearch extends DBSearch
|
||||
$aSQLQueries[] = $oSubQuery;
|
||||
}
|
||||
|
||||
$oSQLQuery = new SQLUnionQuery($aSQLQueries, $aGroupByExpr);
|
||||
$oSQLQuery = new SQLUnionQuery($aSQLQueries, $aGroupByExpr, $aUnionQuerySelectExpr);
|
||||
//MyHelpers::var_dump_html($oSQLQuery, true);
|
||||
//MyHelpers::var_dump_html($oSQLQuery->RenderSelect(), true);
|
||||
if (self::$m_bDebugQuery) $oSQLQuery->DisplayHtml();
|
||||
|
||||
@@ -70,7 +70,7 @@ abstract class Expression
|
||||
{
|
||||
return base64_encode($this->Render());
|
||||
}
|
||||
|
||||
|
||||
static public function unserialize($sValue)
|
||||
{
|
||||
return self::FromOQL(base64_decode($sValue));
|
||||
@@ -1373,7 +1373,7 @@ class QueryBuilderExpressions
|
||||
*/
|
||||
protected $m_aClassIds;
|
||||
|
||||
public function __construct(DBObjectSearch $oSearch, $aGroupByExpr = null)
|
||||
public function __construct(DBObjectSearch $oSearch, $aGroupByExpr = null, $aSelectExpr = null)
|
||||
{
|
||||
$this->m_oConditionExpr = $oSearch->GetCriteria();
|
||||
if (!$oSearch->GetShowObsoleteData())
|
||||
@@ -1387,7 +1387,7 @@ class QueryBuilderExpressions
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->m_aSelectExpr = array();
|
||||
$this->m_aSelectExpr = is_null($aSelectExpr) ? array() : $aSelectExpr;
|
||||
$this->m_aGroupByExpr = $aGroupByExpr;
|
||||
$this->m_aJoinFields = array();
|
||||
|
||||
@@ -1448,8 +1448,10 @@ class QueryBuilderExpressions
|
||||
|
||||
/**
|
||||
* Get tables representing the queried objects
|
||||
* Could be further optimized: when the first join is an outer join, then the rest can be omitted
|
||||
*/
|
||||
* Could be further optimized: when the first join is an outer join, then the rest can be omitted
|
||||
* @param array $aTables
|
||||
* @return array
|
||||
*/
|
||||
public function GetMandatoryTables(&$aTables = null)
|
||||
{
|
||||
if (is_null($aTables)) $aTables = array();
|
||||
@@ -1458,6 +1460,8 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$oExpression->CollectUsedParents($aTables);
|
||||
}
|
||||
|
||||
return $aTables;
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
@@ -1498,7 +1502,6 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
|
||||
foreach($this->m_aClassIds as $sClass => $oExpression)
|
||||
{
|
||||
$this->m_aClassIds[$sClass] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
|
||||
@@ -34,10 +34,10 @@ class QueryBuilderContext
|
||||
|
||||
public $m_oQBExpressions;
|
||||
|
||||
public function __construct($oFilter, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null)
|
||||
public function __construct($oFilter, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null)
|
||||
{
|
||||
$this->m_oRootFilter = $oFilter;
|
||||
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter, $aGroupByExpr);
|
||||
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter, $aGroupByExpr, $aSelectExpr);
|
||||
|
||||
$this->m_aClassAliases = $oFilter->GetJoinedClasses();
|
||||
$this->m_aTableAliases = array();
|
||||
|
||||
@@ -293,11 +293,12 @@ class SQLObjectQuery extends SQLQuery
|
||||
* Needed for the unions
|
||||
* @param $aOrderBy
|
||||
* @return string
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function RenderOrderByClause($aOrderBy)
|
||||
{
|
||||
$this->PrepareRendering();
|
||||
$sOrderBy = self::ClauseOrderBy($aOrderBy);
|
||||
$sOrderBy = self::ClauseOrderBy($aOrderBy, $this->__aFields);
|
||||
return $sOrderBy;
|
||||
}
|
||||
|
||||
@@ -357,8 +358,8 @@ class SQLObjectQuery extends SQLQuery
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelect = self::ClauseSelect($this->__aFields);
|
||||
$sOrderBy = self::ClauseOrderBy($aOrderBy);
|
||||
$sSelect = self::ClauseSelect($this->__aFields, $sLineSep);
|
||||
$sOrderBy = self::ClauseOrderBy($aOrderBy, $this->__aFields);
|
||||
if (!empty($sOrderBy))
|
||||
{
|
||||
$sOrderBy = "ORDER BY $sOrderBy$sLineSep";
|
||||
@@ -381,21 +382,42 @@ class SQLObjectQuery extends SQLQuery
|
||||
/**
|
||||
* @param array $aArgs
|
||||
* @param bool $bBeautifulQuery
|
||||
* @param array $aOrderBy
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
* @return string
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function RenderGroupBy($aArgs = array(), $bBeautifulQuery = false)
|
||||
public function RenderGroupBy($aArgs = array(), $bBeautifulQuery = false, $aOrderBy = array(), $iLimitCount = 0, $iLimitStart = 0)
|
||||
{
|
||||
$this->m_bBeautifulQuery = $bBeautifulQuery;
|
||||
$sLineSep = $this->m_bBeautifulQuery ? "\n" : '';
|
||||
$sIndent = $this->m_bBeautifulQuery ? " " : null;
|
||||
|
||||
$this->PrepareRendering();
|
||||
|
||||
$sSelect = self::ClauseSelect($this->__aFields);
|
||||
$sFrom = self::ClauseFrom($this->__aFrom, $sIndent);
|
||||
$sWhere = self::ClauseWhere($this->m_oConditionExpr, $aArgs);
|
||||
$sGroupBy = self::ClauseGroupBy($this->__aGroupBy);
|
||||
$sSQL = "SELECT $sSelect,$sLineSep COUNT(*) AS _itop_count_$sLineSep FROM $sFrom$sLineSep WHERE $sWhere$sLineSep GROUP BY $sGroupBy";
|
||||
$sOrderBy = self::ClauseOrderBy($aOrderBy, $this->__aFields);
|
||||
if (!empty($sGroupBy))
|
||||
{
|
||||
$sGroupBy = "GROUP BY $sGroupBy$sLineSep";
|
||||
}
|
||||
if (!empty($sOrderBy))
|
||||
{
|
||||
$sOrderBy = "ORDER BY $sOrderBy$sLineSep";
|
||||
}
|
||||
if ($iLimitCount > 0)
|
||||
{
|
||||
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLimit = '';
|
||||
}
|
||||
$sSQL = "SELECT $sSelect,$sLineSep COUNT(*) AS _itop_count_$sLineSep FROM $sFrom$sLineSep WHERE $sWhere$sLineSep $sGroupBy $sOrderBy$sLineSep $sLimit";
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,18 +69,18 @@ abstract class SQLQuery
|
||||
abstract public function RenderDelete($aArgs = array());
|
||||
abstract public function RenderUpdate($aArgs = array());
|
||||
abstract public function RenderSelect($aOrderBy = array(), $aArgs = array(), $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false, $bBeautifulQuery = false);
|
||||
abstract public function RenderGroupBy($aArgs = array(), $bBeautifulQuery = false);
|
||||
abstract public function RenderGroupBy($aArgs = array(), $bBeautifulQuery = false, $aOrderBy = array(), $iLimitCount = 0, $iLimitStart = 0);
|
||||
|
||||
abstract public function OptimizeJoins($aUsedTables, $bTopCall = true);
|
||||
|
||||
protected static function ClauseSelect($aFields)
|
||||
protected static function ClauseSelect($aFields, $sLineSep = '')
|
||||
{
|
||||
$aSelect = array();
|
||||
foreach ($aFields as $sFieldAlias => $sSQLExpr)
|
||||
{
|
||||
$aSelect[] = "$sSQLExpr AS $sFieldAlias";
|
||||
}
|
||||
$sSelect = implode(', ', $aSelect);
|
||||
$sSelect = implode(",$sLineSep ", $aSelect);
|
||||
return $sSelect;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,13 @@ abstract class SQLQuery
|
||||
}
|
||||
}
|
||||
|
||||
protected static function ClauseOrderBy($aOrderBy)
|
||||
/**
|
||||
* @param array $aOrderBy
|
||||
* @param array $aExistingFields
|
||||
* @return string
|
||||
* @throws CoreException
|
||||
*/
|
||||
protected static function ClauseOrderBy($aOrderBy, $aExistingFields)
|
||||
{
|
||||
$aOrderBySpec = array();
|
||||
foreach($aOrderBy as $sFieldAlias => $bAscending)
|
||||
|
||||
@@ -38,8 +38,9 @@ class SQLUnionQuery extends SQLQuery
|
||||
{
|
||||
protected $aQueries;
|
||||
protected $aGroupBy;
|
||||
protected $aSelectExpr;
|
||||
|
||||
public function __construct($aQueries, $aGroupBy)
|
||||
public function __construct($aQueries, $aGroupBy, $aSelectExpr = array())
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@@ -49,6 +50,7 @@ class SQLUnionQuery extends SQLQuery
|
||||
$this->aQueries[] = $oSQLQuery->DeepClone();
|
||||
}
|
||||
$this->aGroupBy = $aGroupBy;
|
||||
$this->aSelectExpr = $aSelectExpr;
|
||||
}
|
||||
|
||||
public function DisplayHtml()
|
||||
@@ -129,7 +131,17 @@ class SQLUnionQuery extends SQLQuery
|
||||
}
|
||||
|
||||
// Interface, build the SQL query
|
||||
public function RenderGroupBy($aArgs = array(), $bBeautifulQuery = false)
|
||||
|
||||
/**
|
||||
* @param array $aArgs
|
||||
* @param bool $bBeautifulQuery
|
||||
* @param array $aOrderBy
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
* @return string
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function RenderGroupBy($aArgs = array(), $bBeautifulQuery = false, $aOrderBy = array(), $iLimitCount = 0, $iLimitStart = 0)
|
||||
{
|
||||
$this->m_bBeautifulQuery = $bBeautifulQuery;
|
||||
$sLineSep = $this->m_bBeautifulQuery ? "\n" : '';
|
||||
@@ -143,15 +155,41 @@ class SQLUnionQuery extends SQLQuery
|
||||
$sSelects = '('.implode(")$sLineSep UNION$sLineSep(", $aSelects).')';
|
||||
$sFrom = "($sLineSep$sSelects$sLineSep) as __selects__";
|
||||
|
||||
$aAliases = array();
|
||||
$aSelectAliases = array();
|
||||
$aGroupAliases = array();
|
||||
foreach ($this->aGroupBy as $sGroupAlias => $trash)
|
||||
{
|
||||
$aAliases[] = "`$sGroupAlias`";
|
||||
$aSelectAliases[$sGroupAlias] = "`$sGroupAlias`";
|
||||
$aGroupAliases[] = "`$sGroupAlias`";
|
||||
}
|
||||
foreach($this->aSelectExpr as $sSelectAlias => $oExpr)
|
||||
{
|
||||
$aSelectAliases[$sSelectAlias] = $oExpr->Render()." AS `$sSelectAlias`";
|
||||
}
|
||||
$sSelect = implode(', ', $aAliases);
|
||||
$sGroupBy = implode(', ', $aAliases);
|
||||
|
||||
$sSQL = "SELECT $sSelect,$sLineSep COUNT(*) AS _itop_count_$sLineSep FROM $sFrom$sLineSep GROUP BY $sGroupBy";
|
||||
$sSelect = implode(",$sLineSep ", $aSelectAliases);
|
||||
$sGroupBy = implode(', ', $aGroupAliases);
|
||||
|
||||
$sOrderBy = self::ClauseOrderBy($aOrderBy, $aSelectAliases);
|
||||
if (!empty($sGroupBy))
|
||||
{
|
||||
$sGroupBy = "GROUP BY $sGroupBy$sLineSep";
|
||||
}
|
||||
if (!empty($sOrderBy))
|
||||
{
|
||||
$sOrderBy = "ORDER BY $sOrderBy$sLineSep";
|
||||
}
|
||||
if ($iLimitCount > 0)
|
||||
{
|
||||
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLimit = '';
|
||||
}
|
||||
|
||||
|
||||
$sSQL = "SELECT $sSelect,$sLineSep COUNT(*) AS _itop_count_$sLineSep FROM $sFrom$sLineSep $sGroupBy $sOrderBy$sLineSep $sLimit";
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user