To be tested, but here's a way that might work for you :
The trick is to split the formatting and the data gathering. Split your 2 sections into 2 arrays and make then whole once you've recovered everything.
function renderTabs(){
$_db = array(
'host' => MYSQL_HOST,
'user' => MYSQL_USER,
'password' => '',
'database' => DB
);
$_channels = array(
'chan1' => 'db1',
'chan2' => 'db2',
'chan3' =>'db3',
'chan4' => 'db4'
);
$html = '';
$ul = array();
$tabs = array();
$tab = 0;
$conn = new mysqli($_db['host'],$_db['user'],$_db['password'],$_db['database']);
foreach ($_channels as $i => $channel){
$ul[] = '<li><a href="#tabs-'.++$tab.'">'.$channel.'</a></li>';
$results = $conn->query('SELECT * FROM table_test WHERE date BETWEEN (CURDATE() - INTERVAL 7 DAY) AND CURDATE() AND channel = \''.$channel.'\' GROUP BY id ORDER BY total DESC LIMIT 10');
foreach($results as $row){
$tabs[] = '<div id="tabs-'.$tab.'">
<table style="width:100%">
<tr><td>TEST</td>
<td>TEST COL1</td>
<td>TEST COL2</td>
<td>TEST COL3</td>
<td>TEST COL4</td></tr>
<tr><td><a href="'.$row['url'].'">'.$row['title'].'</a></td>
<td>'.$row['data1'].'</td>
<td>'.$row['data2'].'</td>
<td>'.$row['data3'].'</td>
<td>'.$row['data4'].'</td></tr>
</table></div>';
}
}
$html .= '<div id="tabs">';
$html .= "<ul>" . implode($ul). "</ul>";
$html .= implode($tabs);
$html .= '</div>';
return $html;
}