У меня есть данные из MySQL, показывающие все организации, которые есть у клиента, со всеми деталями занятости в каждой организации. Я хочу указать имя каждой организации только один раз, то есть в одной ячейке (диапазон строк) и всех сотрудников в этой организации против этого имени, например:
Org1 Emp1 Name, Emp1 Phone, Emp1 Address
Emp2 Name, Emp2 Phone, Emp2 Address
Org2 Emp1 Name, Emp1 Phone, Emp1 Address
Emp2 Name, Emp2 Phone, Emp2 Address
Как мне отобразить эти данные, потому что количество сотрудников для каждой организации не известно заранее, поэтому я не устанавливаю значение rowspan. Точно так же, как мне начать ссору для другой организации? Надо ли писать два запроса?
Огромное спасибо.






Классический.
Решение: отображать имя, только если оно отличается от предыдущего. Можно даже не заморачиваться с диапазоном строк (оставьте пустую ячейку).
$currentOrg = '';
while ($row = mysql_fetch_object($query)) {
if ($row->org != $currentOrg) {
echo "$row->org".
}
$currentorg = $row->org;
}
Не самый красивый, но такой простой.
// Get the data
$data = mysql_query('SELECT org, emp_name, emp_phone, emp_address FROM x');
// Store it all in a 2D array, keyed by org
$rows = array();
while ($row = mysql_fetch_assoc($data))
{
// Initialise each org to an empty array (not really needed in PHP but I prefer it)
if (empty($rows[$row['org']]))
$rows[$row['org']] = array();
$rows[$row['org']][] = $row;
}
// Print it out
foreach ($rows as $org => $employees)
{
print('<tr><td rowspan = "' . count($employees) . '">' . htmlentities($org) . '</td>');
foreach ($employees as $i => $employee)
{
// If $i == 0, we've already printed the <tr> before the loop
if ($i)
print('<tr>');
print('<td>......</td></tr>');
}
}
Чтобы сделать правильный rowspan, вам нужно знать номер заранее.
Это оставляет вам:
Лично я бы выбрал второй метод. Серверы БД довольно эффективны с подсчетом строк, это, вероятно, будет намного быстрее, когда есть много строк для отображения.
Я бы не рекомендовал второй метод, если вы используете движок INNODB.
Было бы проще (но менее эффективно) сделать запрос для каждой организации (плюс один запрос, чтобы узнать, сколько организаций предположительно существует).
Лучше всего заранее просмотреть массив в цикле. Например:
$sql = $mysqli->query('SELECT * FROM `organisation_members` ORDER BY `organisation` DESC');
if (!$sql || $sql->num_rows) {
// No data
} else {
$data = array();
while ($row = $sql->fetch_assoc()) {}
if (!array_key_exists($row['organisation'], $data)) {
$data[$row['organisation']] = array();
}
$data[$row['organisation']][]['name'] = $row['name'];
// ...
}
$sql->close();
echo '<table>';
foreach ($data as $org => $people) {
$people_in_org = count($data[$org]) - 1;
$counter = 0;
echo '<tr>';
echo '<td rowspan = "' . $people_in_org + 1 . '">' . $org . '</td>';
while ($counter < $people_in_org) {
if (counter > 0) {
echo '<tr>';
}
echo '<td>' . $people[$counter]['name'] . '</td>';
// etc
echo '</tr>';
}
}
echo '</table>';
}
Чтобы сохранить память, вы можете перебирать набор результатов, пока org буферизует строки, когда org изменяется, распечатайте текущий пакет и начните буферизацию следующего пакета.
Как насчет использования пакета HTML_Table груши, как в следующем примере, мне также нравится версия Jrgns ROLLUP
<?php
require_once "HTML/Table.php";
$table = new HTML_Table(array('border'=>'1'));
$bo=array(
array('6','a2','a3','a4'),
array('1','b2','b3','b4'),
array('1','c2','c3','c4') ,
array('2','c2','c3','c4') ,
array('2','c2','c3','c4') ,
array('4','c2','c3','c4') );
foreach ($bo as $r => $borow)
$table->addRow($borow);
$rsFirst=0;
$rsLen=0;
foreach ($bo as $r => $borow) {
if ($r!=0 and $borow[0]!=$prevrow[0] ) {
//jump in values
$table->setCellAttributes ( $rsFirst,0, array('rowspan'=>$rsLen));
$rsFirst=$r;
$rsLen=0;
}
$prevrow=$borow;
$rsLen++;
if ($r==sizeof($bo) - 1) {
$table->setCellAttributes ( $rsFirst,0, array('rowspan'=>$rsLen));
}
}
echo $table->toHTML();
?>
сервас, бурль
Я проголосовал за ваш ответ за то, что до сих пор был единственным человеком, который использовал htmlentities (), чтобы избежать вывода. Я бы, наверное, использовал sprintf () здесь вместо конкатенации.