Preserve the insert order in a PHP array - php

I have a PHP page used by an Ajax call that I want to return an ordered list of items as JSON. However whichever field I use in the query's 'order by' clause the array is always ordered by its key, the ID field.
Is there a way to preserve the insert order of each item in the PHP array?
This is the code that generates the JSON array:
$Soggetti = array();
while($row = $db->fetch_array($query))
{
$Soggetti[$row['ID']] = array();
$Soggetti[$row['ID']]['Denominazione'] = $row['Denominazione'];
$Soggetti[$row['ID']]['Indirizzo'] = $row['Indirizzo'].','.$row['Comune'].', '.$row['Provincia'];
$Soggetti[$row['ID']]['Superficie'] = $row['Superficie'];
$Soggetti[$row['ID']]['Lat'] = $row['Lat'];
$Soggetti[$row['ID']]['Lng'] = $row['Lng'];
$Soggetti[$row['ID']]['Tipologia'] = $row['Tipologia'];
$Soggetti[$row['ID']]['CodiceIscrizione'] = $row['CodiceIscrizione'];
$Soggetti[$row['ID']]['Visitato'] = intval($row['Visitato']);
}
echo json_encode($Soggetti)

If the problem lies in where the JSON is interpreted, in the client, you can use this syntax to return a JSON array (enclosed in []) instead of a JSON object (enclosed in {}).
echo json_encode(array_values($Soggetti));

You are building a 2 dimensional array with the key on first dimension being the id. Assuming id is numeric you will end up with nested objects in JSON, with the key of top level being the numerical id values. The problem here being that object properties have no guarantee of order.
To get the order of the query results, simply build a 1-D array inside your result set loop like this:
$tempArray = array();
$tempArray['ID'] = $row['ID'];
$tempArray['Denominazione'] = $row['Denominazione'];
$tempArray['Indirizzo'] = $row['Indirizzo'].','.$row['Comune'].', '.$row['Provincia'];
$tempArray['Superficie'] = $row['Superficie'];
$tempArray['Lat'] = $row['Lat'];
$tempArray['Lng'] = $row['Lng'];
$tempArray['Tipologia'] = $row['Tipologia'];
$tempArray['CodiceIscrizione'] = $row['CodiceIscrizione'];
$tempArray['Visitato'] = intval($row['Visitato']);
$Soggetti[] = $tempArray;
The will encode to JSON as an array of objects with the array numerically indexed from 0 based on order in result set.

You need an ORDER BY clause of your MySQL statement.
In this case you want to order by your id, and in ascending order, so;
SELECT * from your_table ORDER BY id ASC
Reference: MySQL Sorting

The problem may lie in your mysql query, try:
select * from table_name order by ID asc

Related

perform two different fetch on the same query result

I have this query:
$all = $dbh->query("SELECT DISTINCT movimenti.nome, SUM(movimenti_carta.importo)
FROM movimenti_carta JOIN movimenti ON movimenti_carta.movimento=movimenti.id
WHERE month(data)='$mese' AND year(data)='$anno' GROUP BY movimenti.nome");
It retrieves two columns from my db. What I want to do is to put each column in a separate array.
If I do:
$labels=$all->fetchAll(PDO::FETCH_COLUMN,0);
I get the values for the first column with the format I am looking for.
I tried to do:
$values=$all->fetchAll(PDO::FETCH_COLUMN,1);
after the first fetch but $all is unset by the first fetch and the result is that $values is an empty array (I was pretty sure of this but did give it a try).
I can build the arrays in php after I fetch an array with both columns but I was wondering how to get my goal using PDO api.
Of course it will never work this way, as fetchAll() returns data only once.
The only idea I could think of is PDO::FETCH_KEY_PAIR constant:
$data = $all->fetchAll(PDO::FETCH_KEY_PAIR);
$labels = array_keys($data);
$values = array_values($data);
It feels like you are overcomplicating this. It's easily done in PHP, and if you just use PDOStatement::fetch, you don't need to worry about array manipulation; it will also be more friendly to your memory usage if you have a lot of data.
$labels = [];
$values = [];
while ($row = $all->fetch(PDO::FETCH_NUM)) {
$labels[] = $row[0];
$values[] = $row[1];
}
Maybe you could use array_column.
$all = $dbh->query("
SELECT DISTINCT movimenti.nome, SUM(movimenti_carta.importo) AS importo
FROM movimenti_carta
JOIN movimenti ON movimenti_carta.movimento=movimenti.id
WHERE month(data)='$mese'
AND year(data)='$anno'
GROUP BY movimenti.nome
");
// set of results indexed by column name
$results = $all->fetchAll(PDO::FETCH_ASSOC);
// set of values from the column 'nome'
$nomes = array_column($results, 'nome');
// set of values from the column 'importo'
$importos = array_column($results, 'importo');

Dynamic multi-diemnsional array sorting

Hello everyone I have a simple question. How to choose by string which column of multidimensional array to sort. Here is some informations you should know.
I have table with eshops data and a function which shows me orders for particular eshop like this
$sql = mysql_query("SELECT * FROM eshops WHERE active = 1");
while($data = mysql_fetch_assoc($sql)){
$res = showOrders($data['host'],$data['user'],$data['pass'],$data['db'],$data['prefix']);
echo $res;
}
This was my first try how to show all orders i made filters by passing sql condition to my function. But then i wanted to sort the result, and Here comes the problem i can sort every eshop but i want to sort all eshops at once it means that if i sort them by order date the eshops mix up but that is not possible right now so i made this.
Example:
$GLOBALS['container'] = array();
and in a function i put datas to array like this
$GLOBALS['container'][] = array($data['eshop_id'],$data2['order_id']
,$data2['order_status'],$data2['order_number'],$data2['d_f_name'],$data2['d_l_name']
,$data2['order_total'],$data2['payment_method_id'],$data2['shipping_method_id']
,$data2['Exportovano'],$data2['C_Baliku'],date("d.m.Y",strtotime($data2['order_date'])));
Then i sort i like that
foreach($GLOBALS['container'] as $key => $datas){
$eshop_id[$key] = $datas[0];
$order_id[$key] = $datas[1];
$order_st[$key] = $datas[2];
$order_nm[$key] = $datas[3];
$d_f_name[$key] = $datas[4];
$d_l_name[$key] = $datas[5];
$order_tl[$key] = $datas[6];
$pay_m_id[$key] = $datas[7];
$shp_m_id[$key] = $datas[8];
$exported[$key] = $datas[9];
$parc_num[$key] = $datas[10];
$ord_date[$key] = $datas[11];
}
array_multisort($ord_date, SORT_DESC,$d_f_name, SORT_ASC, $GLOBALS['container']);
Here we go now i can sort as i wish then by foreach container select order by order also adding a condition but how to choose what i want to sort? P.e. i pass data by get
?sort=ord_date&orn=asc
I want sort ord_date variable ascending how? PLease help me thanks.
I am also open for other solutions.
It will be easier to write in SQL query, just after WHERE statement use a ORDERED BY (column) statement.
EDIT:
Using ORDER BY statement

Extract a specific value from this data type

I'm using this script to get data from a database
$sql = "SELECT * FROM items WHERE catid = 1";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)){
echo $row['extra_fields'];
}
The output is:
[{"id":"1","value":"johndoe"},{"id":"2","value":"marydoe"}]
I want to extract/print only the value corresponding to "id":"1" (that in this case is 'johndoe'). I'm not able to extract it from the above data type.
To read JSON in PHP use
while($row = mysql_fetch_array($result)){
$array = json_decode($row['extra_fields'];
// Do something with $array['id']
}
Did you realise you can directly go for that data in MySQL?
SELECT value FROM items WHERE id = 2;
edit:
Basically your query is
SELECT comma-separated column names or star for all, use only what you really need to save bandwidth, e.g. SELECT id, value
FROM table-name, e.g. FROM mytable
WHERE columnname = desired value, e.g. WHERE id = 2
You want to query only the required columns in the required rows. Imagine one day you would have to parse 1 million users every time you want to get an id... :)
The output is JSON. Use PHP's json_decode function.
while($row = mysql_fetch_array($result)){
$array = json_decode($row['extra_fields']);
foreach($array AS $item) {
echo $item['id'];
}
}
Currently this is the code that fits my needs:
while($row = mysql_fetch_array($result)){
$array = json_decode($row['extra_fields']);
$value = $array[0]->value;
}
You should do it in the mysql query part. For example, set the ID = 1 in the query.

Sum the entries of items with the same index ID in a multi-dimensional array?

I have a multidimensional array that contains a variable number of sub arrays.
Each sub-array contains a list of numeric keys and values.
I have a separate array that is the result of an "array_intersect_key" function against the multidimensional array that contains only the keys that exist in each sub-array.
I want to walk through the intersect_key array and for each item in it sum the values associated with the matching keys within the multidimensional array and then take the total and use that to replace the value associated with the key in the intersect_key array while maintaining the same index id.
The key in each array relates to the id of an article in the database, the value associated with the key is how many times a certain word appears in that article. I'm trying to add together all the word counts relating to each article so I can then order them by relevance.
The code that creates the arrays:
$arr_articles = array();
foreach($arr_words as $wordid => $word) {
$query = "SELECT articleid,wordcount FROM index_wordsearch AS iws WHERE iws.keywordid = '$wordid'";
$articlesearch = mysql_query($query);
if (!$articlesearch) {
die('Unable to search for articles matching the specified words: '.mysql_error());
} else {
$arr_ids = array();
while ($row = mysql_fetch_assoc($articlesearch)) {
$articleid = $row['articleid'];
$wordcount = $row['wordcount'];
$arr_ids["$articleid"] = "$wordcount";
}
$arr_aticles[] = $arr_ids;
}
}
$arr_matches = call_user_func_array('array_intersect_key',$arr_articles);
I've started trying to tackle this by using the call_user_func_array() call again to branch out to a custom function but this approach doesn't feel right.
Maybe replace
$arr_ids["$articleid"] = "$wordcount";
with
if (!isset($arr_ids[$articleid]))
$arr_ids[$articleid] = 0;
$arr_ids[$articleid] += $wordcount;
I suggest for performance, that you retrieve all required data with a single SQL query (maybe using WHERE iws.keywordid IN (...)) and then process results in a PHP loop. Generally speaking, putting an SQL query in a loop should be avoided.
EDIT suggestion:
$query = "SELECT articleid, SUM(wordcount) AS wordcount
FROM index_wordsearch
WHERE keywordid IN (".implode(", ", array_keys($arr_words)).")
GROUP BY articleid";
$articlesearch = mysql_query($query) or die('Unable to search for articles matching the specified words: '.mysql_error());
$arr_articles = array();
 
while ($row = mysql_fetch_assoc($articlesearch))
$arr_articles[$row['articleid']] = $row['wordcount'];
print_r($arr_articles); // shows total matched word count for each article id

php & mysql - loop through columns of a single row and passing values into array

I have a mysql table with columns id, f1, f2, f3, ..., f20 where id is productID and f1,...f20 are product features. Depending on each product, some might have all, none or only some columns filled.
Each column holds a delimited string like a#b#c#d where a,b,c,d are values in different languages (a=english, b=french etc)
I need to select a row by it's id, explode each column's value (f1,f2...) with '#' in order to get the language part I need and then pass the values to an array in order to use in my product spec page.
How do I loop through the fetched row (i'm using $row = my_fetch_array) and put the exploded value into a one dimension array like $specs=('green', 'M', '100', 'kids'...) etc?
PS:I know, is complicated but I cant come up with a better idea right now.
Try this:
$result = mysql_query("...");
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$arr = array();
foreach ($row as $k=>$v)
{
$features = explode("#", $v);
$value = $features[1]; // get the specific language feature
$arr[] = $value;
}
$specs = join(", " , $arr);
}
Not sure this is the best way togo but you could define an array with your langs, then access the result by lang
<?php
$langs=array('eng'=>0,'fr'=>1,'ger'=>2,'geek'=>3);
while ($row=mysql_fetch_assoc($result)) {
$specs=explode('#',$row['f1']);
$other=explode('#',$row['f2']);
...
}
//Get lang from cookie that you could set elsewhere
$lang=(isset($_COOKIE['lang']))?$_COOKIE['lang']:'eng';
echo $specs[$langs[$lang]];
?>
My solution for how I understand you question:
// Make a MySQL Connection
$sQuery = "SELECT f1,f2,... FROM table WHERE id = ...";
$oResult = mysql_query($sQuery) or die(mysql_error());
//Fetch assoc to use the column names.
$aRow = mysql_fetch_assoc($oResult);
//Prepare the product properties array
$aProductProperties = array("English"=>array(),"French"=>array(),"Dutch"=>array());
//Loop over all the columns in the row
foreach($aRow as $sColName=>$sColVal){
//Explde the column value
$aExplodedCol = explode("#",$sColVal);
//The code below could be nicer when turned into a looped that looped over every language,
//But that would make the code less readable
$aProductProperties['English'][$sColName] = $aExplodedCol[0];
$aProductProperties['French'][$sColName] = $aExplodedCol[1];
$aProductProperties['Dutch'][$sColName] = $aExplodedCol[2];
}
//Done, you should now have an array with all the product properties in every language

Categories