我在MySQL数据库中有以下数据:
Autonum ID Name MetaValue
1 1 Rose Drinker
2 1 Rose Nice Person
3 1 Rose Runner
4 2 Gary Player
5 2 Gary Funny
我现在正在使用PHP,但是我使用C#,Java和其他语言多次遇到过这个问题。
现在我过去和现在的目标是以下列格式显示数据:
<table>
<thead>
<th>Name</th>
<th>MetaValue1</th>
</thead>
<tbody>
<tr>
<td>Rose</td>
<td>
<ul>
<li>Drinker</li>
<li>Nice Person</li>
<li>Runner</li>
</ul>
</td>
</tr>
<tr>
<td>Gary</td>
<td>
<ul>
<li>Player</li>
<li>Funny</li>
</td>
</tr>
</tbody>
</table>
我之前通过创建一个代表我的SQL表的类来解决这个问题。
然后我创建了一个Dictionary
来保存EmployeeId
和班级。
Dictionary<string,MyTable> MyData = new <string,MyTable>();
Table MyMetaData = new Table();
MyMetaData SomeMetaData=getMetaValueList();//imagine a web service that does that
MyData.add(EmployeeId,SomeMetaData);
我正在跳过步骤,但我希望你明白我的观点。我可能只需要关键字来称呼这类问题。实现这一目标的首选方法是什么?
答案 0 :(得分:11)
出于某种原因,我不喜欢SQL解决方案。您要求数据库引擎加入字符串,然后使用PHP将其拆分。这就像重复的工作。另一个缺点是如果metavalue
包含分隔符,那该怎么办。
我的代码只演示了如何在PHP中轻松地将数据与二维数组进行分组,并且可以决定从数据库中检索遗留mysql_ *或PDO的数据的方法。
// get result
$result = mysql_query("SELECT autonum,id,name,metavalue FROM table");
// loop through each row
while ($row = mysql_fetch_assoc($result)) {
$table[$row['name']][] = $row['metavalue'];
}
// print it out
print_r($table);
无需将整个结果集临时存储到数组中。您可以通过首先按数据排序数据来直接迭代,以便对数据进行分组并跟踪状态。
然而,我喜欢这种风格有两个原因,这是个人偏好(这不是必须做的解决方案):
通常,每个人都希望将逻辑和表达分开。将数据存储在数组中可以轻松传递给模板引擎。我更喜欢使用PHP模板引擎,因为它易于实现并且运行速度很快。
我宁愿换取轻微的性能速度和内存使用量以提高可读性和可维护性。该算法简短易懂。如果性能是您的首要任务,您可以始终使用缓存,例如存储在文件中,存储在memcached中,或将计算结果存储在数据库中。
是的,我们正在对来自不同方面的数据进行分组,但您认为metavalue
不包含分隔符(在您的代码中为|)。通过选择metavalue
几乎无法使用的分隔符,可以轻松修复它。无论如何,你的解决方案几乎在所有情况下都能正常工作,因为@jvelez显示的metavalue
将永远不会包含字符|。
答案 1 :(得分:9)
问题不在于php / java / c#代码,而是在SQL结尾。
SELECT ID AS id,
Autonum AS num,
Name AS name,
GROUP_CONCAT
(
ORDER BY MetaValue DESC SEPARATOR '|'
) AS list
FROM Things
GROUP BY Things.ID
通过这种方式,您可以获得name
值的列表,以及该项目的所有关联MetaValues,您只需将list
拆分为'|'
。
在PHP中,您使用explode()
,使用String.Split()
在C#中执行此操作,我认为您可以找到与任何语言类似的内容。
HTML的生成变得非常简单。
这是一个PHP示例(使用PDO连接API):
$statement = $pdo->query( $sql );
if ( $statement->execute() )
{
$data = $statement->fetchAll(PDO::FETCH_ASSOC);
foeach ( $data as $row )
{
echo '<tr><td>' , $row['name'] , '</td>';
echo '<td><ul><li>' , str_replace( '|', '</li><li>' , $row['list']) ;
echo '</li></ul></td></tr>';
}
}
这会从您的示例生成<tbody>
内容。
答案 2 :(得分:3)
请查看您的数据,对其进行排序和订购:
Autonum ID Name MetaValue
1 1 Rose Drinker
2 1 Rose Nice Person
3 1 Rose Runner
4 2 Gary Player
5 2 Gary Funny
所以你能做的就是通过输出来解决这个问题:
您需要做的就是预测下一个元素以查看更改。这意味着您提前迭代(预先计算的迭代)或者您执行缓存迭代(例如,在PHP中使用CachingIterator
)。
如果您随后跟踪状态,则可以对每个条目说明:
实际上它甚至更简单,这里是基于数组的行迭代示例(Demo):
$rows = array(
array(1, 1, 'Rose', 'Drinker'),
array(2, 1, 'Rose', 'Nice Person'),
array(3, 1, 'Rose', 'Runner'),
array(4, 2, 'Gary', 'Player'),
array(5, 2, 'Gary', 'Funny'),
);
echo "<table>\n <thead>\n <th>Name</th>\n <th>MetaValue1</th>\n </thead>\n <tbody>\n";
$events = new Events();
$last = array(2 => null);
foreach($rows as $row)
{
if ($last[2] !== $row[2]) {
$events->newRow($row[2]);
}
$events->newItem($row[3]);
$last = $row;
}
$events->closeRow();
echo " </tbody>\n</table>";
解决问题的代码不多,因为问题本身只是数据中的一小部分状态。
这里描述的事件可以通过创建自己的迭代器来反转,该迭代器可以传递给支持迭代器的模板系统,例如:树枝或小胡子。一个完整的例子显示在我以前的答案和博客文章中:
答案 3 :(得分:2)
这是一个解决方案,它类似于@ invisal,就我们基于表的属性创建数组以将结果分组在一起的方式。
<?php
$mysqli = new mysqli("localhost", "uname", "pword", "wordpress");
if ($mysqli->connect_errno) {
die("Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error);
}
$res = $mysqli->query("SELECT * FROM wp_postmeta");
// array that will hold the final results
$results = array();
// while we have more rows
while ($row = $res->fetch_assoc()) {
// check to see if we already have this ID
if (!array_key_exists($row['ID'], $results)) {
// if not create a new index for it in $results, which holds an array
$results[$row['ID']] = array();
}
// create new stdClass object that holds the row data
$obj = new stdClass;
$obj->Name = $row['Name'];
$obj->MetaValue = $row['MetaValue'];
// append this data to our results array based on the ID
$results[$row['ID']][] = $obj;
}
?>
<table>
<thead>
<th>Name</th>
<th>MetaValue</th>
</thead>
<tbody>
<?php foreach($results as $id => $values): ?>
<tr>
<td style="vertical-align: top"><?php echo $values[0]->Name ?></td>
<td>
<ul>
<?php foreach($values as $value): ?>
<li><?php echo $value->MetaValue ?></li>
<?php endforeach; ?>
</ul>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
这似乎会产生您想要的结果。希望有所帮助。
答案 4 :(得分:2)
你问过如何调用这种类型的问题:它叫做分组。确实有一种可能性是在GROUP BY
子句的帮助下在SQL中解决它(但是不同的SQL引擎对这些有不同的支持,特别是当涉及要分组的更复杂的数据聚合时)。
在C#中,由于LINQ,基本解决方案是单线程,只需使用GroupBy
扩展方法:
var data = new [] {
new { RowId = 1, EmpId = 1, Name = "Rose", Value = "Drinker" },
new { RowId = 2, EmpId = 1, Name = "Rose", Value = "Runner" },
new { RowId = 3, EmpId = 2, Name = "Gary", Value = "Player" },
};
var grouping = data.GroupBy(row => row.Name);
var sb = new StringBuilder();
foreach (var grp in grouping) {
sb.AppendFormat("<tr><td>{0}</td>\n", grp.Key);
sb.AppendLine(" <td><ul>");
foreach (var element in grp) {
sb.AppendFormat(" <li>{0}</li>\n", element.Value);
}
sb.AppendLine(" </ul></td>\n</tr>");
}
Console.WriteLine(sb.ToString());
GroupBy
背后的基本思想只是某种关联数组或字典,其中包含作为键的分组属性以及与该键关联的所有行的列表。例如(使用具有上述定义的变量数据):
var map = new Dictionary<Tuple<int, string>, List<object>>();
foreach (var row in data) {
var key = Tuple.Create(row.EmpId, row.Name);
if (!map.ContainsKey(key))
map.Add(key, new List<object>());
map[key].Add(row);
}
上面的代码片段在概念上与drew010和invisal的基于PHP的答案相同(它们使用二维PHP数组,概念上与上面的列表字典相同)。我试图尽可能明确地使用这些步骤,而不是使用C#的太多特殊功能(例如,在真正的程序中,你应该倾向于使用它自己的适当类来代替复杂的键而不是简单的元组),所以上面snippet应该可以轻松移植到Java和其他语言。
正如您在此处的所有示例中所看到的,在对数据进行分组后,HTML生成始终是相同的(两个嵌套循环)。
答案 5 :(得分:2)
我会以不同的方式解决这个问题。现在,您遇到了问题,因为您的数据库架构未规范化。相反,我会从改变架构开始。现在,你有这个:
CREATE TABLE foo {
`autonum` INT(12) NOT NULL AUTO_INCREMENT,
`id` INT(12) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`metaValue` VARCHAR(255) NOT NULL,
PRIMARY KEY(autonum)
)
相反,我会把它分成两个表:
CREATE TABLE user {
`id` INT(12) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY(id)
)
CREATE TABLE user_meta {
`user_id` INT(12) NOT NULL,
`value` VARCHAR(255) NOT NULL
)
忽略这个看起来像EAV表的事实(由于OP的命名,meta只是错误命名),应该清楚这是如何更容易的。那么让我们看看你的记录,并建立表格:
#User
id | name
1 | Rose
2 | Gary
#User Meta
user_id | value
1 | drinker
1 | Nice Person
1 | Runner
2 | Player
2 | Funny
现在我们有了数据,让我们来看看我们如何提取数据。让我们假设我们总是希望打印出所有用户(限制它会很简单,但为了清楚起见,我们现在可以完成所有操作)。所以,我会在这里围绕每个表设置一个简单的类,将数据缓存到单个查询中。
class User implements IteratorAggregate {
protected $data = array();
public function __construct() {
$query = mysql_query("SELECT id, name FROM user");
while ($row = mysql_fetch_assoc($query)) {
$this->data[$row['id']] => $row['name'];
}
}
public function getIterator() {
return new ArrayObject($this->data);
}
}
class User_Meta {
protected $data = array();
public function __construct() {
$query = mysql_query("SELECT user_id, value FROM user_meta");
while ($row = mysql_fetch_assoc($query)) {
if (empty($this->data[$row['user_id']])) {
$this->data[$row['user_id']] = array();
}
$this->data[$row['user_id']][] = $row['value'];
}
}
public function getDataForUserId($id) {
return empty($this->data[$id]) ? array() : $this->data[$id];
}
}
现在,构建输出变得微不足道了:
$users = new User;
$meta = new User_Meta;
echo "<table>
<thead>
<th>Name</th>
<th>MetaValue1</th>
</thead>
<tbody>";
foreach ($users as $id => $name) {
echo "<tr>
<td>".htmlspecialchars($name)."</td>
<td>
<ul>";
foreach ($meta->getDataForUserId($id) as $metaValue) {
echo "<li>" . htmlspecialchars($metaValue) . "</li>";
}
echo " </ul>
</td>
</tr>";
}
echo "</tbody></table>";
现在,尽管如此,我会亲自实现它,使用一流的业务对象和数据映射器来处理所有事情。
我确实在这里犯了几个重罪,但我是为了简单而做的。以下是我的不同之处:
但它确实取决于应用程序的确切要求。没有一个(或两个)正确的方法来做到这一点。每种可能的方式都有利有弊。学会权衡权衡,以便您可以根据自己的要求选择合适的权衡......
答案 6 :(得分:1)
我有一个类似的表一次,我最终使用一些SQL将数据作为单独的行返回。我修改了我的对象以使用你的sql并编写了一个简单的函数,它将按照你在问题中使用的格式输出表中的数据。
我使用的主要查询聚合函数是MySQL GROUP_CONCAT。这类似于implode()
函数。默认分隔符是逗号,因此如果元数据中有逗号,可以通过在列名后面的括号内添加SEPARATOR 'yourSeparator'
将其更改为其他标记。您还可以使用列名前面的distinct
来仅选择group_concat中的不同行。
我已将表头部分放在try
语句中,因此如果没有任何结果,则不会显示半生成的表。
<?php
class myUser
{
public $ID;
public $name;
public $metas;
}
class myTables
{
public $SQL="
select
ID,
name,
GROUP_CONCAT(metavalue) as metas
FROM
table1
GROUP BY
ID,
name;";
public function outputTable()
{
$hostname="mysql:host=localhost;dbname=test";
$username="testdb";
$password="testdbpassword";
try{
echo "
<table>
<thead>
<th>Name</th>
<th>MetaValue</th>
</thead>
<tbody>
";
$dbh = new PDO($hostname, $username, $password);
$stmt = $dbh->query($this->SQL);
$obj = $stmt->setFetchMode(PDO::FETCH_INTO, new myUser);
foreach($stmt as $myUser)
{
echo "
<tr><td>".$myUser->name."</td><td><ul>";
$metas=explode(",", $myUser->metas);
for($i=0;$i<count($metas);$i++)
{
echo "<li>".$metas[$i]."</li>";
}
echo "</ul></td></tr>";
}
unset($obj);
unset($stmt);
unset($dbh);
echo "
</tbody>
</table>
";
}
catch(PDOException $e){
echo 'Error : '.$e->getMessage();
exit();
}
}
}
$myPage= new myTables();
$myPage->outputTable();
?>
示例输出:
<table>
<thead>
<th>Name</th>
<th>MetaValue1</th>
</thead>
<tbody>
<tr><td>Rose</td><td><ul><li>Drinker</li><li>Nice Person</li><li>Runner</li></ul></td></tr>
<tr><td>Gary</td><td><ul><li>Player</li><li>Funny</li></ul></td></tr>
</tbody>
</table>
我从您的查询中删除了Autonum
,因为它会破坏聚合函数。如果你确实需要它,你必须以类似的方式聚合它。 group_concat
函数将跳过空字段,因此您需要巧妙地使用它们,否则您的autonum ID将与您的结果不匹配。我在coalesce()
函数中使用简单的group_concat
来完成此操作。
为了适应这些额外的比特,我稍微重写了这个对象。这应该做你需要的一切,我已经把我的调试笔记设置为私有变量isDebug
,我设置为false,但是设置为true会在对象运行时提供额外的信息。这将帮助您进行调试,因为我假设您的源数据实际上要复杂得多。
<?php
class myUser
{
public $ID;
public $name;
public $metaDesc;
public $metaNum;
public $metaDescs;
public $metaNums;
}
// Basic User stored here. One Object per Row is created.
class myTables
{
private $isDebug=false; // Change this to true to get all validation messages;
private $hostname="mysql:host=localhost;dbname=test";
private $username="testdb";
private $password="testdbpassword";
private $myUsers=array();
private $curUser = myUser;
private $userCount=0;
private $SQL="
select
ID,
name,
GROUP_CONCAT(coalesce(metavalue,'null')) as metaDesc,
group_concat(autonum) as metaNum
FROM
table1
GROUP BY
ID,
name;";
public function getuserData()
{
$dbh = new PDO($this->hostname, $this->username, $this->password);
$stmt = $dbh->query($this->SQL);
$obj = $stmt->setFetchMode(PDO::FETCH_INTO, new myUser);
$userCount=0;
foreach($stmt as $myUser)
{
$this->myUsers[$userCount]=new myUser;
$this->myUsers[$userCount]->ID=$myUser->ID;
$this->myUsers[$userCount]->name=$myUser->name;
$this->myUsers[$userCount]->metaDesc=$myUser->metaDesc;
$this->myUsers[$userCount]->metaNum=$myUser->metaNum;
$userCount++;
}
$this->userCount=$userCount;
if($this->isDebug){echo "There are ".$this->userCount." users found.<br>";}
unset($obj);
unset($stmt);
unset($dbh);
}
// Pulls the data from the database and populates the this->object.
public function outputTable()
{
echo "
<table>
<thead>
<th>Name</th>
<th>MetaValue</th>
</thead>
<tbody>
";
for($i=0; $i<$this->userCount; $i++)
{
if($this->isDebug){echo "Running main cycle. There are ".$this->userCount." elements.";}
$this->myUsers[$i]->metaDescs=explode(',', $this->myUsers[$i]->metaDesc);
$this->myUsers[$i]->metaNums=explode(',', $this->myUsers[$i]->metaNum);
if($this->isDebug){echo "This user has ".(count($this->myUsers[$i]->metaDescs))." segments<br>";}
if($this->isDebug){echo "My first segment is ".($this->myUsers[$i]->metaDesc)."<br>";}
echo "<tr><td>".$this->myUsers[$i]->name."</td><td><ul>";
for($j=0;$j<count($this->myUsers[$i]->metaDescs);$j++)
{
echo "<li>ID: ".$this->myUsers[$i]->metaNums[$j]." - ".$this->myUsers[$i]->metaDescs[$j]."</li>";
}
echo "</ul></td></tr>";
}
echo "
</tbody>
</table>
";
}
// Outputs the data held in the object into the table as required.
}
$myPage= new myTables();
$myPage->getUserData();
$myPage->outputTable();
?>
输出现在看起来像这样:
<table>
<thead>
<th>Name</th>
<th>MetaValue</th>
</thead>
<tbody>
<tr><td>Rose</td><td><ul><li>ID: 1 - Drinker</li><li>ID: 2 - Nice Person</li><li>ID: 3 - Runner</li></ul></td></tr>
<tr><td>Gary</td><td><ul><li>ID: 4 - Player</li><li>ID: 5 - Funny</li><li>ID: 6 - null</li><li>ID: 7 - Smelly</li></ul></td></tr>
</tbody>
</table>
Name MetaValue
Rose
ID: 1 - Drinker
ID: 2 - Nice Person
ID: 3 - Runner
Gary
ID: 4 - Player
ID: 5 - Funny
ID: 6 - null
ID: 7 - Smelly
答案 7 :(得分:1)
我建议你到数据库中的create a function
create function get_meta(@autonum int)
returns varchar(500)
as
declare @meta varchar(500)='<ul>';
select @meta=@meta+'<li>'+MetaValue+'</li>' from mytable where Autonum=@autonum
return @meta+'</ul>';
并在PHP端使用一个干净的语句。
select id,autonum,name, get_meta(autonum) as meta_output from mytable
然后你需要做
echo $row["meta_output"];
与任何其他专栏一样。这就是我要用的。
答案 8 :(得分:1)
This would print exactly what you need within the <tbody> tags :
<?php
$result = mysql_query("SELECT name, metavalue FROM table");
$previous_name = ""; //Variable to keep track of previous name value in array()
print '<table><thead><th>Name</th><th>Metavalue</th></thead><tbody>'; //print the static table header
while ($row = mysql_fetch_array($result)) {
$name = $row['name'];
$meta_value = $row['metavalue'];
if (($previous_name != $name) && ($previous_name !="")) {
//If $name has changed, close tags, reset $previous_name
print '</ul></td></tr>';
$previous_name = "";
}
if ($previous_name == "") {
//New value of $name, open tags, set $name to $previous_name
print '<tr><td>'.$name.'</td><td><ul>';
$previous_name = $name;
}
if ($previous_name == $name) {
//print contents of $meta_value if $name is the same
print '<li>'.$meta_value.'</li>';
}
}
//Once there are no more values in the array, close the static table header
print '</tbody></table>'; //close the static table header
?>
答案 9 :(得分:1)
以下是关于这个问题的第二种方法,like with the first one,我仍然喜欢用输出来解决这个问题,例如:
<table>
<?php foreach($users as $name => $columns) : ?>
<tr>
<td>
<?php echo htmlspecialchars($name); ?>
</td>
<td>
<ul>
<?php foreach($columns as $column) : ?>
<li><?php echo htmlspecialchars($column); ?></li>
<?php endforeach ?>
</ul>
</td>
</tr>
<?php endforeach ?>
</table>
数据库结果集在这里用数组结构模拟,但是典型的迭代器:
$rows = array(
array(1, 1, 'Rose', 'Drinker'),
array(2, 1, 'Rose', 'Nice Person'),
array(3, 1, 'Rose', 'Runner'),
array(4, 2, 'Gary', 'Player'),
array(5, 2, 'Gary', 'Funny'),
);
$result = new ArrayIterator($rows);
$users = new Users($result);
这表明这是一个单一的查询,没有子选择,不需要重新分组(如第一个问题所述),根据它的顺序执行此操作。
仅缺少Users
类的代码:
class Users extends IteratorIterator
{
private $last;
public function __construct($it) {
parent::__construct(new NoRewindIterator($it));
}
public function current() {
$current = $this->getInnerIterator()->current();
$this->last = $current[2];
return new Columns($this->getInnerIterator(), $this->last);
}
public function key() {
return $this->last;
}
public function next() {
$current = $this->getInnerIterator()->current();
if ($this->last === $current[2] || $current === NULL) {
parent::next();
}
}
}
class Columns extends IteratorIterator
{
private $name;
public function __construct($it, $name) {
$this->name = $name;
parent::__construct($it);
}
public function valid()
{
$current = parent::current();
return parent::valid() && $current[2] === $this->name;
}
public function current() {
$current = parent::current();
return $current[3];
}
}
Full demo at codepad - 我必须承认这包含一些迭代器黑魔法。
答案 10 :(得分:1)
这与其他一些回复非常接近,但我认为更清洁,更容易理解。
我在任何输出之前创建了一个三维数组,以方便使用。你可以一次完成所有事情,但我发现看起来更干净的代码往往会将它分开(例如,从数据库中读取与输出不同,因此请将它们分开)。这样,如果您需要引用33的第15个元值$resultArr[33]["meta"][15]
,您也可以使用方便的数组。
我还为每个结果行添加了类名和ID,以便于CSS样式化。
<?php
// DB connect //
// Get the DB Data
$result = mysql_query("SELECT Autonum, ID, Name, MetaValue FROM table GROUP BY ID");
// Set Start Values
$resultArr = array();
$curRow = -1;
$curMeta = -1;
// Loop Through the Rows
while ($row = mysql_fetch_assoc($result)) {
// Start of a new ID, Set the name and Create the MetaValue Array
if ($curRow != $row["ID"]){
$curRow = $row["ID"];
$resultArr[$curRow]["name"] = $row["Name"];
$resultArr[$curRow]["meta"] = array();
$curMeta = 0;
}
// Add the MetaValue
$resultArr[$curRow]["meta"][$curMeta] = $row["MetaValue"};
$curMeta++;
}
/* Array looks like:
$resultArr[1]["name"] = "Rose";
$resultArr[1]["meta"][0] = "Drinker";
$resultArr[1]["meta"][1] = "Nice Person";
$resultArr[1]["meta"][2] = "Runner";
$resultArr[2]["name"] = "Gary";
$resultArr[2]["meta"][0] = "Player";
$resultArr[2]["meta"][1] = "Funny";
*/
// Start the Table
$out = "<table>";
$out .= "\n<thead>";
$out .= "\n<th>Name</th>";
$out .= "\n<th>MetaValue1</th>";
$out .= "\n</thead>";
$out .= "\n<tbody>";
// Add the Rows
foreach($resultArr as $id => $col){
$out .= "\n\n<tr id='result_" . $id . "'>";
$out .= "\n<td class='rowName'>" . $col["name"] . "</td>";
$out .= "\n<td class='rowMeta'>";
$out .= "\n<ul>";
foreach($col["meta"] as $meta){
$out .= "\n<li>".$meta."</li>";
}
$out .= "\n</ul>";
$out .= "\n</td>";
$out .= "\n</tr>";
}
// Close the Table
$out .= "\n</tbody>";
$out .= "\n</table>";
// Print It Out Where You Need It
echo $out;
?>
答案 11 :(得分:1)
我既不在MySql或PHP端进行分组,也就是说不使用php的内存进行分组或使用mysql函数。只是控制打印。
您可以看到以下代码here
的工作示例<?php
$result = mysql_query("SELECT name,metavalue FROM table");
$count = mysql_num_rows($result);
?>
<table>
<thead>
<th>Name</th>
<th>MetaValue1</th>
</thead>
<tbody>
<?php
$i = 0;
// loop through each row
$start = 1;
while ($row = mysql_fetch_assoc($result) {
if ($name != $row['name']) {// row with new name
if ($start) {
$start = 0;
echo "<tr>";
echo "<td>" . $row['name'] . "</td>
<td><ul><li>" . $row['metadata'] . "</li>";
} else {
$start = 1;
echo "</ul></td>";
echo "</tr><tr>";
echo "<td>" . $row['name'] . "</td>
<td><ul><li>" . $row['metadata'] . "</li>";
}
} else {//row with the same name
echo "<li>" . $row['metadata'] . "</li>";
if ($i == $count - 1) {
echo "</ul></td></tr>";
}
}
?>
<?php
$name = $row['name'];
$i++;
}
?>
</tbody>
</table>
答案 12 :(得分:0)
这是您想要的代码。为了避免与您的代码发生任何冲突,我没有使用任何类对象概念,因此代码以简单的方式编写。它看起来很简单,但毫无疑问。请注意,代码是由高级程序员在php工作的最后一年半。所以不要介意代码的简单方式
<table>
<thead>
<th>Name</th>
<th>MetaValue1</th>
</thead>
<tbody>
<?php
mysql_select_db("dbName", $con);
$result = mysql_query("SELECT DISTINCT Name,ID FROM tableName");
while($row = mysql_fetch_array($result))
{
$userName = $row['Name'];
echo $userId = $row['ID'];
?>
<tr>
<td><?=$userName?> <?=$userId?></td>
<td>
<ul>
<?php
$resultNew = mysql_query("SELECT * FROM tableName WHERE ID =$userId");
while($row = mysql_fetch_array($resultNew))
{
$mValue = $row['MetaValue'];
?>
<li><?=$mValue?></li>
<?php
}
?>
</ul>
</td>
</tr>
<?php } ?>
</tbody>
</table>
答案 13 :(得分:0)
<?php
/**
* Displaying a table in PHP with repeated columns
* @link http://stackoverflow.com/a/11616884/367456
*/
class Events
{
private $row = 0;
public function newRow($name)
{
$this->closeRow();
echo " <tr><td>$name</td><ul>";
$this->row++;
}
public function closeRow()
{
if (!$this->row) return;
echo "</ul></tr>\n";
$this->row = 0;
}
public function newItem($name)
{
echo "<li>$name</li>";
}
}
$rows = array(
array(1, 1, 'Rose', 'Drinker'),
array(2, 1, 'Rose', 'Nice Person'),
array(3, 1, 'Rose', 'Runner'),
array(4, 2, 'Gary', 'Player'),
array(5, 2, 'Gary', 'Funny'),
);
echo "<table>\n <thead>\n <th>Name</th>\n <th>MetaValue1</th>\n </thead>\n <tbody>\n";
$events = new Events();
$last = null;
foreach ($rows as $row) {
if (@$last[2] !== $row[2]) {
$events->newRow($row[2]);
}
$events->newItem($row[3]);
$last = $row;
}
$events->closeRow();
echo " </tbody>\n</table>";