I have a table with 6 columns
Sort like:
Database -> kids
|CANDY | COLOR | DRINK | PET | SONG | TOY |
---------------------------------------------------
|cookie | blue | juice | dog | if | ball |
|cake | red | coke | cat | ask | doll |
I want to store
all the candies in one Array called Candy[];
all the colors on color[];
all the drinks on drink[]; etc....
I managed to create the arrays with the columns names with a FORLOOP with these lines, which works fine:
$fieldName = mysqli_fetch_field_direct($result, $i)->name;
${$fieldName} = array();
But when the code gets to the WHILE part, that is also inside the loop, to add the columns items inside the arrays[], it adds only the first element and returns to the FORLOOP, goes and adds one element to the next array[] and jumps to the next array[]....
while($row = mysqli_fetch_array($result)){
//inserts itens in the "$array" with columns name
${$fieldName}[] = $row[$i];
}
If I try to "echo" the arrays[] and don´t put a "BREAK" at the end of the WHILE, It returns an error
"Undefined offset: 0 in line..."
And when I put the "BREAK", it works for:
echo candy[0]; = cookie
but doesn't works for:
echo candy[1]; = Undefined offset: 1 in line...
Here is the whole code:
$sql="SELECT candy, color, drink, pet, song, toy FROM kids";
$result = mysqli_query($con,$sql);
$colNumber = mysqli_num_fields($result);
for($i=0;$i<=$colNumber -1;$i++){
$fieldName = mysqli_fetch_field_direct($result, $i)->name;
echo . $fieldName . "<br /><br />";
//Creates an Array with Coll Name from DB
//with dynamic-variable ${$fieldname}
${$fieldName} = array();
while($row = mysqli_fetch_array($result, MYSQLI_NUM)){
//inserts the received itens into the array ${$fieldName}
${$fieldName}[] = $row[$i];
printf ("%s (%s)\n", $row[$i], $row[1]);
}
echo ${$fieldName}[0];
echo candy[0];
echo ${$fieldName}[1];
echo candy[1];
echo "<hr />";
}
The WHILE code works when it´s not inside a FORLOOP and if I make a query() like:
SELECT candy FROM kids.
But then, like that, I´d need like 600 lines of repeated code to get what I want and copy/paste again and again for each new coll on the DB table.
Any ideas?
I need it to put the arrays inside HTML
<SELECT><OPTION></SELECT> , then use mt_rand() to shuffle and get different "profiles". This won´t be used with kid stuff, that was just an example.
It will be a virtual crime creator that will shuffle the variables to create different crime hypothesis for law school students work on.
I already spent 3 days reading documentation on http://php.net/manual/pt_BR/mysqli-result.fetch-array.php
and "googling" it but couldn't find any answer.
Found a way to do it. I translated the code to English so others can have it. If there is any variable name wrong, fix it using the comments and enjoy!
$sql = "SELECT parquet, defendant, action, modusOperandi, victim, crime FROM crime_elements";
//runs '$sql' query to get database data
$result = mysqli_query($con,$sql);
$collNumber = mysqli_num_fields($result);
echo "ColL Number :" . $collNumber;
// Creates $data Array[]
$data = array();
while($row = mysqli_fetch_array($result)){
//inserts received data into "$data" and makes available by array[]index
$data[] = $row;
}
for($i=0;$i<=$collNumber -1;$i++){
// Gets the column name from the query()
$fieldName = mysqli_fetch_field_direct($result, $i)->name;
echo "</br><b>Coll Name:</b> " . $fieldName . "<br /><br />";
${$fieldName} = array_column($data, $i);
print_r(${$fieldName});
echo "<br /><b>Specified item choice[]:</b> ". ${$fieldName}[2];
echo "<hr />";
}
Related
I'm writing a quick and dirty reporting script that queries a report and emails the results. When using the MySQL console the results are in a nicely formatted table:
mysql> select * from users;
+-----------+------------+-------+
| firstname | city | zip |
+-----------+------------+-------+
| Maria | Holland | 12345 |
| Rene | Doylestown | 65432 |
| Helen | Conway | 98745 |
+-----------+------------+-------+
3 rows in set (0.01 sec)
Is there an easy way to replicate this formatting when fetching the results with PHP? Obviously I could achieve this by writing my own report formatter but I was hoping for something a little more elegant.
You could do this quite easily using the Console_Table PEAR package. Just loop through your MySQL results, and add rows to your table. You can use the Console_Table::setHeaders() method to add the headers for your columns, then the Console_Table::addRow() method to add each row, and finally Console_Table::getTable() to display it.
There is nothing built into PHP to do this. If you don't want to use/write code to draw console tables, just pass -e query to mysql via PHP using passthru(). This will work queries terminated with both ; and \G:
passthru("mysql -e '$query;' database_name");
You have to do it yourself.
do a loop to find the max size for each column. Then output each row padding to that size +2 with a space at the beginning and end. seperate each column with a |.
Use + and - to create your top and bottom.
It's hard to give a concrete example without knowing what you're using to get your results. But assuming you're using mysql_query. Here's an example.
$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";
That would do it (I hope I didn't miss a semicolon in there :) ).
Hope that helps!
You could use exec or backticks and actually run it from the command line through php. Apparently the mysql command has a -H switch you can use, and it will output HTML formatted. Haven't tried it though, but that might look good too.
echo '<pre>';
echo `mysql -u user -ppass -e "select * from table;" database_name`;
2 lines, no pear packages, how much more elegant can it get for a quick and dirty stats page.
Building on mfonda's answer, you can really easily load the Console_Table pear package with composer now: 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'],
['...', '...']
]
);
This outputs:
+---------+----------+
| column | headings |
+---------+----------+
| 1st row | values |
| 2nd row | values |
| ... | ... |
+---------+----------+
This doesn't make any sense bearing in mind the manner in which you fetch data from MySQL in PHP. (i.e.: You generally fetch onw row of data at a time either as an array (mysql_fetch_array) or an object (mysql_fetch_object).)
As such, you'd need to write your own hack to grab all of the rows and format the output in this manner. (That said, it should be trivial to grab the data and output it as an HTML table - you could get the field names via array_keys if you use mysql_fetch_array, etc. )
I optimized the answer of #ehudokai so it uses less loops (5 vs 9). And for completeness I added the command line, stats and error output, too:
<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>
Examples
SELECT
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)
Error:
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
UPDATE
mysql>UPDATE topics_search SET topic_id = topic_id WHERE topic_id = 2
Query OK, 0 rows affected (0 ms)
it sounds like you just need to use any one of the exec methods or backticks. I'm not sure about the '\G' thingy... but, I published a php function called query2Table() a few months ago # http://www.logicwizards.net/php-query2table -- based on a function I've been recycling for years. I have a bunch that I've accumulated over the years: query2xml, query2excel, query2json, etc. I think I still have the old perl & asp versions somewhere, too.
Basically, in my solution, you can just pass it the query string and it dynamically spit's out an html table using column names fetched from the results as the table's header row. It also grows to fill the width of it's inherited container object.
query2table("select * from table;");
I have a more up to date version query2AjaxTable() which wraps everything up nicely in a class and adds jQuery sorting & animations -- but it's not ready for publishing yet.
If my silly little function doesn't help you, in your dilemma, maybe someone else will find it useful...
so i have a question regarding, hmmm filtering data in mysql/php.
So i have table lets say
ID | fk1 | fk2
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 3 3
Basicaly i have in same table many occurancies of fk1 that are referenced to fk2 and when i output that in table ofcourse i get result as
1 1
1 2
1 3
2 1
etc. And that is normal. What i want to do is basically output one time FK2 value lets say 1, and all corresponding FK1 values below it. Sorta like group by but for each occurancie of FK2 i need all the FK1s that have that FK2 in their row.
I managed to get it working somehow so that all FK1 print out and corresponding FK2 but other way around wont work :S
$FK1 = '';
while($row = mysql_fetch_array($result_set)){
if($FK1 != $row['fk1']){
if($FK1 != ''){
echo $printout;
}
$FK1 = $row['fk1'];
$printout = "<tr class='success'><td>" . "<strong>" . $row['fk1']. "</td></tr>";
}
$printout = $printout .'<td class="warning"> '.$row['fk2']. '</td></tr>';
}
echo $printout ;
Any idea how to do this with some smart loop instead of using multiple queries on base?
Thanks
For each iteration of the loop that prints the query, you can check if the previous iteration printed the same thing and (if yes) skip the printing or print the current one if not.
I hope I understood the question and my answer is clear enough.
Something like this:
$cFk1 = "";
foreach($query_result as $cVal){
if($cVal != cFk1){
print $cVal;
}
$cFk1 = $cVal;
}
You can try GROUP_CONCAT in your query such as:
SELECT
fk2, GROUP_CONCAT(fk1) fk1,
FROM
table
GROUP BY
fk2
And then in your PHP code:
foreach($rows as $row) {
// plain echo
echo $row['fk2'].' '.$row['fk1'];
}
or
foreach($rows as $row) {
// or with post-processing
echo $row['fk2'].' ';
$fk1 = explode(',', $row['fk1']);
foreach($fk1 as $value) {
echo $value.'-';
}
}
But beware - GROUP_CONCAT has its limits, you should make sure the strings don't contain the separator (if it's only numbers, it's ok), etc.
I have a mysql database called menus. I am able to query my database to obtain a recordset accordingly. I do NOT want to write a query for each season. My problem: I want to write a php if statement within body to echo a message if the season field CONTAINS 2.
table menu
id | item (varcar) | season (set)
1 | fresh lemonade | 2,3
2 | smoothie | 2
3 | cafe latte | 4
My query works fine
mysql_select_db($database_rest, $rest); $query_menus = "SELECT * FROM
menus";
$menus = mysql_query($query_menus, $rest) or die(mysql_error());
$row_menus = mysql_fetch_assoc($menus);
$totalRows_menus = mysql_num_rows($menus);
I can write a php if to work where recordset field = 2 that works.
<?php echo $row_menus['item']; ?>: <?php
if (#$row_menus['season'] == 1)
{
echo "Winter";
}
else if (#$row_menus['season'] == 2)
{
echo "Spring";
}
else if (#$row_menus['season'] == 3)
{
echo "Summer";
}
else if (#$row_menus['season'] == 4)
{
echo "Fall";
}
?>
Result Shows:
fresh lemonade: Spring
smoothie: Spring
cafe latte: Fall
I want to write php so that if season CONTAINS 2 (example: if (#$row_menus['season'] CONTAINS 1) echo Spring, etc for each. so that result would look like this:
fresh lemonade: Spring
fresh lemonade: Summer
smoothie: Spring
cafe latte: Fall
First of all, it's time to upgrade those mysql_* functions! Second, there's better ways to set up the relationship between the item and its seasons. However, I'll let you look into that stuff.
$query_menus = "SELECT * FROM menus";
$menus = mysql_query($query_menus, $rest) or die(mysql_error());
$seasons_array = array('All Seasons', 'Winter', 'Spring', 'Summer', 'Fall');
while($row_menus = mysql_fetch_array($menus))
{
$item = $row_menus['item'];
$season = $row_menus['season'];
if(strpos($season, ',') !== false)
{
$seasons = explode(',', $season);
// To show the item and season on separate rows
foreach($seasons as $s)
echo $item . ': ' . trim($seasons_array[(int)$s]);
// To show the item, and then a list of seasons
echo $item . ': ';
foreach($season as $k => $s)
echo trim($seasons_array[(int)$s]) . (($k + 1) == count($season) ? '' : ', ');
}
else
{
echo $item . ': ' . $seasons_array[(int)$season];
}
}
I didn't test this, but it should work for you. Try it out, and let us know.
EDIT: I updated it so that you can list the items on separate rows, or list the item followed by each season.
You have two choices:
use PHP to split the field into an array and work through that
use multiple rows where season only holds one value
Using PHP, you could use $season=explode(',',$row_menus['season']); and then use a foreach statement to iterate through $season
The problem you have is that PHP interprets 2,3 as a string. When it's converted into a number, it appears as 2
Try using multiple rows for the season field:
id | item (varcar) | season
1 | fresh lemonade | 3
2 | smoothie | 2
3 | cafe latte | 4
4 | fresh lemonade | 2
This will also help where you want to select all rows where season=2
Finally, as Tobias said, don't use the mysql_ functions. Use newer functions which are supported
I got a table as DOMDocument which looks like this:
name | user | comment
-----------------------------
Test | user1 | Line 1
Abc | user2 | Line 1
| | Line 2
Test2 | user3 | Line 1
Test3 | user3 | Line 1
| | Line 2
| | Line 3
as you can see, sometimes the comment Wraps over multiple tablerows. (Apparently when the comment is a long one)
When those wraps occur, all fields except for the comment one are empty.
How can I merge those wrapped comments together and output them?
I am currently outputting them like this:
foreach ($xml->getElementsByTagName('table')->item(1)->getElementsByTagName('tr') as $row) {
echo "<tr>";
foreach ($row->getElementsByTagName('td') as $column) {
echo "<td>" . $column->textContent . "</td>";
}
echo "</tr>";
}
}
You are outputting each row before you know what the next one contains. A different approach would be to store each row in an array, allowing you to correct the previous row if the following row meets a certain condition (eg. wrapping). You can then output the resulting array as an HTML table once processed.
Something like this (untested):
// build array
$rows = array();
$xmlRows = $xml->getElementsByTagName('table')->item(1)->getElementsByTagName('tr');
foreach ($xmlRows as $xmlRow) {
$emptyFields = 0;
$row = array();
$xmlColumns = $xmlRow->getElementsByTagName('td');
foreach ($xmlColumns as $xmlColumn) {
if (empty($xmlColumn->textContent)) { // count empty fields
$emptyFields++;
}
$row[] = $xmlColumn->textContent;
}
if ($emptyFields >= 2) { // detect if wrapping has occurred
$lastRow = array_pop($rows); // remove last row from array
$lastRow[2] .= $row[2]; // update last row with wrapped data
$row = $lastRow; // use newly merged row
}
$rows[] = $row;
}
// output array
foreach ($rows as &$row) {
$row = '<td>' . implode('</td><td>', $row) . '</td>';
}
echo '<table><tr>' . implode('</tr><tr>', $rows) . '</tr></table>';
I have a MySQL query that returns a number of records. For example:
+-------+------------+-----------+
| group | first_name | last_name |
+-------+------------+-----------+
| Red | John | Doe |
+-------+------------+-----------+
| Red | Jane | Doe |
+-------+------------+-----------+
| Green | Bob | Anybody |
+-------+------------+-----------+
| Black | Betty | Anybody |
+-------+------------+-----------+
I also have defined several group names in a PHP array:
$importantGroups = array('Red', 'Blue', 'Green');
Using the query results, I'm trying to write a PHP script that will create an unordered HTML list for each group that's defined in the array.
If a group doesn't appear in any query results, then that list doesn't get created.
If a result has group value that doesn't appear in the array, it's placed in a ul at the end.
Using the query results above, the HTML output would be:
<ul id="Red">
<li>John Doe</li>
<li>Jane Doe</li>
</ul>
<ul id="Green">
<li>Bob Anybody</li>
</ul>
<ul id="Other">
<li>Betty Anybody</li>
</ul>
Any help on the best way to make this work?
First, do the ordering in SQL like this:
SELECT ... ORDER BY FIELD(`group`, 'Green', 'Blue', 'Red') DESC
The parameters for FIELD should be in reverse order of their importance, results not in this group will be sorted to the end.
During output, just break into a new group whenever you encounter one:
$group = null;
while ($row = /* get result */) {
if (!in_array($row['group'], $importantGroups)) {
$row['group'] = 'other';
}
if ($row['group'] != $group) {
if ($group !== null) {
echo '</ul>';
}
printf('<ul id="%s">', $row['group']);
$group = $row['group'];
}
printf('<li>%s</li>', $row['name']);
}
if ($group !== null) {
echo '</ul>';
}
This is the most efficient way for large result sets. If the sets aren't that large, it's a lot more readable to group them together in PHP and output the groups, as demonstrated in the other answers.
This is a little janky, I think there may be some way to add efficiency but it certainly works.
<?php
$importantGroups = array('Red', 'Blue', 'Green');
$sql = "SELECT * FROM `table`";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)){
if(array_search($row['group'],$importantGroups)){
$groupName = $row['group'];
}else{
$groupName = "Other";
}
$groups[ $groupName ][] = $row;
}
$importantGroups[] = "Other";
foreach($importantGroups as $groupName){
echo '<ul id="' . $groupName . '">';
foreach($groups[$groupName] as $element){
echo '<li>' . $element['first_name'] . ' ' . $element['last_name'] . '</li>';
}
echo '</ul>';
}
?>
This is a really basic script, and you should really look into finding out more about how PHP and mySQL work together instead of just asking for help. I'll post the basic flow to help you in the correct order of operations and the resources to help you along. To start I'd recommend reading this how-to on Tizag, which should help you fully understand how these languages work together.
Query SQL to get the data you need
//Connect to the database
//Query for the data
$sql = "SELECT group, first_name, last_name FROM ... WHERE ..."
$results = mysql_query($sql);
Parse the SQL results to create a multi-dimensional array of results
while($result = mysql_fetch_assoc($results){
$array_of_groups[$result["group"]][] = $result;
}
Iterate through the results array to create the desired output
foreach($array_of_groups as $group_name => $group){
//We are now looping groups
echo("<ul id='$group_name'>");
foreach($group as $item){
$item_name = $item["first_name"] . " " . $item["last_name"];
echo("<li>$item_name</li>");
}
echo("</ul>");
}
The above code is untested and really just a stub of what you need. You'll need a test above to figure out what groups are not needed. I'm really going to recommend reading up on that Tizag article and patching up that example code to make sure you understand how it works going forward.
I think it might be better to have three while loops. SELECT * FROM Table WHERE 'Group'='Red', then SELECT * FROM Table WHERE 'Group'='Green', then SELECT * FROM Table WHERE 'Group' NOT IN ('Red','Green'). With each result, put them in UL tags.
For example:
<?php
echo '<ul>';
while($row = mysql_fetch_array($result_Red))
{
echo "<li>" . $row['first_name'] . " " . $row['last_name'] . "</li>";
}
echo "</ul>";
mysql_close($con);
?>
And then again for Green and Other. It might save more time than saving each value to an array, then running a foreach loop to call them. Maybe not. Try it and find out.