MySQL和PHP查询使用列标题和行输出基于相应的标题

时间:2017-11-25 01:02:51

标签: php mysql

enter image description here我正在尝试做两件事,有列标题输出($ accounts),然后在相应的列下添加相应的总和(z.cost),比如Water Rates。以及分组,因为每个属性有很多记录。它应该看起来像:

Property                     Council Rates              Water Rates
6 Hudson Road Rosemeadow          $1000                     $150
121 New York Street New York City $500

目前它单独输出每个属性行,并且仅在第一列中输出议会费率。

代码如下:

<table width="100%" class="table table-striped table-bordered table-hover" id="dataTables-example">
    <thead>
    <tr>
        <th class='text-center'>Property</th>
        <?php
        $query_prop = "SELECT a.street_number,
                         a.street_name,
                         a.suburb,
                         z.services, 
                         z.cost, 
                         j.service_type 
                         FROM pms_property a 
                         LEFT JOIN pms_holding_costs z 
                          ON z.pms_fk_id = a.pms_id 
                         LEFT JOIN pms_accounts j 
                          ON j.service_type = z.services 
                         WHERE z.services IS NOT NULL";

        $accounts = "SELECT service_type FROM pms_accounts";
        $value = $newdb->mysqlquery($query_prop);
        $acc = $newdb->mysqlquery($accounts);

        while ($acc1 = mysqli_fetch_array($acc)) {
            echo "<th class='text-center'>$acc1[0]</th>";
        }
        ?>
    </tr>
    </thead>
    <tbody>

    <?php
    while ($row = mysqli_fetch_array($value)) {
        echo "<tr class='odd gradeX'><td>$row[0] $row[1] $row[2]</td> ";
        if ($row['service_type'] == $acc1['service_type']) {
            echo "<td>$$row[4]</td>";
        } else {
            echo "<td>$0</td></tr>";
        }
    } ?>
    <tr>
        <td colspan="1" class="text-right"><strong>Total Costs</strong></td>
        <td colspan="1"><strong>$<?php echo $row1[1]; ?></strong></td>
    </tr>
    </tbody>
</table>

<table width="100%" class="table table-striped table-bordered table-hover" id="dataTables-example">
                            <thead>
                                <tr>
                                    <th class='text-center'>Property</th>


                                        <th class='text-center'>Council Rates</th>



                                        <th class='text-center'>Water Rates</th>


                                    </tr>
                                    </thead>
                                    <tbody>


                                    <tr class='odd gradeX'>
                                        <td>6 Hudson Road Rosemeadow</td> 

                                                <td>$0</td>
                                                </tr>

                                    <tr class='odd gradeX'>
                                        <td>121 New York Street New York City</td> 

                                                <td>$0</td>
                                                </tr>

                                    <tr class='odd gradeX'>
                                        <td>6 Hudson Road Rosemeadow</td> 

                                                <td>$0</td>
                                                </tr>

                                    <tr class='odd gradeX'>
                                        <td>6 Hudson Road Rosemeadow</td> 

                                                <td>$0</td>
                                                </tr>

                                    <tr class='odd gradeX'>
                                        <td>6 Hudson Road Rosemeadow</td> 

                                                <td>$0</td>
                                                </tr>

                                    <tr class='odd gradeX'>
                                        <td>6 Hudson Road Rosemeadow</td> 

                                                <td>$0</td>
                                                </tr>

                                    <tr class='odd gradeX'>
                                        <td>6 Hudson Road Rosemeadow</td> 

                                                <td>$0</td>
                                                </tr>
                                                                                        <tr>
                                        <td colspan="1" class="text-right"><strong>Total Costs</strong></td>
                                        <td colspan="1"><strong>$1650</strong></td>
                                    </tr>
                                </tbody>
                            </table>

enter image description here

2 个答案:

答案 0 :(得分:0)

我可能已经完成了Bodge,但目的是展示一些事情......

变量命名 - 按原样阅读代码让我头晕目眩...把事情称之为......你是如何做到这一点是开放的意见,但有一些东西......

我添加了很多评论,但更重要的是 - 为了让事情顺利进行 - 我已经以var_dump()的形式添加了一些调试信息。

这是“我们”至少可以看到你实际得到的东西,而不是你“想到”你得到的东西...... 因为当有问题时 - 通常就是这种情况

我“试图”指出在数据库结果中使用字段名称比使用数字索引要好得多,因为0到n不是很具描述性。所以为此我已经用提供的代码编写了我可以收集的内容。

所以新代码 - 没有经过测试,也没有直接回答你的问题,但应该通过看看你从var_dumps得到什么来帮助我们前进(你必须取消注释)。

希望代码中的注释有助于解释发生了什么。 注意:这是未经测试的。

<table width="100%" class="table table-striped table-bordered table-hover" id="dataTables-example">
    <thead>
    <tr>
        <th class='text-center'>Property</th>
        <?php
        $property_query = "SELECT a.street_number,
                         a.street_name,
                         a.suburb,
                         z.services, 
                         z.cost, 
                         j.service_type 
                         FROM pms_property a 
                         LEFT JOIN pms_holding_costs z 
                          ON z.pms_fk_id = a.pms_id 
                         LEFT JOIN pms_accounts j 
                          ON j.service_type = z.services 
                         WHERE z.services IS NOT NULL";
        // I am assuming ( badly ) that $property_result is an associative array.
        $property_result = $newdb->mysqlquery($property_query);
        // To check for debug purposes - uncomment the line below
        // var_dump($property_result);

        $accounts_query = "SELECT service_type FROM pms_accounts";

        // I am assuming ( badly ) that $accounts_result is an associative array.
        $accounts_result = $newdb->mysqlquery($accounts_query);
        // To check for debug purposes - uncomment the line below
        // var_dump($account_result);


        // Looks like this is an array of an array which has the table column names?
        while ($account = mysqli_fetch_array($accounts_result)) {
            echo "<th class='text-center'>$account[0]</th>";
        }
        ?>
    </tr>
    </thead>
    <tbody>

    <?php
    // Use MYSQLI_ASSOC to return the result set as an Associative Array.
    // Using numeric Indexes is hard to read and debug and prone to errors.
    while ($row = mysqli_fetch_array($property_result, MYSQLI_ASSOC)) {
        // Wrap variables in {} to help PHP work out what is a Variable in a double quoted string.
        echo "<tr class='odd gradeX'><td>{$row['street_number']} {$row['street_name']} {$row['suburb']}</td> ";
        if ($row['service_type'] == $acc1['service_type']) {
            echo "<td>{$$row['cost']}</td>";
        } else {
            // Use single quotes as double quotes will try to evaluate $0 as a variable
            echo '<td>$0</td></tr>';
        }
    } ?>
    <tr>
        <td colspan="1" class="text-right"><strong>Total Costs</strong></td>
        <!-- No idea where $row1[1] comes from! -->
        <td colspan="1"><strong>$<?php echo $row1[1]; ?></strong></td>
    </tr>
    </tbody>
</table>

答案 1 :(得分:0)

您的问题来自数据查询,查询没有任何内在错误,只是数据没有按您期望的方式格式化,或者需要它。

<强> 问题

SELECT
    a.street_number,
    a.street_name,
    a.suburb,
    z.services, 
    z.cost, 
    j.service_type 
FROM
    pms_property a 
LEFT JOIN
    pms_holding_costs z ON z.pms_fk_id = a.pms_id 
LEFT JOIN
    pms_accounts j ON j.service_type = z.services 
WHERE
    z.services IS NOT NULL

这里你基本上有多对多的关系,很多属性可以拥有多个账户。

现在在您的Html中,您使用此

构建标题
"SELECT service_type FROM pms_accounts"

这给你这个数组(基本上)

['Council Rates','Water Rates']

所有服务类型,这也是&#34; uncorallated&#34;到另一个查询。这只意味着两者之间没有直接关系,毕竟它们是单独的查询。

对于每种服务类型,您预计会有z.cost$row[4] ( 0 based indexing )两个值。但是如果查看查询(上图),您可以看到该字段只出现一次。因此,没有合理的方法可以在一行中获得2个值。

不用担心,我们可以用PHP解决这个问题。有一些方法可以使用SQL来解决这个问题,但如果您添加了任何服务类型,它们将会成为一个问题(我们将在后面介绍这些服务类型)。

这个DBfiddle应该有助于说明这个问题。这不是你的确切模式,我删除了&#34;肤浅的&#34;列,因为只有表之间的关系才是重要的。

pms_id  |       services    |   service_type
    1   |   Council Rates   |   Council Rates  //property (id 1) with only one service
    2   |   Council Rates   |   Council Rates  //property (id 2) with 2 services, 1 of 2
    2   |   Water Rates     |   Water Rates    //property (id 2) with 2 services, 2 of 2

这是你想要的结构,

pms_id  |   Council Rates   |   Water Rates | ...
    1   |    {cost}         |   {cost}   
    2   |    {cost}         |   {cost}    

<强>

首先,我们需要属性的主要ID,因此我们唯一标识是。所以将它添加到数据查询

SELECT
    a.pms_id, #<--------- add the ID
    a.street_number,
    a.street_name,
    a.suburb,
    z.services, 
    z.cost, 
    j.service_type 
FROM
    pms_property a

然后,我们将不得不挂在$accounts上,我会称他们为$headers因为他们是table的头部。它们是此查询的结果

"SELECT service_type FROM pms_accounts"

好的,所以你用while循环遍历那个结果集。我们只需要创建一个数组并将数据保存在其中。像这样:

$headers = [];
while ($acc1 = mysqli_fetch_array($acc)) {
     $headers[] = $acc1[0];
     echo "<th class='text-center'>$acc1[0]</th>";
}

对于这些示例和测试,我必须使用一些&#34; Canned&#34;反映数据的数据,因为我无法在线使用数据库。因此,这是您的数据来自2个查询的基本结构,现在{现在}。

$headers = ['Council Rates','Water Rates'];

$rows = [
    ['pms_id' => 1, 'street_name' => 'ONE', 'service_type' => 'Council Rates', 'cost' => 100],
    ['pms_id' => 2, 'street_name' => 'TWO', 'service_type' => 'Council Rates', 'cost' => 100],
    ['pms_id' => 2, 'street_name' => 'TWO', 'service_type' => 'Water Rates', 'cost' => 200],
];

我们必须将其改为更有用的东西&#34;对手头的任务有意义。

//We will need the result from the first query, the one for the headers. 
$headers = ['Council Rates','Water Rates']; 

/*
   first: create a "template" array by using $headers as the keys and
   fill them with 0 for the value {cost = 0, when missing}
   ----------------------------------------------------
   example. ['Council Rates'=>'0','Water Rates'=>'0']
   ----------------------------------------------------
*/
$default = array_fill_keys($headers,'0');  

$data = [];
while ($row = mysqli_fetch_assoc($value)) {
   //instead of mysqli_fetch_array, see http://php.net/manual/en/mysqli-result.fetch-assoc.php
   $service_type = $row['service_type'];

   /*
      Create a key based on the properties primary id
      ----------------------------------------------------
      I like to put a string "r" ( or anything ) in front
      of it so it doesn't get mistaken for a meaningless
      numeric index, because it's critical that we have it.     
   */
   $key = 'r'.$row['pms_id']; //such as 'r345'

    if( !isset($data[$key])){
        //if not set then it's the first pass ( Setup ) for this property

        //Create a new item with the service name as the key, and cost as the value
        $row[$service_type] = $row['cost'];

        //remove the type and cost they will just get in the way now.
        unset($row['service_type'], $row['cost']);

        /*
           by merging $row "header template" we made earlier {$default}
           ------------------------------------------------
           ['Council Rates'=>'0','Water Rates'=>'0']
           ------------------------------------------------
           we insure that any {$header} values, have a corresponding
           key in {$row}. This way there are no missing index issues,
           and we won't have to check if they have that service because
           any that don't will be conveniently filled with a '0'
           -----------------------------------------------
           example: ['pms_id' => 1, 'Council Rates'=>'100','Water Rates'=>'0']
           ----------------------------------------------------
        */
        $row =  array_merge( $default, $row);

        /*
            lastly add to our data array with our primary ID based key
            this loop iteration, is complete
        */
        $data[$key] = $row;

    }else{
        /*
             Additional passes, we only need the cost and service type.
             Because the properties {pms_id} is the primary key, and we
             have that in our sql as well as in $data from the previous
             loop iteration, we can easily find and fill in the next 
             service type. 

             -note- were not creating the service type, because we did 
              that with the {$default} array, we are simply replacing
              the '0' cost placeholder from that operation. 
             Any properties that are missing a service type will just 
             leave that 0 there.
        */
        $data[$key][$service_type] = $row['cost'];
    }
} 

//print_r($data);

此输出:

$data = Array(
    [r1] => Array(
        [Council Rates] => 100
        [Water Rates] => 0
        [pms_id] => 1
        [street_name] => ONE
    )
[r2] => Array(
        [Council Rates] => 100
        [Water Rates] => 200
        [pms_id] => 2
        [street_name] => TWO
    )
)

您可以在此处测试此部分:

http://sandbox.onlinephpfunctions.com/code/aa938ec823f8f116432eadad1f6db991e4be37dd

正如您所看到的,我们现在拥有了服务类型所需的密钥,这些数据的结构使我们能够轻松创建所需的HTML输出。这将使输出部分几乎无足轻重。

因此,在输出数据的地方(在使用wile循环之前,从数据库中读取它),我们将改为使用foreach循环。

这两项操作必须分开进行。无法保证数据的顺序,因此我们无法一次处理几行并在同一循环中执行输出。这不是什么大问题,因为我们通过组合行减少了数据数组的大小。

    //$headers = ['Council Rates','Water Rates']; //for readability

    foreach($data as $row) {
        echo "<tr class='odd gradeX'>";

        echo "<td>{$row['street_number']} {$row['street_name']} {$row['suburb']}</td>";

        /*
           Dynamically loop over headers.  We could just type this in
           but if you wanted to add more service types latter you would 
           have to come back here and add them in.  This way, you wont
           have to touch it in that case.

           This also enforces the order, we need the costs for each 
           service_type to be output in the same exact order the
           service_type headers were added into the table ( <th> ). 
         */
        foreach($headers as $header ){

            /*
              We have each service_type as a key in {$row}
              so we just pull it out with the {$header}.
            */              
            echo "<td>{$row[$header]}</td>";
        }
        echo "</tr>";
    }

输出 -note-我在我的示例数据中遗漏了street_numbersuburb,但这并不重要(在Real中)。

<tr class='odd gradeX'>
    <td> ONE </td>
    <td>100</td> <!-- Council Rates -->
    <td>0</td> <!-- Water Rates -->
</tr>

<tr class='odd gradeX'>
    <td> TWO </td>
    <td>100</td> <!-- Council Rates -->
    <td>200</td> <!-- Water Rates -->
</tr>

您可以在此处测试:

http://sandbox.onlinephpfunctions.com/code/6192b8fc732a88f212daed91423b180fd78ec4b9

在PHP中执行它更好,因为如果我们使用查询执行此操作,它将是静态的,如果您添加了另一种服务类型,我们将不得不编辑查询和输出。这种方式在PHP中,如果添加更多服务,则必须进行虚拟无代码更改。根据我的经验,随着时间的推移,需求发生变化,您不希望每次发生这种情况都需要重新访问此代码。作为开发人员,我们应该始终展望未来,并使代码尽可能地证明和维护。

对于&#34;短&#34;回答,这很有趣。正如我在评论中提到的那样,请花点时间查看上面代码中的注释,因为学习和理解然后获取一段有用的代码更重要。 这是完整的代码:

<table width="100%" class="table table-striped table-bordered table-hover" id="dataTables-example">
    <thead>
        <tr>
            <th class="text-center">Property</th>
        <?php 
            //for debugging
            error_reporting(-1);
            ini_set('display_errors', -1);

            $accounts = "SELECT service_type FROM pms_accounts";
            $acc = $newdb->mysqlquery($accounts);
            $headers = [];
        ?>        
        <?php while ($acc1 = mysqli_fetch_array($acc)){ ?>
            <?php $headers[] = $acc1[0]; ?>
            <th class="text-center"><?php echo $acc1[0]; ?></th>
        <?php } ?>
        </tr>
    </thead>
    <tbody>
        <?php 
          $default = array_fill_keys($headers,'0');

          $query_prop = "
                SELECT
                    a.pms_id,
                    a.street_number,
                    a.street_name,
                    a.suburb,
                    z.services,
                    z.cost,
                    j.service_type
                 FROM
                    pms_property a
                 LEFT JOIN
                    pms_holding_costs z ON z.pms_fk_id = a.pms_id
                 LEFT JOIN
                    pms_accounts j ON j.service_type = z.services
                 WHERE
                     z.services IS NOT NULL
             ";

          $value = $newdb->mysqlquery($query_prop);

          $data = [];
          while ($row = mysqli_fetch_assoc($value)){
              $service_type = $row['service_type'];

              //row unique id
              $key = 'r'.$row['pms_id']; 

              if( !isset($data[$key])){
                  //if not set then it's the first pass ( Setup ) for this property

                  //Create a new item with the service name as the key, and cost as the value
                  $row[$service_type] = $row['cost'];

                  //remove the type and cost they will just get in the way now.
                  unset($row['service_type'], $row['cost']);

                  $row =  array_merge( $default, $row);
                  $data[$key] = $row;
              }else{
                  //Additional passes set just the service type cost
                  $data[$key][$service_type] = $row['cost'];
              }
          } 
        ?>
        <?php foreach($data as $row){ ?>
            <tr class="odd gradeX">
                <td>
                    <?php echo "{$row['street_number']} {$row['street_name']} {$row['suburb']}"; ?>
                </td> 
            <?php foreach($headers as $header){ ?>             
                <td><?php echo $row[$header]; ?></td>
            <?php } ?>
            </tr>
        <?php } ?>  
            <tr>
                <td colspan="1" class="text-right"><strong>Total Costs</strong></td>
                <td colspan="1"><strong>$<?php echo $row1[1]; ?></strong></td>
            </tr>
        </tbody>
    </table>