To give some context, a little while ago with the help from VolkerK on this very site I created a function that queries an Oracle database and places the content into a neatly formatted PHP array, depending on the index. Here's the original question.
The problem is, in some cases I just want to return a single value from a quick query, and when I do I get the the following error: Notice: Undefined index:
Here's the code I'm using:
function oracleGetData($query, $id = null) {
global $conn;
$results = array();
$sql = OCI_Parse($conn, $query);
OCI_Execute($sql);
while ( false!==($row=oci_fetch_assoc($sql)) ) {
$results[ $row[$id] ] = $row;
}
// remove one layer if there's only one record
if(count($results) == 1 and is_null($id)) {
$results = array_pop($results);
}
return $results;
}
I have tried changing the line that populates the array like so:
if(is_null($id)) {
while ( false!==($row=oci_fetch_assoc($sql)) ) {
$results[ $row ] = $row;
}
} else {
while ( false!==($row=oci_fetch_assoc($sql)) ) {
$results[ $row[$id] ] = $row;
}
}
Basically if the $id variable is null, remove all references to it, but then I get a 'Warning: Illegal offset type' error.
Any help would be much appreciated, I've tried passing in the single field I require into the function but get the same error.
Thank you
Perhaps if $id is NULL you could just use sequential numbers for the indexes, as in:
function oracleGetData($query, $id = null)
{
global $conn;
$results = array();
$sql = OCI_Parse($conn, $query);
OCI_Execute($sql);
if(is_null($id)) {
$idx = 1;
while (false!==($row=oci_fetch_assoc($sql))) {
$results[ $idx ] = $row;
$idx = $idx + 1;
}
} else {
while ( false!==($row=oci_fetch_assoc($sql))) {
$results[ $row[$id] ] = $row;
}
}
// remove one layer if there's only one record
if(count($results) == 1 and is_null($id)) {
$results = array_pop($results);
}
return $results;
}
Share and enjoy.
Related
I am trying to test a few scripts that I would normally get from an SQL database but for testing offline I am just creating an array.
Here is what I have right now;
$result = array
(
array("name"=>"Toby", "q1"=>"1"),
array("name"=>"Phelps", "q1"=>"1"),
array("name"=>"Davies", "q1"=>"1"),
array("name"=>"Keith", "q1"=>"1"),
);
$resultnum = count($result);
echo "<b>Question 1</b> <br/><br/>";
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$name = $row['name'];
$answer = $row['q1'];
$q1answer = 1;
if($answer == $q1answer) {
echo $name . " got this right! <br/>";
} else {
echo $name . " got this wrong! <br/>";
}
}
}
How can I get this to work the same as though it was getting the array from an SQL query instead of just my array, for some reason I can't find a way to get this to run.
You can wrap the array in an anonymous class. Single uses like this are a main reason they exist.
$result = new class {
private $data = array
(
array("name"=>"Toby", "q1"=>"1"),
array("name"=>"Phelps", "q1"=>"1"),
array("name"=>"Davies", "q1"=>"1"),
array("name"=>"Keith", "q1"=>"1"),
);
private $data_index = 0;
public $num_rows;
public function __construct() {
$this->num_rows = count($this->data);
}
public function fetch_assoc() {
if (isset($this->data[$this->data_index])) {
$index = $this->data_index++;
return $this->data[$index];
}
}
};
Similar to the earlier answer, I propose a class. Here I would actually name the class, and pass the data to the constructor. The iteration over the array can be done with the current and next methods:
class ResultSet {
private $array = [];
public $num_rows = 0;
public function __construct($data) {
$this->array = $data;
$this->num_rows = count($this->array);
}
public function fetch_assoc() {
$val = current($this->array);
next($this->array);
return $val;
}
}
Until there it would be fixed. You would play with the data in the following:
$result = new ResultSet([
["name"=>"Toby", "q1"=>"1"],
["name"=>"Phelps", "q1"=>"1"],
["name"=>"Davies", "q1"=>"1"],
["name"=>"Keith", "q1"=>"1"],
]);
I did not implement support for count($result) as I don't think that is supported on real mysqli result sets either. You get the count via ->num_rows (like you also do).
I have got this code:
function retrieve_answers($array = array(), $id = null)
{
include(root_path . '\config.php');
if($id == null)
{
$id = $this->question_id;
}
$query = mysqli_query($link, "SELECT * FROM `answers` WHERE `question_id`='$id'");
if(!mysqli_num_rows($query))
{
throw new Exception('Question not found.');
}
/* - Retrieves the answer rows
- Loops through the array
- Indexes the array and assigns the answerID to the index */
else
{
while($result = mysqli_fetch_array($query))
{
for($i=0;$i<mysqli_num_rows($query);$i++)
{
$array[$i] = $result["id"];
}
}
}
}
Which is a part of a class.
What am I trying to do?
I am trying to accept an array as a parameter, and assign values to the array, the values are to be answerIDs which are linked to the question.
The test.php file is here:
<?php
define('root_path', realpath(dirname(__FILE__)));
include(root_path . '\config.php');
require_once(root_path . '\includes\question.class.php');
$q = new Question(3);
$array = array();
$q->retrieve_answers($array);
var_dump($array);
?>
What happens?
When I try to debug by dumping the array, it shows that the array contains nothing:
array(0) { }
I tried to execute the MySQL result through the class to debug, and it does succeed to retrieve the answer IDs, so I'm pretty positive the issue is in the array.
I would happy to get assistance, thanks in advance.
return value in a function like this
function retrieve_answers($array = array(), $id = null)
{
include(root_path . '\config.php');
if($id == null)
{
$id = $this->question_id;
}
$query = mysqli_query($link, "SELECT * FROM `answers` WHERE `question_id`='$id'");
if(!mysqli_num_rows($query))
{
throw new Exception('Question not found.');
}
/* - Retrieves the answer rows
- Loops through the array
- Indexes the array and assigns the answerID to the index */
else
{
$i = 0;
while($result = mysqli_fetch_array($query))
{
$array[$i] = $result["id"];
$i++;
}
return $array;
}
}
and then get it as
$arr = $q->retrieve_answers($array);
var_dump($arr);
What is the proper way to create a function to get array values from a query? I am getting "Undefined index: page_title" error.
However I can get the value without function like: echo $row->page_title;
Or echo $query[0]->title;
function get_page($id) {
$db = new DB();
$query = $db->get_rows("SELECT * FROM pages WHERE id = :id ", array('id' => $_GET['id']) );
foreach ($query as $row) {
$page_id = $row->id;
$page_title = $row->title;
}
return $query;
}
$page = get_page(1);
echo $page['page_title'];
here is my database class:
function get_rows($query, $values=array(), $fetchType = FETCH_OBJ)
{
$sth = $this->dbh->prepare($query);
if(is_array($values) && (sizeof($values) > 0))
{
foreach($values as $key=>$val)
{
$key = is_numeric($key) ? ($key + 1) : $key;
$sth->bindValue($key,$val);
}
}
if($sth->execute())
return $sth->fetchAll($fetchType);
}
To make the function reusable, I would rewrite it the following way
function get_page($id, $col) {
$db = new DB();
$query = $db->prepare('SELECT * FROM pages WHERE id = :id');
$query->execute(array(':id' => $id));
$results = $query->fetch(PDO::FETCH_NUM);
return $results[0][$col];
}
$page = get_page(1, 'page_title');
echo $page;
I skipped the foreach as you said that all id's are unique so you should only ever have 1 result
Also it may not be a bad idea to add some error checking to make sure you do get back what you expect from the query and to make sure it is not empty.
Edit: Sorry if the syntax is a little off, dont have anything to test the code against quickly.
I have two database tables, one for allowances and one for deductions. I want to calculate net salaries.
I'm using CodeIgniter. Here's my current code:
function get_allowances($eid)
{
$this->db->from('allowances');
$this->db->where('eid',$eid);
$query = $this->db->get();
if($query->num_rows()==1)
{
return $query->row();
}
else
{
//Get empty base parent object, as $item_id is NOT an item
$salary_obj=new stdClass();
//Get all the fields from items table
$fields = $this->db->list_fields('allowances');
foreach ($fields as $field)
{
$salary_obj->$field='';
}
return $salary_obj;
}
}
function get_deductions($eid)
{
$this->db->from('deductions');
$this->db->where('eid',$eid);
$query = $this->db->get();
if($query->num_rows()==1)
{
return $query->row();
}
else
{
//Get empty base parent object, as $item_id is NOT an item
$salary_obj=new stdClass();
//Get all the fields from items table
$fields = $this->db->list_fields('deductions');
foreach ($fields as $field)
{
$salary_obj->$field='';
}
return $salary_obj;
}
}
and in controller,
function net_salary($eid)
{
$allownces[] = $this->Salary->get_allowances($eid);
$deductions[] = $this->Salary->get_deductions($eid);
return $net_salary = array_sum($allownces) - array_sum($deductions);
}
My net_salary() function gives me a result of 0. What am I doing wrong, and how can I fix it?
Your models with plural names are only going to return a single object.
so what you are ending up with is...
Array
(
[0] => allowance_object
)
and
Array
(
[0] => deduction_object
)
While we really need the schema of your database try this (and make same edits for deductions)...
function get_allowances($eid)
{
$this->db->from('allowances');
$this->db->where('eid',$eid);
$query = $this->db->get();
if($query->num_rows()==1)
{
return $query->row_array(); //<--- return an Array
}
else
{
// make an array instead of object
$salary_obj = array();
//Get all the fields from items table
$fields = $this->db->list_fields('allowances');
foreach ($fields as $field)
{
$salary_array[$field] = 0; //<---- add array keys and set to integer 0 instead of empty string.
}
return $salary_array;
}
}
then in your net_salary function
function net_salary($eid)
{
$allownce = $this->Salary->get_allowances($eid);
$deduction = $this->Salary->get_deductions($eid);
return array_sum($allownce) - array_sum($deduction);
}
Try something like this:
function get_values($eid, $table_name)
{
$this->db->where('eid',$eid);
$query = $this->db->get($table_name);
$salary_obj = $query->result();
$values = array();
foreach($salary_obj as $row){
$values[] = $row->value_column_name;
}
return $values;
}
where value_column_name is the name of the table column (filedname) where the desired value stands.
call in controller:
function net_salary($eid)
{
$allownces = $this->Salary->get_values($eid, 'allowances');
$deductions = $this->Salary->get_values($eid, 'deductions');
return $net_salary = array_sum($allownces) - array_sum($deductions);
}
Have just come across a problem where I believe this is the solution.
At the moment I have the following code:
function siteUsers()
{
global $database;
$q = "SELECT username, id FROM ".TBL_USERS."";
return mysql_query($q, $this->connection);
}
function generateUserArray()
{
$u = array();
$i = array();
$result = $this->siteUsers();
while( $row=mysql_fetch_assoc($result))
{
$u[] = $row['username'];
$i[] = $row['id'];
}
return $u, $i;
}
As you can see, when I then go onto use foreach, the u and i get split apart.
Is there anyway that I could keep them together?
foreach ($u as $username) {
echo"<option value='$i'>$username</option>";
}
What I need it the option value to be the id and the visual value to be the username.
Is this possible?
Thanks
Use an associative array linking the ID to the username. I'm assuming here the IDs are unique.
$users = array();
while( $row=mysql_fetch_assoc($result))
{
$users[$row['id']] = $row['username'];
}
return $users;
Then:
foreach ($users as $id => $username)
{
echo "<option value='$id'>$username</option>";
}
foreach($u as $idx => $username)
{
echo"<option value='".$i[$idx]."'>$username</option>";
}
assuming equal length and that php function can return two values :\