Код скрипта:
<?php
require_once "config.php";
ob_start("ob_gzhandler");
// Разбираемся с формой.
$mask = @$_REQUEST['mask'];
$depth = @$_REQUEST['depth'];
$num = min(100, max(10, @intval($_REQUEST['num'])));
$doCount = @$_REQUEST['count'];
if (!isset($_REQUEST['mask'])) $_REQUEST['mask'] = "/";
if (!isset($_REQUEST['depth'])) $_REQUEST['depth'] = 4;
if (!isset($_REQUEST['count'])) $_REQUEST['count'] = true;
if (!isset($_REQUEST['num'])) $_REQUEST['num'] = 100;
// Ограничения.
if (!$depth) $depth = $MAX_NEST;
if ($depth > $MAX_NEST) $depth = $MAX_NEST;
// Нажали кнопку?
if ($mask) {
// Разбиваем путь по "/".
$parts = explode('/', $mask);
if ($parts[count($parts)-1] === '') array_pop($parts);
// Составляем большой SQL-запрос.
$fields = array(); // куски после SELECT (имена полей выборки)
$joins = array(); // JOIN-ы
$wheres = array(); // WHERE-условия
$levels = array(); // инкременты для level
for ($i=0; $i<$depth; $i++) {
// Алиасы для таблицы.
$alias = "t".sprintf("%04d", $i);
$aliasPrev = $i>0? "t".sprintf("%04d", $i-1) : null;
// Список полей для конкретного алиаса.
$fields[] = join(", ", array(
"$alias.id as `$i.id`",
"$alias.parent as `$i.parent`",
"$alias.text as `$i.text`"
));
// LEFT JOIN только для второй и далее таблиц!
if ($aliasPrev)
$joins[] = "LEFT JOIN $TBL_TREE $alias ON ($alias.parent=$aliasPrev.id)";
else
$joins[] = "$TBL_TREE $alias";
// Привязываемся к корню (если поиск от корня).
if (!$aliasPrev && substr($mask, 0,1)=='/') $wheres[] = "$alias.parent=0";
// Условия поиска.
if (isset($parts[$i])) $wheres[] = "$alias.text LIKE '".addslashes($parts[$i])."'";
// Инкремент level-а.
$levels[] = "IF($alias.id IS NOT NULL,1,0)";
}
// Подсчет общего числа результатов.
$t0 = explode(" ", microtime());
if ($doCount) {
$sql = join("\n", array(
"-- rnd: " . time(),
"SELECT",
"\t COUNT(*)",
"FROM",
"\t" . join("\n\t", $joins),
"WHERE",
"\t" . join(" AND \n\t", $wheres),
));
$result = mysql_query($sql) or die(mysql_error().": $sql");
$numRows = mysql_result($result, 0, 0);
} else {
$numRows = '?';
}
$t1 = explode(" ", microtime());
$deltaTimeC = ($t1[0]+$t1[1]) - ($t0[0]+$t0[1]);
// Запрос с LIMIT-ом.
$t0 = explode(" ", microtime());
$sql = join("\n", array(
"-- rnd: " . time(),
"SELECT",
"\t(" . join("+", $levels) . ") as level,",
"\t" . join(",\n\t", $fields),
"FROM",
"\t" . join("\n\t", $joins),
"WHERE",
"\t" . join(" AND \n\t", $wheres),
# "ORDER BY level DESC" . "\n" .
"LIMIT $num"
));
$result = mysql_query($sql) or die(mysql_error().": $sql");
$t1 = explode(" ", microtime());
$deltaTimeR = ($t1[0]+$t1[1]) - ($t0[0]+$t0[1]);
// Чистим результаты запроса.
$nCols = 0;
for ($rows=array(); $row=mysql_fetch_assoc($result); ) {
// Удаляем все поля, кроме level и text.
$r = array();
foreach ($row as $k=>$v)
if (!preg_match('/\.(id|parent)$/', $k) || $k == "0.id")
$r[$k] = $v;
$rows[] = $r;
$nCols = max($nCols, $row['level']);
}
// Удаляем заведомо пустые столбцы.
foreach ($rows as $k=>$v) {
array_splice($rows[$k], $nCols+2); // +2 - для level и id
}
}
?>
<form method="get">
Запрос: <input type="text" name="mask" value="<?=@htmlspecialchars($_REQUEST['mask'])?>"><br>
Глубина выборки: <input type="text" name="depth" value="<?=@htmlspecialchars($_REQUEST['depth'])?>"><br>
Результатов: <input type="text" name="num" value="<?=@htmlspecialchars($_REQUEST['num'])?>"><br>
<input type="checkbox" name="count" <?=@$_REQUEST['count']? 'checked' : ''?>> Подсчитывать число записей<br>
<input type="submit" value="Выполнить">
<br>
</form>
<?if (@$rows) {?>
<hr>
<p>
Найдено записей всего: <b><?=$numRows?></b><br>
Время подсчета числа записей: <b><?=sprintf("%.3f", $deltaTimeC)?></b> с.<br>
Время получения результата: <b><?=sprintf("%.3f", $deltaTimeR)?></b> с.
</p>
<table border="1">
<tr>
<td>#</td>
<?foreach ($rows[0] as $k=>$v) {?>
<td><b><?=$k?></b></td>
<?}?>
</tr>
<?foreach ($rows as $i=>$row) {?>
<tr>
<td><?=$i+1?></td>
<?foreach ($row as $k=>$v) {?>
<td><?=htmlspecialchars($v)?><br></td>
<?}?>
</tr>
<?}?>
</table>
<p>SQL-запрос:</p>
<pre><?=$sql?></pre>
<?}?>
<hr>
<p>Код скрипта:</p>
<?show_source(__FILE__)?>