【问题标题】:Pivot a mysql result set and create html table/matrix透视 mysql 结果集并创建 html 表/矩阵
【发布时间】:2020-12-27 12:35:55
【问题描述】:

整晚都把我的头撞在墙上,但还没有解决方案,假设我有这样的 Mysql 表结构:

ID  name  value   year
 1  Tom     15     2018
 2  Tom     4      2019
 3  Tom     6      2020
 4  Kate    18     2018
 5  Kate    20     2019
    ...and so on... 

我想通过 PHP 打印如下所示的结果,并且年份应该是动态的,因为它会随着时间的推移而增加。请告诉我什么是一种方法谢谢

year |2018 |2019|2020
----------------------
Tom  |  15 |  4 | 6
----------------------
Kate |  18 | 20 | ---

----- and so on --- 

我的代码:

<table>

<?php
$mysqli = new mysqli('localhost', 'root', '123', 'news');
$report = array();
$columnIndex = 0;
$query = $mysqli->query("SELECT name, value, year FROM Testab");
while ($results = $query->fetch_assoc()) {
    foreach ($results as $tos => $toa) {
        $report[$tos][$columnIndex] = $toa;
    }
    $columnIndex++;
}

foreach ($report as $tos => $results) { ?>
    <tr>
        <th><?php echo $tos; ?></th>
        <?php foreach ($results as $toa) { ?>
            <th><?php echo $toa; ?></th>
        <?php } ?>
     </tr>
 <?php } ?>
</table>

【问题讨论】:

  • 如果您的数据库中没有 2019 年的数据,您的表是否还应该有 2018、2019、2020 列,还是在这种情况下您只想将 2019 年排除在外?
  • 给定的代码到底是什么不工作?你有什么努力让它发挥作用?

标签: php mysql matrix html-table pivot


【解决方案1】:

请参阅下面的代码可以帮助您找出解决方案:

基本上需要对输入数据进行一次额外循环来创建输出数据所需的元数据。在一些数据报告场景中,需要这种数据转换。

<?PHP
//assuming mysql is giving below data
$in_data = array(
                array('ID'=>1,'name'=>'Tom','value'=>15,'year'=>2018),
                array('ID'=>2,'name'=>'Tom','value'=>4,'year'=>2019),
                array('ID'=>3,'name'=>'Tom','value'=>6,'year'=>2020),
                array('ID'=>4,'name'=>'Kate','value'=>18,'year'=>2018),
                array('ID'=>5,'name'=>'Kate','value'=>20,'year'=>2019),
            );
            
$out_data = convertInToOut($in_data);

var_dump($out_data);

function convertInToOut($inData){
    $years = array();
    $persons = array('year'=>array('name'));
    //creating meta data 
    foreach($inData as $in){
        $years[$in['year']] = $in['year'];
        $persons[$in['name']] = array($in['name']); 
    }

    sort($years,SORT_NUMERIC);
    //aligning based on year
    $yearIndex = array();
    foreach($years as $key=>$year){
        $yearIndex[$year] = $key;
        $persons['year'][] = $year;
    }
    //final step of handling values for each names
    foreach($inData as $in){
        $persons[$in['name']][$yearIndex[$in['year']]+1] = $in['value'];    
    }
    
    return $persons;
    
}           

?>

var_dump($out_data) 的输出:

    array(3) {
  ["year"]=>
  array(4) {
    [0]=>
    string(4) "name"
    [1]=>
    int(2018)
    [2]=>
    int(2019)
    [3]=>
    int(2020)
  }
  ["Tom"]=>
  array(4) {
    [0]=>
    string(3) "Tom"
    [1]=>
    int(15)
    [2]=>
    int(4)
    [3]=>
    int(6)
  }
  ["Kate"]=>
  array(3) {
    [0]=>
    string(4) "Kate"
    [1]=>
    int(18)
    [2]=>
    int(20)
  }
}

【讨论】:

  • 这不提供 OP 请求的输出。
  • @mickmackusa,生成的数组可用于在 html 表中生成所需的输出
  • 所以你发布了一个半答案?如果 Stack Overflow 页面包含半答案,那么我们将无法使用旧页面/现有页面来关闭新的重复问题。
  • @mickmackusa,半答案或全答案取决于视角,目标应该是帮助 OP 找到解决方案,我试图这样做。创建 html 不是 OP 的主要问题,它创建用于创建 html 的所需数据。
  • Stack Overflow 帖子绝不是一对一的互动。每个答案都应努力教育/授权 OP 以及成千上万的未来研究人员。每个答案都应完全回答所提出的具体问题,并包括任何可能对具有类似要求的未来研究人员有所帮助的相关见解。您的帖子越全面、越有见地,您就越有可能帮助他人并获得更多代表积分。
【解决方案2】:

首先,您需要有一个单独的查询,以升序排列所有年份。

'SELECT year FROM table GROUP BY year ORDER BY year ASC

或从结果数组中提取年份,如下面循环中的注释,但请确保在主查询中按年份 ASC 排序,以避免两次调用数据库

你应该有这样的结果。您在 foreach 循环中操作数组,它会按用户为您提供一个多维数组。

然后你在你的 html 中循环它,如下面的代码,你应该完成

   <?php

$mydata = array(
    array(
        'id' => 1,
        'name' => 'Tom',
        'value' => 5,
        'year' => 2019
    ),
    array(
        'id' => 1,
        'name' => 'Tom',
        'value' => 5,
        'year' => 2018
    ),
    array(
        'id' => 1,
        'name' => 'kate',
        'value' => 5,
        'year' => 2017
    ),
    array(
        'id' => 1,
        'name' => 'Tom',
        'value' => 5,
        'year' => 2018
    ),
    array(
        'id' => 1,
        'name' => 'kate',
        'value' => 5,
        'year' => 2018
    ),
    array(
        'id' => 1,
        'name' => 'kate',
        'value' => 5,
        'year' => 2017
    ),
    array(
        'id' => 1,
        'name' => 'joe',
        'value' => 5,
        'year' => 2016
    ),
    array(
        'id' => 1,
        'name' => 'joe',
        'value' => 5,
        'year' => 2017
    )
);

 //this line assumes that you queries the database to fetch the years
$years = ['2019','2018','2017','2016'];

$display = array();

foreach ($mydata as $data) {
   //only add this if you don't want to query the database a second 
    //time to get the years
   if(!in_array($data['year'], $years)){
       $years[] = $data['year'];
    }
    $display[$data['name']]['values'][$data['year']] = $data['value'];
    $display[$data['name']]['name'] = $data['name'];
}


?>

<html>

<body>
    <table>
        <td>year</td>
        <?php foreach ( $years as $year) { ?>
            <td><?php echo $year; ?></td>
        <?php } ?>
        <tbody>
            <?php foreach ($display as $name => $info) { ?>
                    <tr>
                        <td><?php echo $info['name']; ?></td>

                        <?php foreach($years as $year){ ?>
                        <td><?php echo isset($info['values'][$year])? $info['values'][$year] : 'null'; ?></td>
                        <?php } ?>
                    </tr>

            <?php } ?>
        </tbody>
        </th>

    </table>
</body>

</html>

【讨论】:

  • 如果您仔细阅读,在我的回复的第一句话中,我指定应该从数据库中查询年份,并每年分组
  • 嗯,通过使用数据循环数组并提取和分组所有年份,多年来可以获得相同的结果。这对性能会更好。
  • 我完全同意你的看法,并在我的回答中证明了这一点。
  • 我根据您的建议编辑了我的评论,并提供了两个选项
【解决方案3】:

有很多方法可以做到这一点;一些技术涉及 sql 来准备动态数据透视。下面我的sn-p会使用php来执行pivot。

  1. 使用foreach() 循环遍历结果集对象——不,您不需要调用获取函数来访问数据,因为结果对象是可迭代的。
  2. 创建一个多维分组数组,以名称作为第一级键,然后以年份作为键、值作为值的子数组。
  3. 创建一组独特的年份。我的方法将通过将年份指定为键和值来确保唯一性——因为数组不能包含重复的键,所以值将是唯一的,而无需稍后调用 array_unique()
  4. 按 ASC 排序年份
  5. 为每年创建一个默认值数组。在这种情况下,我将 - 指定为默认值。
  6. 将文字词 name 添加到包含唯一年份的数组的前面——这将用于填充表格的标题行。
  7. 我更喜欢使用implode() 来制作可变单元格表格行。
  8. printf() 是一种将文字文本与变量混合的简洁方式——它避免了插值/连接语法。
  9. 在每个后续表格行中,将默认年度值替换为相关人员的年度值,并以implode() 呈现。
  10. 如果结果集有可能是空的,那么您可能希望将此 sn-p 的大部分内容包装在 if ($resultObject) { ... } 块中。

代码:(Demo)

$grouped = [];
$columns = [];    

$resultObject = $mysqli->query("SELECT `name`, `value`, `year` FROM `Testab`");
foreach ($resultObject as $row) {
    $grouped[$row['name']][$row['year']] = $row['value'];
    $columns[$row['year']] = $row['year'];
}

sort($columns);
$defaults = array_fill_keys($columns, '-');
array_unshift($columns, 'name');

echo "<table>";
    printf(
        '<tr><th>%s</th></tr>',
        implode('</th><th>', $columns)
    );
    foreach ($grouped as $name => $records) {
        printf(
            '<tr><td>%s</td><td>%s</td></tr>',
            $name,
            implode('</td><td>', array_replace($defaults, $records))
        );
    }
echo "</table>";

输出:(添加间距/制表符以便于阅读)

<table>
    <tr>
        <th>name</th> <th>2018</th> <th>2019</th> <th>2020</th>
    </tr>
    <tr>
        <td>Tom</td>  <td>15</td>   <td>4</td>    <td>6</td>
    </tr>
    <tr>
        <td>Kate</td> <td>18</td>   <td>20</td>   <td>-</td>
    </tr>
</table>

【讨论】:

    【解决方案4】:

    A mi me funciona excelente,戴尔!

    f_pivot($rs,'NombreFila','NombreColumna','Valor', true, 'Nombre del reporte', 'danger'); 
    

    Aqui llamas a la función:

    function f_pivot ($array, $fila, $columna, $valor, $MostrarTotal = true, $Caption=null, $ColorHeader = "info") {
      echo '<div class="table-responsive">
      <table class="table table-hover table-condensed table-striped">';
      if (empty($array)) {
        echo "<caption>No se encuentran datos para mostrar !</caption>";
      }else{
        foreach ($array as $key => $r) {
            $f[$key] = $r[$fila];
            $c[$key] = $r[$columna];
        }
        echo "<caption>".$Caption."</caption>";
        array_multisort($array, SORT_ASC, $f, SORT_ASC, $c);
        $f = array_values(array_unique($f));
        sort($f);
        $c = array_values(array_unique($c));
        sort($c);
        $Constructor = "<thead><tr><th class='$ColorHeader'>$fila</th>";
        foreach ($c as $key => $c_aux){
            $Constructor = $Constructor . "<th class='$ColorHeader'>" . utf8_encode($c_aux) . "</th>";
        }
        if ($MostrarTotal == true){
          $Constructor = $Constructor . "<th class='$ColorHeader'>TOTAL</th></tr></thead>";
        }else{
          $Constructor = $Constructor . "</tr></thead>";
        }
        echo $Constructor;
        echo "<tbody>";
        foreach ($f as $key => $f_aux) {
            echo "<tr>";
            echo '<td>' . utf8_encode($f_aux) . "</td>";
            $array_aux = array_filter($array, function($item) use ($f_aux, $fila){
                if ($item[$fila]==$f_aux) return true; else return false;
            });
            foreach ($c as $key => $c_aux) {
                $array_aux2 = array_filter($array_aux, function($item) use ($c_aux, $columna){
                    if ($item[$columna]==$c_aux) return true; else return false;
                });
                $varValor = array_sum(array_column($array_aux2, $valor));
                echo "<td align='right'>"; 
                  if ($varValor == 0){
                    echo "-";
                  }else{
                    echo number_format($varValor,0);
                  }
                  echo "</td>";
            }
            if ($MostrarTotal == true){
              $Tfila = "<td align='right'><b>" . number_format(array_sum(array_column($array_aux, $valor)),0) . "</b></td>";
              echo $Tfila;
            }
            echo "</tr>";
        }
        echo "</tbody>"; 
        $Constructor = "";
        echo "<tfoot>
                <tr>
                  <td></td>";
        foreach ($c as $key => $c_aux){
            $Tarray = array_filter($array, function($item) use ($c_aux, $columna){
                    if ($item[$columna]==$c_aux) return true; else return false;
                });
            $Constructor =  "<td align='right'><b>" . number_format(array_sum(array_column($Tarray, $valor)),0) . "</b></td>";
            echo $Constructor;
        }
        if ($MostrarTotal == true){
          $Constructor =  "<td align='right'><b>" . number_format(array_sum(array_column($array, $valor)),0) . "</b></td>";
          echo $Constructor;
        }
        echo "</tr>
            </tfoot>";
    }
    echo '  </table>
    
    '; }

    【讨论】:

    • 请将您的 cmets 翻译成英文。
    猜你喜欢
    • 1970-01-01
    • 2019-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 2013-06-25
    相关资源
    最近更新 更多