SQL olap
parent
311ce6b288
commit
e9ab8df823
|
@ -6,6 +6,7 @@
|
|||
define ('IN_CONFIG', true);
|
||||
|
||||
setlocale(LC_ALL, 'ru_RU.UTF-8');
|
||||
setlocale(LC_NUMERIC, 'C');
|
||||
mb_internal_encoding('utf-8');
|
||||
|
||||
include_once 'loconfig.php';
|
||||
|
|
151
olap.php
151
olap.php
|
@ -17,19 +17,24 @@ class OLAP
|
|||
static $sources;
|
||||
static $current_srcid, $current_src;
|
||||
static $functions = array(
|
||||
'year' => array('name' => 'Год', 'time' => true),
|
||||
'month' => array('name' => 'Месяц', 'time' => true),
|
||||
'day' => array('name' => 'Дата', 'time' => true),
|
||||
'weekday' => array('name' => 'День недели', 'time' => true),
|
||||
'week' => array('name' => '№ недели', 'time' => true),
|
||||
'year' => array('name' => 'Год', 'time_format' => 'Y', 'sql' => 'SUBSTR($,1,4)'),
|
||||
'month' => array('name' => 'Месяц', 'time_format' => 'Y-m', 'sql' => 'SUBSTR($,1,7)'),
|
||||
'day' => array('name' => 'Дата', 'time_format' => 'Y-m-d', 'sql' => 'SUBSTR($,1,10)'),
|
||||
'weekday' => array('name' => 'День недели', 'time_format' => 'N', 'sql' => 'WEEKDAY($)'),
|
||||
'week' => array('name' => '№ недели', 'time_format' => 'W', 'sql' => 'WEEK($)'),
|
||||
'hour' => array('name' => 'Час', 'time_format' => 'H', 'sql' => 'HOUR($)'),
|
||||
'minute' => array('name' => 'Минута', 'time_format' => 'H:i', 'sql' => 'DATE_FORMAT($, "%k:%i")'),
|
||||
'second' => array('name' => 'Секунда', 'time_format' => 'H:i:s', 'sql' => 'DATE_FORMAT($, "%k:%i:%s")'),
|
||||
);
|
||||
static $aggregates = array(
|
||||
'count' => array('name' => 'Количество', 'sql' => 'COUNT($)'),
|
||||
'sum' => array('name' => 'Сумма', 'sql' => 'SUM($)'),
|
||||
'avg' => array('name' => 'Среднее', 'sql' => 'AVG($)'),
|
||||
'min' => array('name' => 'Минимум', 'sql' => 'MIN($)'),
|
||||
'max' => array('name' => 'Максимум', 'sql' => 'MAX($)'),
|
||||
'stddev' => array('name' => 'Дисперсия', 'sql' => 'STDDEV($)'),
|
||||
'distinct' => array('name' => 'Значения', 'cell_only' => true),
|
||||
'count' => array('name' => 'Количество'),
|
||||
'sum' => array('name' => 'Сумма'),
|
||||
'avg' => array('name' => 'Среднее'),
|
||||
'min' => array('name' => 'Минимум'),
|
||||
'max' => array('name' => 'Максимум'),
|
||||
'n_uniq' => array('name' => 'Количество уникальных', 'sql' => 'COUNT(DISTINCT $)'),
|
||||
);
|
||||
static $specf = array('v_field', 'v_func', 'h_field', 'h_func', 'cell_field', 'cell_aggr', 'cell_func', 'v_sort_dir', 'v_sort_field', 'v_sort_aggr', 'v_sort_func', 'h_sort_dir', 'h_sort_field', 'h_sort_aggr', 'h_sort_func');
|
||||
|
||||
|
@ -109,75 +114,69 @@ class OLAP
|
|||
exit;
|
||||
}
|
||||
|
||||
$result = mysql_select(self::$current_src['tables'], self::$current_src['fields'], array_merge(self::$current_src['where'], $where), self::$current_src['options'], MS_RESULT);
|
||||
|
||||
foreach(self::$specf as $x)
|
||||
$$x = $request[$x];
|
||||
|
||||
$group = array();
|
||||
$hkeys = array();
|
||||
$v_v = '';
|
||||
$v_h = '';
|
||||
$fetch = self::$current_src['fetch_row'] ? 'mysql_fetch_row' : 'mysql_fetch_assoc';
|
||||
|
||||
$code = 'while($r = '.$fetch.'($result)) {';
|
||||
$fields = array();
|
||||
$options = array('GROUP BY' => array());
|
||||
if ($v_field !== '')
|
||||
{
|
||||
$code .= '$v_v = ';
|
||||
if ($v_func !== '')
|
||||
$code .= 'self::transform_'.$v_func.'(&$r, $v_field);';
|
||||
else
|
||||
$code .= '$r[$v_field];';
|
||||
$v_sql = self::sql_trans_field($v_field, $v_func);
|
||||
$fields[] = $v_sql.' v_field';
|
||||
$options['GROUP BY'][] = $v_sql;
|
||||
}
|
||||
if ($h_field !== '')
|
||||
{
|
||||
$code .= '$v_h = ';
|
||||
if ($h_func !== '')
|
||||
$code .= 'self::transform_'.$h_func.'(&$r, $h_field);';
|
||||
else
|
||||
$code .= '$r[$h_field];';
|
||||
$h_sql = self::sql_trans_field($h_field, $h_func);
|
||||
$fields[] = $h_sql.' h_field';
|
||||
$options['GROUP BY'][] = $h_sql;
|
||||
}
|
||||
$code .= '$v_c = ';
|
||||
if ($cell_func !== '')
|
||||
$code .= 'self::transform_'.$cell_func.'(&$r, $cell_field);';
|
||||
$cell_sql = self::sql_trans_field($cell_field, $cell_func);
|
||||
if (self::$aggregates[$cell_aggr]['sql'])
|
||||
$fields[] = str_replace('$', $cell_sql, self::$aggregates[$cell_aggr]['sql']).' cell_field';
|
||||
else
|
||||
$code .= '$r[$cell_field];';
|
||||
$code .= '$hkeys[$v_h] = 1;';
|
||||
$code .= 'self::aggr_update_'.$cell_aggr.'(&$group[$v_v][$v_h], &$v_c);';
|
||||
if ($v_field !== '' && $v_sort_aggr !== '' && $v_sort_field !== '')
|
||||
{
|
||||
$code .= '$v_vs = ';
|
||||
if ($v_sort_func !== '')
|
||||
$code .= 'self::transform_'.$v_sort_func.'(&$r, $v_sort_field);';
|
||||
else
|
||||
$code .= '$r[$v_sort_field];';
|
||||
$code .= 'self::aggr_update_'.$v_sort_aggr.'(&$vsort[$v_v], &$v_vs);';
|
||||
$do_aggr = true;
|
||||
$fields[] = $cell_sql.' cell_field';
|
||||
$options['GROUP BY'][] = $cell_sql;
|
||||
}
|
||||
if ($h_field !== '' && $h_sort_aggr !== '' && $h_sort_field !== '')
|
||||
|
||||
$result = mysql_select(self::$current_src['tables'], $fields, array_merge(self::$current_src['where'], $where), $options, MS_RESULT);
|
||||
|
||||
$group = array();
|
||||
$hkeys = array();
|
||||
while ($r = mysql_fetch_assoc($result))
|
||||
{
|
||||
$code .= '$v_hs = ';
|
||||
if ($h_sort_func !== '')
|
||||
$code .= 'self::transform_'.$h_sort_func.'(&$r, $h_sort_field);';
|
||||
if ($do_aggr)
|
||||
call_user_func_array('self::aggr_update_'.$cell_aggr, array(&$group[$r['v_field']][$r['h_field']], &$r['cell_field']));
|
||||
else
|
||||
$code .= '$r[$h_sort_field];';
|
||||
$code .= 'self::aggr_update_'.$h_sort_aggr.'(&$vsort[$v_h], &$v_hs);';
|
||||
$group[$r['v_field']][$r['h_field']] = $r['cell_field'];
|
||||
$hkeys[$r['h_field']] = 1;
|
||||
}
|
||||
$code .= '}';
|
||||
|
||||
eval($code);
|
||||
|
||||
if (is_callable("OLAP::aggr_finish_$cell_aggr"))
|
||||
if ($do_aggr && is_callable('self::aggr_finish_'.$cell_aggr))
|
||||
foreach ($group as $i => &$r)
|
||||
foreach ($r as $j => &$c)
|
||||
call_user_func_array("OLAP::aggr_finish_$cell_aggr", array(&$c));
|
||||
call_user_func_array('self::aggr_finish_'.$cell_aggr, array(&$c));
|
||||
|
||||
if ($v_field !== '' && $v_sort_aggr !== '' && $v_sort_field !== '' && is_callable("OLAP::aggr_finish_$v_sort_aggr"))
|
||||
foreach ($vsort as $v => &$c)
|
||||
call_user_func_array("OLAP::aggr_finish_$v_sort_aggr", array(&$c));
|
||||
if ($v_field !== '' && $v_sort_aggr !== '' && $v_sort_field !== '')
|
||||
{
|
||||
$fields = array($v_sql.' v_field');
|
||||
$vs_sql = self::sql_trans_field($v_sort_field, $v_sort_func);
|
||||
$fields[] = str_replace('$', $vs_sql, self::$aggregates[$v_sort_aggr]['sql']).' v_sort_field';
|
||||
$result = mysql_select(self::$current_src['tables'], $fields, array_merge(self::$current_src['where'], $where), array('GROUP BY' => $v_sql), MS_RESULT);
|
||||
while ($r = mysql_fetch_row($result))
|
||||
$vsort[$r[0]] = $r[1];
|
||||
}
|
||||
|
||||
if ($h_field !== '' && $h_sort_aggr !== '' && $h_sort_field !== '' && is_callable("OLAP::aggr_finish_$h_sort_aggr"))
|
||||
foreach ($hsort as $v => &$c)
|
||||
call_user_func_array("OLAP::aggr_finish_$h_sort_aggr", array(&$c));
|
||||
if ($h_field !== '' && $h_sort_aggr !== '' && $h_sort_field !== '')
|
||||
{
|
||||
$fields = array($h_sql.' v_field');
|
||||
$hs_sql = self::sql_trans_field($h_sort_field, $h_sort_func);
|
||||
$fields[] = str_replace('$', $hs_sql, self::$aggregates[$h_sort_aggr]['sql']).' h_sort_field';
|
||||
$result = mysql_select(self::$current_src['tables'], $fields, array_merge(self::$current_src['where'], $where), array('GROUP BY' => $h_sql), MS_RESULT);
|
||||
while ($r = mysql_fetch_row($result))
|
||||
$hsort[$r[0]] = $r[1];
|
||||
}
|
||||
|
||||
$hkeys = array_keys($hkeys);
|
||||
self::do_sort($hkeys, $hsort, $h_sort_dir);
|
||||
|
@ -214,6 +213,18 @@ class OLAP
|
|||
print $template->parse('admin_olap.tpl');
|
||||
}
|
||||
|
||||
static function sql_trans_field($field, $func)
|
||||
{
|
||||
$sql = $field;
|
||||
if (self::$current_src['fielddescs'][$field]['is_time'] &&
|
||||
self::$current_src['fielddescs'][$field]['format'] == TS_UNIX &&
|
||||
(!self::$functions[$func] || self::$functions[$func]['time_format']))
|
||||
$sql = "FROM_UNIXTIME($sql)";
|
||||
if (self::$functions[$func])
|
||||
$sql = str_replace('$', $sql, self::$functions[$func]['sql']);
|
||||
return $sql;
|
||||
}
|
||||
|
||||
static function do_sort(&$values, &$sortvalues, &$sort_dir)
|
||||
{
|
||||
$fn = 'sort';
|
||||
|
@ -241,18 +252,22 @@ class OLAP
|
|||
}
|
||||
|
||||
static $is_html_format = true;
|
||||
static $decimal = '%.3f';
|
||||
static function field_format($field, $func, $aggr, $value)
|
||||
{
|
||||
$o = &self::$current_src['fielddescs'][$field]['options_hash'];
|
||||
if ($aggr == 'distinct')
|
||||
{
|
||||
$r = '';
|
||||
foreach($value as $k => $n)
|
||||
$r .= self::field_format($field, $func, false, $k).': '.$n.(self::$is_html_format ? "<br />" : "")."\n";
|
||||
if ($value)
|
||||
foreach($value as $k => $n)
|
||||
$r .= self::field_format($field, $func, false, $k).': '.$n.(self::$is_html_format ? "<br />" : "")."\n";
|
||||
return $r;
|
||||
}
|
||||
elseif ($o && $o[$value])
|
||||
return $o[$value];
|
||||
elseif (preg_match('/^-?\d+\.\d+$/s', $value))
|
||||
return sprintf(self::$decimal, $value);
|
||||
$fn = self::$is_html_format ? 'htmlspecialchars' : 'addslashes';
|
||||
return $fn($value);
|
||||
}
|
||||
|
@ -272,17 +287,5 @@ class OLAP
|
|||
|
||||
/* Агрегатные функции и преобразования */
|
||||
|
||||
static function transform_year(&$row, $field) { return self::o_tsformat('Y', $row, $field); }
|
||||
static function transform_month(&$row, $field) { return self::o_tsformat('Y-m', $row, $field); }
|
||||
static function transform_day(&$row, $field) { return self::o_tsformat('Y-m-d', $row, $field); }
|
||||
static function transform_weekday(&$row, $field) { return self::o_tsformat('N', $row, $field); }
|
||||
static function transform_week(&$row, $field) { return self::o_tsformat('W', $row, $field); }
|
||||
|
||||
static function aggr_update_count(&$n, &$v) { $n++; }
|
||||
static function aggr_update_sum(&$sum, &$v) { $sum += $v; }
|
||||
static function aggr_update_avg(&$avg, &$v) { $avg['n']++; $avg['s'] += $v; }
|
||||
static function aggr_finish_avg(&$avg) { $avg = $avg['s']/$avg['n']; }
|
||||
static function aggr_update_min(&$min, &$v) { if ($min > $v) $min = $v; }
|
||||
static function aggr_update_max(&$max, &$v) { if ($max < $v) $max = $v; }
|
||||
static function aggr_update_distinct(&$d, &$v) { $d[$v]++; }
|
||||
}
|
||||
|
|
|
@ -9,19 +9,17 @@ OLAP::$sources = array(
|
|||
'where' => array(),
|
||||
'fetch_row' => true,
|
||||
'fielddescs' => array(
|
||||
#'ts'
|
||||
0 => array(
|
||||
'ts' => array(
|
||||
'name' => 'Время',
|
||||
'le_ge' => true,
|
||||
'is_time' => true,
|
||||
'format' => TS_UNIX,
|
||||
'dbname' => 'ts',
|
||||
),
|
||||
#'tag'
|
||||
1 => array(
|
||||
'tag' => array(
|
||||
'name' => 'Тег',
|
||||
'dbname' => 'tag',
|
||||
'options' => array_merge(array('id' => 0, 'name' => '*'), mysql_select('tags', 'id, name', array('type' => 0))),
|
||||
'options' => mysql_select('tags', 'id, name', array('type' => 0)),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue