How do I make a Multidimension-Array of MYSQL data via PHP - php

I want to create a Array with multidimension arrays from a database. The Database has 3 tables, one for vehicle, one for damages and one for damagesPhotos.
Table vehicle has two columns id and name
Table damages has four columns damagesID, vehicleID, damagesType and damagesDescription.
Table damagesPhotos has three columns damagesPhotoID and damagesID and damagesPhotoUrl
I need to combine thoose three columns into an array, that looks like this:
$vehicle = array(
"id" => "somestring",
"name" => "somestring",
"damages" => array(
"damagesType" => "somestring",
"damagesDescription" => "somestring",
"photoOfDamages" => array(
"damagesPhotoUrl" => "somestring"
)
)
);
My code looks like this, but is not working the right way.
$result = mysql_query( "SELECT * from vehicle v LEFT JOIN damages d ON v.id = d.vehicleID LEFT JOIN damagesPhotos p ON d.damagesID = p.damagesID WHERE d.damagesID = p.damagesID AND v.id = 1") or die(mysql_error());
$rowsResult = array();
while ($r = mysql_fetch_assoc($result))
{
$rowsResult [] = $r;
}
mysql_free_result($result);
echo json_encode($rowsResult);
...
/Morten

As its not possible in mysql, so we can write a script which gives all information about specific vehicle and with that data, we can create an array.
Refer following code.
$query = "SELECT * from vehicle v LEFT JOIN damages d ON v.id = d.vehicleID LEFT JOIN damagesPhotos p ON d.damagesID = p.damagesID WHERE d.damagesID = p.damagesID AND v.id = 1";
$result = mysql_query($query);
$i = 0;
$vehicle = array();
while($row = mysql_fetch_array($result)){
$vehicle[$i] = array(
"id" => $row[id],
"name" => $row[name],
"damages" => array(
"damagesType" => $row[damagesType],
"damagesDescription" => $row[damagesDescription],
"photoOfDamages" => array(
"damagesPhotoUrl" => $row[damagesPhotoUrl]
)
)
);
$i++;
}

You can't get a multidimensional array from mysql, it just gives you a two dimensional resultset. A number of column values for each row is all you can get. If you want it nested like that, you'll have to process the array after retrieving the results.
Something like this:
$vehicles = array();
while ($r = mysql_fetch_assoc($result))
{
$vehicle['id'] = $r['id'];
...
$damage = array();
$damage['damagesType'] = $r['damagesType'];
...
$vehicle['damages'] = $damage;
...
array_push($vehicles, $vehicle);
}
echo json_encode($vehicles);

It is not possible to have MySQL do all the work for you here (well, it is possible to have it do most of the work, but don't) because a result set from MySQL - or any SQL driven database - can have exactly two dimensions. The first dimension is a collection of rows, and the second is a collection of columns for each row.
Based on the example target data structure, you have two choices:
Get the initial result set (vehicle LEFT JOIN damages) and iterate over it, running queries to get the photos
Join all tables together as you are currently doing and post-process it into the desired multidimensional structure.
It's a trade off - option 1 results in a lot more database traffic but retrieves no more than the required data, whereas option 2 reduces it to a single query with less database traffic, but retrieves more data than required because each photo row carries the entire vehicle's data with it.
Option 1 would be a prime candidate for using prepared statements, which is something you are unable to take advantage of using the mysql_* functions. You should switch to using PDO or MySQLi instead. I personally recommend PDO. There are numerous other reasons for doing this as well, including the fact that the MySQL extension will one day be removed from PHP, and the proper use of prepared statements can completely removed any risk of security problems resulting from SQL injection via user input.
I would probably recommend option 2.

Thanks to Vinay, my array looks like this. Thats nice :)
[{"vehilceId":"1",
"name":"AW55005",
"damages":{
"damagesType":"Exterior",
"damagesDescription":"Rust",
"photoOfDamages":{
"damagesPhotoUrl":"link to damagesPhoto 01"
}
}
},
{"vehilceId":"1",
"name":"AW55005",
"damages":{
"damagesType":"Exterior",
"damagesDescription":"Rust",
"photoOfDamages":{
"damagesPhotoUrl":"link to damagesPhoto 02"
}
}
},
{"vehilceId":"1",
"name":"AW55005",
"damages":{
"damagesType":"Interior",
"damagesDescription":"Scratch",
"photoOfDamages":{
"damagesPhotoUrl":"link to damagesPhoto 03"
}
}
}
But as you can see the first two objects are the same only the damagesPhotoUrl is different.
How do I merge thoose two array so it will look like this:
{"vehilceId":"1",
"name":"AW55005",
"damages":{
"damagesType":"Exterior",
"damagesDescription":"Rust",
"photoOfDamages":{
{"damagesPhotoUrl":"link to damagesPhoto 01"},
{"damagesPhotoUrl":"link to damagesPhoto 02"}
}
}
}, ...
/Morten

After solving you main problem. I am writing this for new problem. As I know, you cant assign values to same key in your array means you cant allow to have duplicate keys. Because How would you access the value you want if more than one can have the same key. That's why you can choose another way to do merge your value. Re-arrange your array in following way.
$key = "damagesPhotoUrl";
$value = "link to damagesPhoto 01";
$array[$key][] = $value;
you can then access it as:
echo $array[$key][0];
echo $array[$key][1];

Its very late.... but if you using PDO then PDO::FETCH_COLUMN with PDO::FETCH_GROUP can make result in 3 dimensional array.
I think its limited, I'm not very SQL guy, but saying "You can't get a multidimensional array from mysql...or any SQL driven database - can have exactly two dimensions" can be not quite true.
Sorry for my English and off topic (this question is about mysql, not pdo)
http://php.net/manual/en/pdostatement.fetchall.php
(pseudo array):
array(
array(//group 1
array(
0=>item1,
0=>item2...
)
array(
0=>item1,
0=>item2...
)
array(
0=>item1,
0=>item2...
)
array(
0=>item1,
0=>item2...
)
)...
array(//group 2
array(
0=>item1,
0=>item2...
)
array(
0=>item1,
0=>item2...
)
)...
)

Related

Percentage of responses in array for a graph population?

I have this little query that produces the percentage of responses correctly.
$pdo->query("SELECT avg(pineapple = 'yes')*100 FROM responses");
But what I need to do, is get columns question1,2,3,4 columns together where they are arrayed as columnname => percentage for my graph.
Since I'm not getting two fields in the SELECT, I am unclear how to move forward to set up array like I have before:
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
$jsnarray = array();
$json = json_encode($results);
foreach($results as $k => $v){
$jsnarray[] = array('question' => $results[$k]['COLUMN???'], 'value' => $results[$k]['question1']);
};
Update:
To clarify desired output: an array like:
[column1name] => column yes response %
[column2name] => column2 yes response %
so it would theoretically be:
[pineapple] => 55%
[cheesecurds] => 80%
Which allows the bar graph to be labeled pineapple with the value of 55% and so on.
You should normalize your database design. With your current design, you have to list each column separately. What happens if you need to add a new ingredient?
You could modify your existing SQL to calculate an average of each column like so:
SELECT
avg(pineapple = 'yes')*100 AS pineapple,
avg(mushroom = 'yes')*100 AS mushroom,
avg(anchovy = 'yes')*100 AS anchovy,
avg(cheesecurd = 'yes')*100 AS cheesecurd
FROM responses
Then in PHP, you can just access it as you normally would with any other column.
$averages = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Anchovies: ".$averages['anchovy'];
For a non normalized database like one using imports from google forms:
$stmt = $pdo->query("SELECT 100*avg(pineapple = 'yes') AS Pineapple, 100*avg(pepperoni = 'yes') AS Pepperoni, 100*avg(mushrooms = 'yes') AS Mushrooms, 100*avg(anchovies = 'yes') AS Anchovies FROM responses");
$averages = $stmt->fetch(PDO::FETCH_ASSOC);
$jsonEncodedData=json_encode($averages);
header( 'Content-type: application/json' );
echo $jsonEncodedData;
I did 100*avg for percentage.
Again, don't use this if you can help it.

How to easily split results in PHP with a LEFT JOIN mysql query?

I have a query in which I am tring to put the results in an array.
The query returns all data of the two tables: order and orderdetails:
SELECT orders.*, order_details.* FROM `webshop_orders`
LEFT JOIN `order_details`
ON `orders`.`order_id` = `order_details`.`f_order_id`
WHERE `orders`.`f_site_id` = $iSite_id AND `orders`.`order_id` = $iOrder_id;";
I am trying to found out how to return this data an put them in an array of the following format:
$aOrders = array(
0=>array(Orders.parameter1=>value, orders.parameter2=>value, orders.parameter3=>value, 'orderdetails'=>array(
array(Orderdetails.parameter1=>value, orderdetails.parameter2=>value)));
I currently return every result as an associate array and manually split every variable based on its name using 2 key-arrays, but this seems very 'labor-intensive'?
while($aResults = mysql_fetch_assoc($aResult)) {
$i++;
foreach($aResults as $sKey=>$mValue){
if(in_array($sKey, $aOrderKeys){
$aOrder[$i][$sKey] = $mValue;
} else {
$aOrder[$i]['orderdetails'][$sKey] = $mValue;
}
}
}
EDIT: the function above does not take multiple order-details into consideration, but the function is meant as an example!
Is there an easier way or can I use a better query for this?
You can use the following while loop to fill your array:
$data = array();
while ($row = mysql_fetch_assoc($result)) {
if (!isset($data[$row['order_id']])) {
$order = array('order_id' => $row['order_id'],
'order_date' => $row['order_date'],
/* ... */
'orderdetails' => array());
$data[$row['order_id']] = $order;
}
if (isset($row['order_details_id'])) { // or is it "!= null"? don't know...
$details = array('id' => $row['order_details_id'],
'whatever' => $row['order_details_whatever']);
$data[$row['order_id']]['orderdetails'][] = $details;
}
}
This way you can have multiple orderdetails for one order, they get all added to the ['orderdetails'] field.
Additional notes:
Do not use SELECT *, see the question What is the reason not to use select *? and any other website about this topic.
Do not use the mysql_*() functions (even though I did above for showing the while loop), they are deprecated. Use PDO instead.

How to sort a multidimensional array of columns by a specific column in PHP?

I found on the PHP documentation the function "array_multisort" that is meant to sort an array "of columns". They provide one example where the user has an array of rows and then the user has to transform this array of rows into an array of columns. In my case the array is already set by columns, such as:
tablearray
{
['Employee_ID'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}
['First_Name'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}
['LastName'] = {0 => row1, 1 => row2, 2 => row3, 3 =>row4}
}
I want to sort by Employee_ID and I need all the other columns to follow the same order. I tried:
array_multisort($tablearray['Employee_ID'], SORT_ASC);
But it only sorts the first column (which becomes a mess). The array has more than 10 columns and it changes the column names depending on the search (the columns names are its keys).
On PHP's documentation for this function, the example provided shows that the after transforming the rows array into a columns array, we should use the original array as a third parameter to match the keys - I don't have the "original" array to do the match since I didn't transform anything.
Thank you.
Desired output, as suggested by one user:
Original:
array
{
['Employee_ID'] = (1002, 4508, 0002, 1112)
['Business_Unit'] = ('UER', 'ABC', 'XYZ', 'EER')
['LastName'] = ('Smith', 'Vicente', 'Simpson', 'Thompson')
}
Sorted by Employee ID:
array
{
['Employee_ID'] = (0002, 1002, 1112, 4508)
['Business_Unit'] = ('XYZ', 'UER', 'EER', 'ABC')
['LastName'] = ('Simpson','Smith', 'Thompson', 'Vicente')
}
--
My original array is a database query output:
Array
(
[0] => Array
(
[Employee_ID] => 0000
[Supervisor_ID] => 00000
[Location_Descr] => somewhere
[Start_Date] => 06/03/2002
[Service_Date] => 06/03/2002
[Rehire_Date] => 00/00/00
[Business_Unit] => YYYY
[Job_Title] => Manager
[Email] => email#example.com
[Dept_Desc] => bla bla bla
[Employee_Name_LF] => Last, First
[Supervisor_Name_LF] => Last, First
[Term_Date] => 00/00/00
[Preferred_Name] => Someone
[Source] => Sheet2
)
)
There a several more rows.
The main purpose is to show the results as an HTML table and to generate a CSV file. I already made those functions using the modified structure (the first that I posted). I thought it would be easier to deal with that structure... Indeed it was, but not for sorting unfortunately.
The array_multisort documentation (http://php.net/manual/en/function.array-multisort.php) suggests separating each column as an individual array.. However, as you can see I have several columns (and the user can select more or less to be shown before performing the query.. So I can't just list all of them on the statement).
I a willing to change everything just to make the code better to be worked with.
Ugly - would be a lot easier if you formatted the input tables.
$arr = array(
'Employee_ID' => array('1002', '4508', '0002', '1112'),
'Business_Unit' => array('UER', 'ABC', 'XYZ', 'EER'),
'LastName' => array('Smith', 'Vicente', 'Simpson', 'Thompson')
);
$employees = array();
foreach (range(0, sizeof($arr[current(array_keys($arr))]) - 1) as $k) {
$emp = array();
foreach ($arr as $col => $vals) {
$emp[$col] = $arr[$col][$k];
}
$employees[] = $emp;
}
$sort = array();
foreach ($employees as $k => $v) {
$sort[$k] = $v['Employee_ID'];
}
array_multisort($sort, SORT_ASC, $employees);
print_r($employees);
And to put back in the original format:
$arr_sorted = array();
foreach (array_keys($arr) as $col) {
$arr_sorted[$col] = array();
foreach ($employees as $emp) {
$arr_sorted[$col][] = $emp[$col];
}
}
print_r($arr_sorted);
Thank you for posting the extra details in your question, as they did help in understanding the intent of your question.Now, you didn't tell us how that table should look; If you want the employees one per row, or one per column. Which is kind of crucial to know. Normally one would have one employee per line, especially if this is to be exported to CVS. However, I have a suspicion that it's the latter you want. Otherwise you've gone about this in a very overly complicated manner.Point in case: Normal one-per-row layout:
<?php
$db = new PDO();
// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "e.employee_id, e.first_name, e.lastname, u.business_unit, s.email";
// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$query = <<<outSQL
SELECT {$Fields} FROM `unit` AS u
INNER JOIN `employee` AS e ON e.employee_id = u.unit_id
INNER JOIN `employee` AS s ON s.employee_id = u.supervisor_id
ORDER BY e.`employee_id`
outSQL;
$data = $db->query($query);
// Creating a printf() template for the output, to make the code easier to maintain.
$rowTemplate = <<<outHTML
<tr>
<td>%1\$d</td>
<td>%2\$s</td>
<td>%3\$s</td>
</tr>
outHTML;
// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
<thead>
<tr>
<th>ID</th>
<th>First name</th>
<th>Last name</th>
</tr>
</thead>
<tbody>
%s
</tbody>
</table>
outHTML;
// Regular table output, one employee per line.
$temp = '';
foreach ($data as $e) {
// hs() is a shortcut function to htmlspecialchars (), to prevent against XSS.
$temp .= sprintf($rowTemplate, $e['employee_id'], hs($e['first_name']), hs($e['lastname']));
}
// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);
If you want to do it one per column, it becomes a bit more intricate. Though, still a bit easier than your first attempt. :)
Namely, something like this:
<?php
$db = new PDO();
// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "employee_id, first_name, lastname";
// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$data = $db->query("SELECT {$Fields} FROM `employees` ORDER BY `employee_id`");
// We need to know how many columns we'll have. One per employee.
$columns = count ($data);
// Rows have a header in front of each line, and one td tag for each employee.
$rowTemplate = "\t\t<th>%s</th>\n".str_repeat("\t\t\t<td>%s</td>\n", $columns);
// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
<tbody>
%s
</tbody>
</table>
outHTML;
// Reformat the array to give us the data per-column.
$temp = array ();
foreach ($data as $field => $e) {
// Since we've already sorted the data in the database we don't need to do any further sorting here.
// Also note that I'm doing the escaping here, seeing as this array will only be used for output.
$temp['Employee ID'][] = intval($e['employee_id']);
$temp['First name'][] = hs($e['first_name']);
$temp['Last name'][] = hs($e['lastname']);
}
// Now we do the same as in the above example.
$rows = '';
foreach ($temp as $label => $l) {
// We have the label as the first template variable to be added, so put it as the first element.
array_unshift($l, $label);
// Add the current row of items to the output, using the previously established template.
$rows = vprintf($rowTemplate, $l);
}
// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);
PS: Haven't tested the code, but it should work.
I ran into his problem and after much angst found a really nice solution in the notes on the php manual page - I now have the following function which i use whenever I need to solve this type of problem.
function fnArrayOrderby(){
//function to sort a database type array of rows by the values in one or more column
//source http://php.net/manual/en/function.array-multisort.php - user notes
//example of use -> $sorted = fnArrayOrderby($data, 'volume', SORT_DESC, 'edition', SORT_ASC);
$args = func_get_args(); //Gets an array of the function's argument list (which can vary in length)
//echo "sorting ".$args[0]."<br>";
if (!isset($args[0])) { return;}
$data = array_shift($args); //Shift an element off the beginning of array
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}

Iterating through PHP array with duplicate records and deleting one record where a value = 0

I have a MySQL query using Laravel that I convert to a PHP Array.
The rows have values similar to this:
name | override | percentage
Eclipse | 1 | 50%
Eclipse | 0 | 75%
MySQL query
select * from table
Both rows (it's many more than just 2 in reality) have the same name, but one has override set to 0 and one has it set to 1.
How can I get rid of all records in my query result (PHP array) that are duplicates (determined by the name) AND have override set to 0? I want only the records that have been overridden with a new record which I have done, but I need a way to remove the records with override = 0, given that the records are the same but have a different percentage value.
How can this be done?
Thanks.
Try following query,
SELECT * from testtable GROUP BY `name` HAVING count(`name`) = 1 OR `override` = 1;
check this sqlfiddle
If I understand your needs correctly, you need to filter out records that have duplicate name and override = 0.
If you sort your result set by name (SELECT * FROM TABLE ORDER BY name), you can use this function.
function removeDuplicatesFromArray($rows) {
$result = array();
$old_name = '';
foreach($rows as $row) {
if($row['name'] != $old_name) {
$result[] = $row;
$old_name = $row['name'];
}
elseif($row['override'] == 1) {
array_pop($result);
$result[] = $row;
}
}
return $result;
}
NOTE: Doing this in SQL will be WAYYYYYYYYY faster and use far less memory. I would only try this PHP approach if you cannot modify the SQL for some reason.
Maybe try out... hit the db twice, first time only get non-overrides, then get the overrides in second pass -- coerce your arrays to be indexed by name and array_merge them. (Uses a fair chunk of memory given the number of arrays and copies - but it's easy to understand and keeps it simple.
$initial = get_non_overridden();
$override = get_overridden();
$init_indexed = index_by_name($initial);
$over_indexed = index_by_name($override);
$desired_result = array_merge($init_indexed, $over_indexed);
Assuming your database gives you a standard rowset (array of rows, where each row is a hash of fields->values). We want something that looks like this instead:
[
'Eclipse' => [
'name' => 'Eclipse',
'override' => '0',
'percentage' => '75%'
],
'Something' => [
'name' => 'Something',
'override' => '0',
'percentage' => '20%'
],
]
So index_by_name would be:
function index_by_name($rowset) {
$result = array();
foreach ($rowset as $row) {
$result[ $row['name'] ] = $row;
}
return $result;
}
There are ways to tweak your efficiency either in memory or run time, but that's the gist of what I was thinking.
array_merge then overwrites the initial ones with the overridden ones.
NOTE: this all assumes that there is only one row where Eclipse override is 1. If you have twenty Eclipse|0 and one Eclipse|1, this will work, if you have two Eclipse|1 you'd only see one of them... and there's no way to say which one.

Php merge arrays [duplicate]

This question already has answers here:
Is there a php function like python's zip?
(14 answers)
Closed 7 months ago.
So I have these two foreach
foreach($find as $e) {
$theData[] = array('href' => $e->href, 'linkText' => $e->plaintext);
foreach($findText as $f){
$theData[] = array('description' => $f->plaintext);
}
}
So I need that the result to be something like this: $theData = array('href' => $e->href, 'linkText' => $e->plaintext,'description' => $f->plaintext);
array_merge doesn't do want I want to achive.Any help?
Try...
$i = 0;
foreach($find as $e){
$data[$i] = array('href' => $e->href, 'linkText' => $e->plaintext);
foreach($findText as $f){
$data[$i]["description"][] = $f->plaintext;
}
$i++;
}
If your arrays both have automatically created integer keys, then it's simple:
$theData = array();
for($i = 0; $i < count($e); ++$i) {
$theData[] = array(
'href' => $find[$i]->href,
'linkText' => $find[$i]->plaintext,
'description' => $findText[$i]->plaintext);
}
Note that the above code will not work correctly if $find and $findText don't have the same number of items, or if the keys don't match. Generally, making this work without more specific information will get quite messy.
The best practical advice I can give is to re-examine the code which creates $find and $findText -- it will be much easier to achieve your goal at that time.
Allow me to make the assumption that you are combining information from two queries. One option you have is to get href, linktext and description from your database all at once by joining your query.
select table_1.href,table_1.plaintext, table_2.plaintext
from table_1
where //insert your where clause, if appropriate
join table_2 on table_1.id = table_2.parent_id
where table one is your $find array and table_2 is your $findText array; and table_2.parent_id is a value matching the id from table_1. Joining the tables in this query will store all the fields from your two assumed queries into one variable.

Categories