Форматирование результатов запроса MySQL, как если бы он был запущен из консоли


Я пишу быстрый и грязный скрипт отчетности, который запрашивает отчет и отправляет результаты по электронной почте. При использовании консоли MySQL результаты отображаются в хорошо отформатированной таблице:

mysql> select * from users;
+-----------+------------+-------+
| firstname | city       | zip   |
+-----------+------------+-------+
| Maria     | Holland    | 12345 |
| Rene      | Doylestown | 65432 |
| Helen     | Conway     | 98745 |
+-----------+------------+-------+
3 rows in set (0.01 sec)

Есть ли простой способ воспроизвести это форматирование при получении результатов с помощью PHP? Очевидно, я мог бы добиться этого, написав свой собственный формат отчета, но я надеялся на что-то более элегантное.

Author: Mike B, 2011-01-04

7 answers

Вы могли бы сделать это довольно легко, используя пакет console_table PEAR. Просто просмотрите результаты MySQL и добавьте строки в свою таблицу. Вы можете использовать метод Console_Table::setHeaders() для добавления заголовков для ваших столбцов, затем метод Console_Table::addRow() для добавления каждой строки и, наконец, Console_Table::getTable() для ее отображения.

Для этого в PHP ничего не встроено. Если вы не хотите использовать/писать код для рисования консольных таблиц, просто передайте -e query в mysql через PHP с помощью passthru(). Это будет работать с запросами, завершенными как ;, так и \G:

passthru("mysql -e '$query;' database_name");
 12
Author: mfonda, 2011-01-04 19:42:55

Вы должны сделать это сами.

Выполните цикл, чтобы найти максимальный размер для каждого столбца. Затем выведите заполнение каждой строки до этого размера +2 с пробелом в начале и конце. разделите каждый столбец символом |.

Используйте + и -, чтобы создать свой верх и низ.

Трудно привести конкретный пример, не зная, что вы используете для получения своих результатов. Но предполагая, что вы используете mysql_query. Вот пример.

$conn = mysql_connect("localhost", "mysql_user", "mysql_password");
mysql_select_db("mydbname");
$result = mysql_query("SELECT * FROM myTable");
//first get your sizes
$sizes = array();
$row = mysql_fetch_assoc($result);
foreach($row as $key=>$value){
    $sizes[$key] = strlen($key); //initialize to the size of the column name
}
while($row = mysql_fetch_assoc($result)){
    foreach($row as $key=>$value){
        $length = strlen($value);
        if($length > $sizes[$key]) $sizes[$key] = $length; // get largest result size
    }
}
mysql_data_seek($result, 0); //set your pointer back to the beginning.

//top of output
foreach($sizes as $length){
    echo "+".str_pad("",$length+2,"-");
}
echo "+\n";

// column names
$row = mysql_fetch_assoc($result);
foreach($row as $key=>$value){
    echo "| ";
    echo str_pad($key,$sizes[$key]+1);
}
echo "|\n";

//line under column names
foreach($sizes as $length){
    echo "+".str_pad("",$length+2,"-");
}
echo "+\n";

//output data
do {
    foreach($row as $key=>$value){
        echo "| ";
        echo str_pad($value,$sizes[$key]+1);
    }
    echo "|\n";
} while($row = mysql_fetch_assoc($result));

//bottom of output
foreach($sizes as $length){
    echo "+".str_pad("",$length+2,"-");
}
echo "+\n";

Это сделало бы это (надеюсь, я не пропустил точка с запятой там:)).

Надеюсь, это поможет!

 5
Author: ehudokai, 2011-01-04 18:47:51

Вы можете использовать exec или backticks и фактически запустить его из командной строки через php. По-видимому, в команде mysql есть переключатель a -H, который вы можете использовать, и он будет выводить данные в формате HTML. Хотя я еще не пробовал, но это тоже может выглядеть неплохо.

echo '<pre>';
echo `mysql -u user -ppass -e "select * from table;" database_name`;

2 строки, никаких пакетов pear, насколько элегантнее это может быть для быстрой и грязной страницы статистики.

 3
Author: profitphp, 2011-01-04 20:02:27

Я оптимизировал ответ @ehudokai , поэтому он использует меньше циклов (5 против 9). И для полноты я также добавил командную строку, статистику и вывод ошибок:

<pre>
<?php
$db = mysqli_connect('localhost', 'my_user', 'my_password', 'my_db');
$start = microtime(true);
$sql = "SELECT * FROM myTable";
$result = mysqli_query($db, $sql);
$exec_time = microtime(true) - $start;
// obtain the maximum string length of all column headings and rows
$colwidths = array();
while ($row = mysqli_fetch_assoc($result)) {
    foreach ($row as $key => $value) {
        // heading
        if (!isset($colwidths[ $key ])) {
            $colwidths[ $key ] = strlen($key) + 2;
        }
        // rows
        $colwidths[ $key ] = max($colwidths[ $key ], strlen($value) + 2);
    }
}
echo 'mysql>' . trim($sql) . PHP_EOL;
// SELECT, SHOW, DESCRIBE, EXPLAIN = resource
// INSERT, UPDATE, DELETE, DROP = true
// Error = false
if (!is_bool($result)) {
    if ($colwidths) {
        mysqli_data_seek($result, 0);
        while ($row = mysqli_fetch_assoc($result)) {
            // create and display horizontal line and column headings
            if (!isset($header)) {
                $header = '| ';
                $line = '+';
                foreach ($row as $key => $value) {
                    $line .= str_repeat('-', $colwidths[ $key ] + 2) . '+';
                    $header .= str_pad($key, $colwidths[ $key ]) . ' | ';
                }
                echo $line . PHP_EOL;
                echo $header . PHP_EOL;
                echo $line . PHP_EOL;
            }
            // display row values
            foreach ($row as $key => $value) {
                echo '| ' . str_pad($value, $colwidths[ $key ] + 1);
            }
            echo '|' . PHP_EOL;
        }
        echo $line . PHP_EOL;
    }
    mysqli_free_result($result);
}
$affectedrows = mysqli_affected_rows($db);
if ($result === false) {
    echo PHP_EOL . 'ERROR ' . mysqli_errno($db) . ': ' . mysqli_error($db);
}
else if ($result === true) {
    echo 'Query OK, ' . $affectedrows . ' rows affected (' . round($exec_time / $iterations * 1000) . ' ms)';
}
else if ($affectedrows) {
    echo $affectedrows . ' rows in set (' . round($exec_time / $iterations * 1000) . ' ms)';
}
else {
    echo 'Empty set (' . round($exec_time / $iterations * 1000) . ' ms)';
}
?>
</pre>

Примеры

ВЫБЕРИТЕ

mysql>SELECT
        topic_id,
        MATCH(text) AGAINST('tuning') AS score
    FROM
        topics
    WHERE
        MATCH(text) AGAINST('tuning' IN BOOLEAN MODE)
    ORDER BY
        score DESC
    LIMIT 10
+----------+--------------------+
| topic_id | score              |
+----------+--------------------+
| 153257   | 5.161948204040527  |
| 17925    | 4.781417369842529  |
| 66459    | 4.648380279541016  |
| 373176   | 4.570812702178955  |
| 117173   | 4.55166482925415   |
| 167016   | 4.462575912475586  |
| 183286   | 4.4519267082214355 |
| 366132   | 4.348565101623535  |
| 95502    | 4.293642520904541  |
| 29615    | 4.178250789642334  |
+----------+--------------------+
10 rows in set (141 ms)

Ошибка:

mysql>SELECT * WHERE 1=1

ERROR 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE 1=1' at line 1

ОБНОВЛЕНИЕ

mysql>UPDATE topics_search SET topic_id = topic_id WHERE topic_id = 2
Query OK, 0 rows affected (0 ms)
 1
Author: mgutt, 2017-05-23 10:29:31

Основываясь на ответе мфонды, вы действительно можете легко загрузить пакет console_table pear с помощью composer сейчас: https://packagist.org/packages/pear/console_table

$ composer require pear/console_table

<?php
//Suppress E_DEPRECATED errors for statically calling a non-static method (this package is pretty old!)
error_reporting(E_ALL & ~E_DEPRECATED);
require __DIR__ . '/vendor/autoload.php';

//echo "<pre>"; #uncomment this line if running script in a browser

//The class isn't namespaced so just call it directly like so:
echo Console_Table::fromArray(
    ['column', 'headings'], 
    [
        ['1st row', 'values'], 
        ['2nd row', 'values'], 
        ['...', '...']
    ]
);

Это выводит:

+---------+----------+
| column  | headings |
+---------+----------+
| 1st row | values   |
| 2nd row | values   |
| ...     | ...      |
+---------+----------+
 1
Author: Harry Lewis, 2017-10-02 17:52:01

Это не имеет никакого смысла, учитывая способ, которым вы извлекаете данные из MySQL в PHP. (т.Е.: Вы обычно извлекаете строку данных за раз либо в виде массива (mysql_fetch_array), либо в виде объекта (mysql_fetch_object).)

Таким образом, вам нужно будет написать свой собственный хак, чтобы захватить все строки и отформатировать вывод таким образом. (Тем не менее, должно быть тривиально захватить данные и вывести их в виде таблицы HTML - вы можете получить имена полей с помощью array_keys если вы используете mysql_fetch_array и т.д.)

 0
Author: John Parker, 2011-01-04 18:18:29

Похоже, вам просто нужно использовать любой из методов exec или обратных ссылок. Я не уверен насчет "\G"... но я опубликовал функцию php под названием query2Table() несколько месяцев назад @http://www.logicwizards.net/php-query2table - на основе функции, которую я перерабатывал в течение многих лет. У меня есть куча, которую я накопил за эти годы: query2xml, query2excel, query2json и т.д. Я думаю, что у меня все еще где-то есть старые версии perl и asp.

В основном, в моем решение, вы можете просто передать ему строку запроса, и он динамически выплюнет таблицу html, используя имена столбцов, полученные из результатов, в качестве строки заголовка таблицы. Он также увеличивается, чтобы заполнить ширину унаследованного объекта контейнера.

  query2table("select * from table;");

У меня есть более современная версия query2AjaxTable(), которая красиво упаковывает все в класс и добавляет сортировку и анимацию jQuery, но она еще не готова к публикации.

Если моя глупая маленькая функция не поможет вам в вашей дилемме, может быть, кому-то еще это пригодится...

 0
Author: WWWIZARDS, 2011-01-27 08:42:13