2

I am trying to extract a table from mysql in php with the column names to be used as headers and the values in the column to be displayed as values.

| id | firstname | lastname |
|  1 | Joe       | Jones    |
|  2 | Cal       | Clark    |
|  3 | Rob       | Robin    |

problem is i am getting back

| id | firstname | lastname |
|  1 | Joe       | Jones    |
| id | firstname | lastname |
|  2 | Cal       | Clark    |
| id | firstname | lastname |
|  3 | Rob       | Robin    |

please help with what i am doing wrong.

P.S I am quite new to programming also don't mind the poor html.

$query = "SELECT * ";
$query .= "FROM {$selected_table} ";
$query .= "LIMIT 0, 30";

$confirmed_query = confirm_query($query);
$query = mysql_query($confirmed_query);

echo "<table>";
while ($query_result = mysql_fetch_assoc($query)) {
    echo "<tr>";
    foreach ($query_result as $columns => $rows) {
        echo "<th>{$columns}</th>";
    }
    echo "</tr><tr>";
    foreach ($query_result as $colums => $rows) {
        echo "<td>$rows</td>";
    }
    echo "</tr>";

}
echo "</table>";

is there any other way to get the column names out of the array with out using a foreach which will cause it to return the column names for each record in the array?

outis
  • 75,655
  • 22
  • 151
  • 221
Moshe
  • 473
  • 1
  • 8
  • 22
  • The mysql extension is outdated and on its way to deprecation. New code should use mysql or PDO, both of which have important advantages, such as support for prepared statements. Don't use [`SELECT *`](http://stackoverflow.com/questions/321299/what-is-the-reason-not-to-use-select); select only the columns you need. Database access code shouldn't be mixed with display code; they're [separate concerns](http://en.wikipedia.org/wiki/Separation_of_concerns) and should be kept in separate tiers. – outis Dec 07 '11 at 22:43
  • @outis: You mean mysqli? – CodeZombie Dec 07 '11 at 22:50
  • @ZombieHunter: mysqli is also acceptable; it supports prepared statements and OOP. IMO, PDO is nicer to use, though some prefer mysqli (though simply using it as a drop-in replacement for the mysql extension without any other updates is a mistake). – outis Dec 07 '11 at 22:52
  • @outis: Sorry, I'm confused. Your wrote "mysql or PDO". What is the difference between the mysql in the quotes and the mysql extension? – CodeZombie Dec 07 '11 at 22:53
  • 2
    @outis, I think you simply mistyped your comment above. ext/mysqli and PDO support OO usage, prepared statements, transactions. ext/mysql does not and using it is discouraged. But I don't think they'll ever be able to truly deprecate it, because there are probably billions of lines of code out there using ext/mysql. – Bill Karwin Dec 07 '11 at 23:01
  • 1
    I see now. Yes, I have a typo in my original comment. ZombieHunter and Bill are correct. As for hard deprecation of mysql... a boy can dream, can't he? – outis Dec 07 '11 at 23:23
  • @outis: I think we were dreaming about the same... :-) – CodeZombie Dec 07 '11 at 23:34

4 Answers4

3

This is a job for do...while!

$query_result = mysql_fetch_assoc($query);
if ($query_result) {
  echo "<table>";
  echo "<tr>";
  foreach ($query_result as $columns => $rows) {
      echo "<th>{$columns}</th>";
  }
  echo "</tr>";
  do {
    echo "<tr>";
    foreach ($query_result as $colums => $rows) {
        echo "<td>$rows</td>";
    }
    echo "</tr>";
  } while ($query_result = mysql_fetch_assoc($query));
  echo "</table>";
}

But I also give +1 to @outis's answer because we should all be using PDO -- not the antiquated and inferior mysql extension.

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
2

Move the table header section outside of your while loop.

Joe Stefanelli
  • 132,803
  • 19
  • 237
  • 235
  • But then I run in 2 other problems 1. i get an undefined variable error. 2. the column headers/nmaes don't display at all – Moshe Dec 07 '11 at 20:58
2

You have to write the table headers only once and not for each record. Use something like this:

$headerWritten = false;

echo "<table>";
while ($query_result = mysql_fetch_assoc($query)) {
    // Write header
    if(!$headerWritten) {
        echo "<tr>";
        foreach ($query_result as $columns => $rows) {
            echo "<th>{$columns}</th>";
        }
        echo "</tr>";

        $headerWritten = true;
    }

    // Write rows
    echo "<tr>";
    foreach ($query_result as $colums => $rows) {
        echo "<td>$rows</td>";
    }
    echo "</tr>";

}
echo "</table>";
CodeZombie
  • 5,367
  • 3
  • 30
  • 37
  • Nice and simple solutions just needed to add a flag so it won't run again. This is a nice and simple fix. – Moshe Dec 07 '11 at 23:54
  • @PHPSushaRolls: but inefficient, as the `if` statement will be evaluated every time through the loop. Bill's solution is both simple and efficient. However, [simple](http://www.motifake.com/image/demotivational-poster/0905/simplicity-simplicity-demotivational-poster-1243725544.jpg) doesn't mean correct. – outis Dec 08 '11 at 00:11
1

Use PDO and PDOStatement::getColumnMeta to get the column names before the loop.

A full solution is a little involved, as it should also separate data access and display. The following is intended more as an illustration rather than anything that should be used in production code.

<?php
abstract class Model {
    abstract function fields();
    function __get($name) {
        /* Won't work with overloaded methods (`__call`) by design. Accessing
           non-nullary methods as properties will cause warnings. To prevent this
           at a time-cost, use ReflectionMethod to check the arity of the method.
         */
        if (method_exists($this, $name)) {
            return $this->$name();
        }
    }
    ...
}

class ModelCollection extends Model {
    // use the delegate pattern, rather than inheritance
    protected $_delegate, $_fields;

    function __construct($result) {
        $this->_delegate = $result;
    }

    function __call($name, $args) {
        if (is_callable($this->_delegate, $name)) {
            return call_user_func_array(array($this->_delegate, $name), $args);
        } else {
            $delegateClass = get_class($this->_delegate);
            $myClass = get_class($this);
            throw new BadMethodCallException("Method {$delegateClass}::{$name} (called as {$myClass}::{$name}) doesn't exist.");
        }
    }

    /* Here's where we get the column names */
    function fields() {
        if (is_null($this->_fields)) {
            $columnCount = $this->_delegate->columnCount();
            for ($i=0; $i < $columnCount; ++$i) {
                $this->_fields[] = $this->_delegate->getColumnMeta($i);
                // perhaps massage data into some other format
            }
        }
        return $this->_fields;
    }
}

abstract class View {
    public $data;

    abstract function display();
    ...
}

class TableView extends View {
    function display() {
        ?>
        <table>
          <?php 
           $this->_display_head();
           $this->_display_body();
          ?>
        </table>
        <?php
    }
    /* Here's the first place we use the column names */
    protected function _display_head() {
        ?>
          <thead>
            <tr>
              <?php foreach ($this->data->fields as $fields) { ?>
                <th><?php echo $fields['name'] ?></th>
              <?php } ?>
            </tr>
          </thead>
        <?php
    }
    protected function _display_body() {
        ?>
          <tbody>
            <?php
             foreach ($this->data as $row) {
                $this->_display_row($row);
             }
            ?>
          </tbody>
        <?php
    }
    /* Here's the second place we use the column names */
    protected function _display_row(&$row) {
        ?>
            <tr>
              <?php foreach ($this->data->fields as $fields) { ?>
                <th><?php echo $row[$fields['name']] ?></th>
              <?php } ?>
             </tr>
        <?php
    }
}
outis
  • 75,655
  • 22
  • 151
  • 221