I want to execute an SQL query like:
select 'tb1'.'f1','tb1'.'f2','tb2'.'f1' from 'tb1','tb2';
Now the problem is that i want to put it into an array in PHP like:
$result['tb1']['f1'], $result['tb1']['f2'], $result['tb2']['f1']...
Any idea how to achieve the above? Afaik there is no function which does the above. I was wondering the best simple way to do it. I do not want to use a query like "select .. as .. " unless necessary.
I do not know in advance what the fields will be, so I cannot assign them manually as suggest by the answer by benlumley.
Thank you,
Alec
You'll need to select the data as you are already doing, and then loop over it getting it into the format required, and because the fields have the same names, its easiest to use aliases or they'll just overwrite each other in the returned data (but you could use mysql_fetch_row instead, which returns a numerically indexed array).
For example:
$sql = "select tb1.f1 as tb1f1,tb1.f2 as tb1f2,tb2.f1 as tb2f1 from tb1,tb2";
$result = mysql_query($sql);
while ($row = mysql_fetch_assoc($result)) {
$result['t1']['f1']=$row['tb1f1'];
$result['t1']['f2']=$row['tb1f2'];
$result['t2']['f1']=$row['tb2f1'];
}
(The quoting was wrong in your sql as well)
That won't handle multiple rows either, but your question sort of implies that you are only ever expecting one row?
WIthout aliases:
$sql = "select tb1.f1,tb1.f2,tb2.f1 from tb1,tb2";
$result = mysql_query($sql);
while ($row = mysql_fetch_row($result)) {
$result['t1']['f1']=$row[0];
$result['t1']['f2']=$row[1];
$result['t2']['f1']=$row[2];
}
I prefer the first version unless you have a good reason to use the second, as its less likely to result in errors if you ever change the sql or add fields etc.
EDIT:
Taking the meta data idea from the response below ....
<?php
mysql_connect('localhost', 'username', 'password');
mysql_select_db('dbname');
$result = mysql_query('select tb1.f1, tb1.f2, tb2.f1 from tb1, tb2');
$meta = array();
for ($i = 0; $i < mysql_num_fields($result); ++$i) {
$meta[$i] = mysql_fetch_field($result, $i);
}
while ($row = mysql_fetch_row($result)) {
foreach($row as $key=>$value) {
$out[$meta[$key]->table][$meta[$key]->name]=$value;
}
}
seems to do exactly what you are after - although you can still only get one row at a time.
Easily updated to store multiple rows with another dimension on the array:
Change:
$out[$meta[$key]->table][$meta[$key]->name]=$value;
To:
$out[][$meta[$key]->table][$meta[$key]->name]=$value;
Since you say you can't specify column aliases, and you can't know the fields of the query beforehand, I'd suggest a solution using mysql_fetch_field() to get metadata information:
<?php
mysql_connect('localhost', 'username', 'password');
mysql_select_db('dbname');
$result = mysql_query('select tb1.f1, tb1.f2, tb2.f1 from tb1, tb2');
for ($i = 0; $i < mysql_num_fields($result); ++$i) {
$meta = mysql_fetch_field($result, $i);
print_r($meta);
}
You can extract from this metadata information the table name and column name, even when there are multiple columns of the same name in the query.
PHP's ext/mysqli supports a similar function mysqli_stmt::result_metadata(), but you said you can't know the number of fields in the query beforehand, which makes it awkward to use mysqli_stmt::bind_result().
PDO_mysql doesn't seem to support result set metadata at this time.
The output from the above script is below.
stdClass Object
(
[name] => f1
[table] => tb1
[def] =>
[max_length] => 1
[not_null] => 0
[primary_key] => 0
[multiple_key] => 0
[unique_key] => 0
[numeric] => 1
[blob] => 0
[type] => int
[unsigned] => 0
[zerofill] => 0
)
stdClass Object
(
[name] => f2
[table] => tb1
[def] =>
[max_length] => 1
[not_null] => 0
[primary_key] => 0
[multiple_key] => 0
[unique_key] => 0
[numeric] => 1
[blob] => 0
[type] => int
[unsigned] => 0
[zerofill] => 0
)
stdClass Object
(
[name] => f1
[table] => tb2
[def] =>
[max_length] => 1
[not_null] => 0
[primary_key] => 0
[multiple_key] => 0
[unique_key] => 0
[numeric] => 1
[blob] => 0
[type] => int
[unsigned] => 0
[zerofill] => 0
)
Prefixing field names with short version of table name is a good way to achieve it without the need to create aliases in select. Of course you don't get the exact structure that you described but every field has its unique named index in result array. For example, let's assume you have table users, and the user has a name, then call this field usr_name.
Related
I am using PHP PDO extension to create a list of all items from a DB category table.
The expected results are not correct, only one row of data returned instead of all
rows which is expected.
By running the same SQL statement within the phpMyAdmin console I get the expected
results for all rows of data.
I need to know what I am overlooking with pdo.
Current code:
$catId = 0;
$sql = "SELECT *
FROM category
WHERE cat_parent_id = :catId
ORDER BY cat_name";
$_stmt = $this->_dbConn->prepare($sql);
$_stmt->bindParam(":catId", $catId, PDO::PARAM_INT);
$_stmt->execute();
$rows = $_stmt->fetch(PDO::FETCH_ASSOC);
// display PDO result - only getting one row instead of all rows.
print_r($rows);
Array ( [cat_id] => 3
[cat_parent_id] => 0
[cat_name] => Shop
[cat_description] => Seminars
[cat_image] => c72e.gif
)
// NOTE: By running the same SQL within the phpMyAdmin
// console I get the expected results with all rows.
Array ( [cat_id] => 3
[cat_parent_id] => 0
[cat_name] => Shop
[cat_description] => Seminars
[cat_image] => c72e.gif
),
( [cat_id] => 1
[cat_parent_id] => 0
[cat_name] => Site Map
[cat_description] => List content links
[cat_image] => c83b.gif
)
PDOStatement::fetch() will only return 1 row at a time.
You could use PDOStatement::fetchAll():
$rows = $_stmt->fetchAll(PDO::FETCH_ASSOC);
or create a loop where you keep calling PDOStatement::fetch() until it returns false:
$rows = array();
while( $row = $_stmt->fetch(PDO::FETCH_ASSOC) ) {
$rows[] = $row;
}
But the latter example is a bit redundant, if you want to get all rows at once anyway, unless there are some memory concerns you want to address.
You have to use fetchAll like below:
$rows = $_stmt->fetchAll();
print_r($rows);
I have an multidimensional array made from database query and is like that:
Array
(
[0] => Array
(
[0] => -8.63296022565696
[x] => -8.63296022565696
[1] => 41.1584289069069
[y] => 41.1584289069069
[2] => 0
[seq] => 0
[3] => 2
[seq2] => 2
[4] => -8.63306031211831
[next_x] => -8.63306031211831
[5] => 41.1584543235506
[next_y] => 41.1584543235506
[6] => -8.64195115878864
[alert_x] => -8.64195115878864
[7] => 41.1599295066425
[alert_y] => 41.1599295066425
[8] => 54e728edafac1
[route] => 54e728edafac1
[9] => 54e728edafac1
[routeid] => 54e728edafac1
[10] => 2
[counttargetinter] => 2
[11] => passeio
[type] => passeio
[12] => 1355
[arcid] => 1355
)
All the values are repeated because have a key number and a key name.
Example: The value '-8.63296022565696' are in key "0" and "X".
How I can remove the duplicated?
This is how i made the array:
$query = "SELECT * FROM foo;";
$startRows = pg_query($connection, $query);
$startInfo = array();
while($list = pg_fetch_array($startRows)) {
$startInfo[] = $list;
}
Of course you can't mess with the generate JSON string to deal with the dups. You solve it during the creation of the array itself before encoding. Looking at the structure, this seems to be the problem of fetching both numeric and column indices.
Since you haven't posted any codes related to actually creating this JSON string, just use this basic idea on how to get rid of them.
If you intent do remove those numeric indices, you'll probably need to use fetch_assoc() flavours of your database API, so that in turn, you'll only get the column name indices instead of having them both.
Here's the idea:
$data = array(); // initialization of the container
while($row = your_fetch_assoc($result)) { // use assoc() instead to exclude those numeric indices
$data[] = $row;
}
echo json_encode($data);
Depending on what API you're using, if its PDO, either use -->fetch(PDO::FETCH_ASSOC) or just ->fetchAll(PDO::FETCH_ASSOC) without the need of a loop. If its MySQLi, then just use ->fetch_assoc()
EDIT: At last your codes, as I have suspected you're using _array() function which results associative and numeric indexed rows.
$query = "SELECT * FROM foo;";
$startRows = pg_query($connection, $query);
$startInfo = array();
while($list = pg_fetch_assoc($startRows)) {
$startInfo[] = $list;
}
Use pg_fetch_assoc() instead of _array() so that you'll get the associative indices only.
Like Ghost:
You can use pg_fetch_row() to get numeric indices or pg_fetch_assoc() to get field name.
$query = "SELECT * FROM foo;";
$startRows = pg_query($connection, $query);
$startInfo = array();
while($list = pg_fetch_row($startRows)) {
$startInfo[] = $list;
}
Try this:
foreach($walkroute as $routepoints){
foreach($routepoints as $key => $value){
if (is_int($key)){
unset($routepoints[$key]);
}
}
}
You have to modify it due to the fact that i don't know, what the structure and names of your array actually are.
In doctrine DBAL2 when I execute a query like this:
<?php
$connection = $this->getDatabaseConnection();
$sql = "SELECT page_url
FROM cms_user_page
WHERE site_id = :siteid
AND active = '1'
";
$stmt = $connection->prepare($sql);
$stmt->bindValue("siteid", $id);
$stmt->execute();
return $stmt->fetchAll();
?>
I get a result like this:
Array
(
[0] => Array
(
[page_url] => index.php?action=login
)
[1] => Array
(
[page_url] => index.php?action=shoppingcart
)
[2] => Array
(
[page_url] => index.php?action=products
)
)
My question is, is there a fetch mode that produces an result like this:
Array
(
[0] => index.php?action=login
[1] => index.php?action=shoppingcart
[2] => index.php?action=products
)
I could not find any info about fetch modes in the documentation. and i could do an array map. But thats overhead in my opinion..
You can pass a fetch mode parameter to fetchAll().
$stmt->fetchAll(\PDO::FETCH_COLUMN)
This answer has been edited because this answer is correct.
You can use the FETCH_COLUMN fetch mode in fetchAll():
$stmt->fetchAll(\PDO::FETCH_COLUMN)
As another user points out in the comments, fetchAll() can return data formatted in a multitude of interesting formats.
Or you can iterate with fetchColumn():
while($page_url = $stmt->fetchColumn()) {
echo $page_url . PHP_EOL;
}
As of PHP5.5 you could use aray_column to achieve required result like so:
<?php
$connection = $this->getDatabaseConnection();
$sql = "SELECT page_url
FROM cms_user_page
WHERE site_id = :siteid
AND active = '1'
";
$stmt = $connection->prepare($sql);
$stmt->bindValue("siteid", $id);
$stmt->execute();
$data = array_column($stmt->fetchAll(), 'page_url');
return $data;
If you have more than one case where you need that form of result, although i dont really understand the sense too, you could implement AbstractHydrator interface to create your own ArrayHydrator that returns the structure as you need it.
Hydration Classes reside in NS:
Doctrine\ORM\Internal\Hydration
It looks like fetchAll was made deprecated in a recent version of DBAL. However I found another method called fetchFirstColumn which appears to do the same thing as fetchAll(\PDO::FETCH_COLUMN). I am currently on version 2.11.1 Doctrine DBAL.
I am using it like this in Symfony:
$statement = $connection->prepare('SELECT foo FROM bar WHERE baz = :baz');
$statement->execute([':baz' => 1]);
$result = $statement->fetchFirstColumn();
The value of $result will be a numerically indexed array starting at 0 like this:
[
0 => 'foo1',
1 => 'foo2'
];
As soon as you're requesting multiple rows in a database it does not make sense.
RDBMS stores rows and columns so the result is represented as rows and columns.
In the programming world it is called a matrix, in the PHP world it is an array.
________________
| id | name |
|______|_________|
| 1 | foo |
|______|_________|
| 2 | bar |
|______|_________|
will results in
array(
0 => array(
'id' => 1,
'name' => 'foo',
),
1 => array(
'id' => 2,
'name' => 'foo',
)
);
So no, you can't do that, you'd rather to process the result to fit your needs.
I am pulling some data from a mysql table via the following:
$result = mysql_query("SELECT characters_ID, name, borndate, deathdate, marrieddate, ispregnant FROM characters WHERE isfemale='1'",$db);
$femaledata = array();
while ($row_user = mysql_fetch_assoc($result))
$femaledata[] = $row_user;
This gives me an array that looks like this:
Array (
[0] => Array ( [characters_ID] => 2 [name] => Helene [borndate] => 35 [deathdate] => 431 [marrieddate] => 157 [ispregnant] => 0 )
[1] => Array ( [characters_ID] => 4 [name] => Isabelle [borndate] => 161 [deathdate] => [marrieddate] => 303 [ispregnant] => 1 )
[2] => Array ( [characters_ID] => 7 [name] => Helene [borndate] => 326 [deathdate] => [marrieddate] => [ispregnant] => 0 )
[3] => Array ( [characters_ID] => 72 [name] => Faylinn [borndate] => 335 [deathdate] => [marrieddate] => [ispregnant] => 0 )
[4] => Array ( [characters_ID] => 74 [name] => Relina [borndate] => 349 [deathdate] => [marrieddate] => [ispregnant] => 0 )
)
Now I need to remove any characters who have a value for deathdate or ispregnant, and then I need to run some code on the others. For instance I need to grab the borndate value, compare it to the current date to find age, and based partly on age, I need to run code for each to determine if the character has become pregnant on the turn.
Apologies that this seems like a long-reaching question. Multidimensional arrays still seem to confound me.
Edit: (question needs to be more clear)
Can you please suggest the best way that I would either explode or break up the array, and then do conditional modification to the data, or instead how I could remove unneeded data and then do conditional modification to the data.
My ultimate output here would be taking suitable female characters (not dead or pregnant already), and based on their age, giving them a chance at becoming pregnant. If true, I'd throw some code back at the SQL database to update that character.
Thanks!
All the things you need could probably get done with SQL :
Now I need to remove any characters who have a value for deathdate or
ispregnant
Simply add some argument to your WHERE condition :
isPregnant IS NULL AND deathdate IS NULL
For instance I need to grab the borndate value, compare it to the
current date to find age
Depending of your field format the maths could be done in SQL , have look to the DATE function of mysql
Don't underestimate the power of your sql server , 99% of the time it is probably faster than php to work on data set.
Instead if immediately removing some rows from your array, try limiting the data you recieve through SQL.
You can loop through your array like this:
foreach($femaledata as $female)
{
echo $female['name'];
}
do you mean something like this?
$femaledata = array();
while ($row_user = mysql_fetch_assoc($result)) {
$ok = false;
// do you validation for every user
if($ok) array_push($femaledata,$row_user);
}
TJHeuvel gave you the right answer, and you should accept that answer. However, to inform: multidimensional arrays need not confound. Let me see if I can explain.
In PHP, you can put any object at all into an array, including other arrays. So, let's say you have an array that contains other arrays. When you iterate over that array using a looping construct (usually a foreach loop), each iteration of the loop will give you another array; if you want to access the elements of this sub-array, just loop over it. This is called a nested loop. Example:
$r = array(
array(1,2,3),
array(4,5,6),
array(7,8,9)
);
foreach ($r as $cur) {
foreach ($cur as $num) {
echo $num;
}
}
In each iteration of the outer loop, $cur contains an array; the inner loop iterates over contents of this array. This technique allows you to process arrays of any dimension.
However, in your specific case, you don't need to use an inner loop to iterate over your subarrays. You only need to access certain elements of your subarrays by their keys, rather that processing all of them in turn. So, a simple foreach loop will do.
For some reason my array I am returning is not what I expect. Could someone explain to me why I am getting the current results, and what I can do to fix it? Here is the code in question:
public static function getProduct($_row, $_value)
{
$stmt = _DB::init()->prepare("SELECT pid, name, quantity, price, cost
FROM products
WHERE $_row = ?"
);
if($stmt->execute(array($_value)))
{
while ($row = $stmt->fetch())
return $row;
}
}
$product = Class::getProduct('pid',1);
print_r($product);
When I print the following array I am getting two results per row like so:
Array ( [pid] => 1 [0] => 1 [name] => Boondoggle [1] => Boondoggle [quantity] => 12 [2] => 12 [price] => 9.9900 [3] => 9.9900 [cost] => 12.9900 [4] => 12.9900 ) Boondoggle
I was only wanting to show the associative results. What is wrong with my function?
From the looks of it you are using PDO to communicate with your DBMS. The PDOStatement::fetch() method's first argument is a parameter to tell it what to return. By default it returns each column in both name format and numbered index format to allow iterating through columns easier. To just get the column names as indexes, you can pass it PDO::FETCH_ASSOC to your call. So the fetch statement would look like this:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)
See here for more details:
http://www.php.net/manual/en/pdostatement.fetch.php
Pass PDO::FETCH_ASSOC to your fetch call:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
edit: I'm just assuming you're using PDO, of course