Fetch Object Only Returning 1 Value - php

Hi Guys I am having trouble on fetching object please see my code below.
Table Animals
-----------------------
id | type | name
-----------------------
1 Cat Muning
2 Kookaburra Bruce
3 Dog Bruce
-----------------------
Animal.php
class Animal extends DatabaseObject{
static $db_fields;
static $table_name = 'animals';
public function animal_group(){
global $database;
$sql = "SELECT animal_name as ani_name, COUNT(animal_name) as quantity FROM " . static::$table_name . " GROUP BY animal_name";
$stmt = $database->query($sql);
return $result = $database->fetch_object($stmt);
}
}
$animal = new Animal();
index.php
<?php
require_once('includes/database.php');
require_once('includes/animal.php');
$ani = $animal->animal_group();
echo $ani->ani_name . " - " . $ani->quantity;
?>
Result
Bruce - 2
What it should be
Bruce - 2
Muning - 1
I also tried While and Foreach but still didn't work.

fetch_object returns one row as an object. If you want to get all of them you have to call it in a loop, or otherwise use another method that returns all the rows from the result set (if you are using mysqli, that would be fetch_all).

Are you using PDO?.
Use fetchAll() instead of fetch_object.

Related

SELECTING multiple rows by 2 columns

[ POSTS ]
| id | title | class |
|----|----------|-------|
| 1 | 4567 | 2 |
| 2 | 1234 | 1 |
| 3 | 9124 | 1 |
| 3 | 9124 | w |
________________________
How can i SELECT multiple class column values and sort it to be echoed in HTML like
$query = "SELECT * FROM posts WHERE id = :id"
$statment= $conn->prepare($query);
$statment->execute([':id' => $id]);
while($row = $stmt->fetch()){
$title1 = $row['title'] //WHERE THE CLASS IS 1
$title2 = $row['title'] //WHERE THE CLASS IS 2
echo"
<a>$title1</a>
<a>$title2</a>
}
How do specify which title appear by its class? i already used the id but i want to use the class like
$title1 = $row['id'], AND $row['class'] = 1
$title2 = $row['id'], AND $row['class'] = 2
$titleo = $row['id'], AND $row['class'] = w
to sort it while echo or do i have to go
$query = "SELECT * FROM posts WHERE id = :id AND class = 1"
$query = "SELECT * FROM posts WHERE id = :id AND class = 2"
$query = "SELECT * FROM posts WHERE id = :id AND class = 'w'" //FOR STRINGS
I think you are looking for
SELECT * FROM Posts WHERE class in (1,2,'w') ORDER BY class ASC
This will give you all the posts with the class values within the In () statement. It will show each record separately which means you will have two rows for titles which have multiple class values. Since it looks like you want to separate them using PHP that should be ok. Then you can do that in your while loop like:
$classes = array();
while($row = $stmt->fetch()){
if(!isset($classes[$row['class']])){ $classes[$row['class']] = array(); }
$classes[$row['class']][] = $row['title'];
}
This would give you arrays of Titles for each class:
[
1=>[1234,9124]
2=>[4567]
'w'=>[9124]
]
Then you can output them all in order of the class or by class:
foreach($classes as $key => $class){
echo "Class Value: ".$key; // just to show the order
foreach($class as $title){ echo "<a>".$title."</a>"; }
}
Which will wind up giving you:
Class Value: 1
<a>1234</a>
<a>9124</a>
Class Value: 2
<a>4567</a>
Class Value: w
<a>9124</a>
I am not entirely sure if this leads you to what you are looking for, however, it does give you a workflow to be able to order the posts by class and output them based on class. I hope this helps

Make hierarchy from table with PHP

I have a table in database and in this table i have added 3 columns that is i, name,parent_id.please see below.
ID | name | parent_id
1 name1 0
2 name2 1
3 name3 1
Now i want to fetch this id from database. I have created a method in PHP and fetch data one by one from database. Please see below
function getData($id)
{
$array = array();
$db = JFactory::getDBO();
$sql = "SELECT * from table_name when id = ".$id;
$db>setQuery($sql);
$fetchAllDatas = $db->getObjectList();
foreach ($fetchAllDatas as $fetchAllData)
{
if($fetchAllData->parent_id > 0)
{
$array[$fetchAllData->parent_id] = $fetchAllData->name;
$this->getData($fetchAllData->parent_id);
}
else
{
$array[$fetchAllData->parent_id] = $fetchAllData->name;
}
}
return $array;
}
Now if i call this method with id 3 like
$this->getData(3); // has a parent
It will return like that
Array(
[0]=>name1
)
But i want like below
Array(
[1]=>name3,
[0]=>name1
)
I know i have redefine array if we have parent but how i manage it.
i have used array_push php function but its not work with my condition.
foreach ($fetchAllDatas as $fetchAllData)
{
$array[$fetchAllData->parent_id] = $fetchAllData->name;
if($fetchAllData->parent_id > 0)
array_push($array,$this->getData($fetchAllData->parent_id));
}
return $array;
1)Because you do $array[$fetchAllData->parent_id] = $fetchAllData->name; in the if and in the else, you do this in both cases so put out of if..else.
2) Try to push the result of your second call in the original array to get what you want.
you have unique ID in your table, so if you call your query it will always return only one result. Maybe you wanted to write query this way:
$sql = "SELECT * from table_name when parent_id = ".$id;
if you want to get the result with given ID and his parent, you should add this after calling $this->fetchSharedFolder(...);
$array = array_merge($array, $this->getData($fetchAllData->parent_id));

how to select all data from mysql table where column is an array or single and my value match with one item of this array?

Please could someone help me? I want to select all values in mysql table where the column that i want to check get a value is mix with aingle or array of values....... So to be more clear I have a table to store all messages from many sender to one or many reciever....
my functions is
public static function find_messagesTo_by_user_id($mess_to=0) {
global $database;
$mess_to = $database->escape_value($mess_to);
$sql = "SELECT * FROM ".self::$table_name;
$sql .= " WHERE mess_to = '{$mess_to}'";
$sql .= " AND mess_deleted = 0";
$sql .= " ORDER BY mess_created_date DESC";
$result_array = parent::find_by_sql($sql);
return $resultrray;
}
So 'mess_to ' has array and single value .... they are only numbers Like (1, 15, 25 ,26 ,27 , array(1,25, 27) , 31, 42, .......)
Please, i break my head on it :)
I waiting for any help?
Building on #Maluchi's answer. Make sure your data looks like:
| mess_to |
+-----------------+
| ,123, |
| ,123,456,152,1, |
| ,456,567, |
| ,3, |
So surround each value in ,. then you can safely do:
WHERE `mess_to` LIKE "%,{$mess_to},%"
This ensures that $mess_to = 1 will match only the 2nd row, and not the 1st as well.
You could also denormalize your data and make a table to JOIN on.
If I'm reading it correctly, $mess_to is passed into the function and could contain either a single value or it could be passed in an array.
When matching multiple values, the SQL should be looking for a comma-separated list. The where clause needs to be IN the list rather than EQUAL to the list.
Try:
public static function find_messagesTo_by_user_id($mess_to=0) {
global $database;
$mess_to = $database->escape_value($mess_to);
$sql = "SELECT * FROM ".self::$table_name;
$sql .= " WHERE mess_to IN (" . implode(',', $mess_to) . ")";
$sql .= " AND mess_deleted = 0";
$sql .= " ORDER BY mess_created_date DESC";
$result_array = parent::find_by_sql($sql);
return $resultrray;
}
See this line in particular:
$sql .= " WHERE mess_to IN (" . implode(',', $mess_to) . ")";
Code edited with geomagas's comments! (Thank you geomagas!)
asuming your column is like this
| mess_to |
+---------+
| 1 |
| 1,2,3,4 |
| 2 |
| 3 |
you can use the LIKE operator:
$sql .= " WHERE mess_to LIKE '%{$mess_to}%'";
this will match every row where mess_to has the string value of $mess_to (your column data type should be string for this to work).

Mysql joining 1 row with multiple rows - group concat or php?

Consider the following example:
+----------+--------+-------------+----------+
| Person_id| Person | Language_id | Language |
+----------+--------+-------------+----------+
| 1 | Bob | 5 | English |
| 1 | Bob | 3 | Italiano |
| 1 | Bob | 8 | Deutsch |
+----------+--------+-------------+----------+
and the query is (not that important, just scripting to show you the table structure):
SELECT pl.Person_id, Person, Language_id, Language FROM people as p
LEFT JOIN people_languages as pl ON p.Person_id = pl.Person_id
LEFT JOIN languages as l ON pl.language_id = l.language_id
WHERE pl.Person = 1;
So basically, if the tables are constructed in this way, is it better to retrieve all results as shown above and then create a php function that creates a Person Model with languages_id and languages in an array, or using group_concat to retrieve a single row and then explode the languages and languages_id into an array?
By the way, no matter what I do, at the end I'd like to have a Person Model as the following:
class Person {
public $person_id; // 1
public $person; // Bob
public $language_id; // Array(5, 3, 8)
public $language; // Array(English, Italiano, Deutsch);
.
. // Functions
.
}
I think you should separate the queries into their separate model
There should be a Language model and will keep this simple
class Language
{
function getId() { return $id; }
function getDescription { return $description; }
}
class Person {
public $person_id; // 1
public $person; // Bob
public $languages; //this will store array of Language object
}
//From DataAccess
function getPerson($person_id)
{
$person = new Person();
//select only from Person table
//fill $person properties from records
//$person.person_id = $row['person_id']; etc
//select from people_languages joined to language where person_id=$person_id
$person->languages = getLanguagesByPerson($person->person_id); //returns array of languages
return $person;
}
You can now have
$person = getPerson(123);
$person->langauges[0]->getId(); //language id
$person->langauges[0]->getDescription(); //language id
$person->langauges[1]->getId(); //language id
$person->langauges[1]->getDescription(); //language id
Or loop through the languages
foreach($person->languages as $lang)
{
//use($lang->getId());
//use($lang->getDescription();
}
Here is the answer. You can use both ways but in my opinion it is much much better to use group concat. The reason is that this will increase performance as well as reduce the php code. If you go on with the example you gave you will have to do much coding on the php end. And sometimes it becomes difficult to handle on php end. I had this experience a couple of months ago. Instead using group concat will fetch you single row having everything you need for each person. On the php end simple extract the Group Concated cell and make another loop or put it in array. That is easy to handle.
Consider using a Dictionary
class Person {
public $person_id; // 1
public $person; // Bob
//I don't know php but for your idea
public Dictionary<int,string> languageList; // KeyValuePairs {(5,English),(3,Italiano),(8,Deutsch)}
.
. // Functions
.
}

PHP MySQL - An attempt at recursive functions

I'm trying out my first recursive function (at least I think I am!) and it only half works. First, the code:
function check_title($i,$title) {
$q=mysql_query("SELECT Title FROM posts WHERE Title = '$title'");
$num=mysql_num_rows($q);
if($num==0) {
return $title;
}else {
$title=$title.' ('.$i++.')';
check_title($i,$title);
}
}
What I'm doing is taking a string (title) and checking if that title exists in the db already. If it does, I want to append a number to the newer of the duplicates (e.g. 'I Am A Title' becomes 'I Am A Title-2'). I then need to run the function again to check this new version of my title, and increase the appended value as required ('I Am A Title-3'). Once no duplication is discovered, return the Title in its acceptable form.
It works when no duplication is found (the easy bit), but fails when duplication is found. Instead of appending a number, the entire title variable is emptied.
Any help would by greatly appreciated!
As Mchl stated, the empty title is due to a lack of return in the else branch.
However, there is a problem with the function as it does not do what you intend. Currently, your function is building $title as 'Title-1-2-3-4-etc' the way you currently append the number to the title and check again. Instead of passing a modified title on the recursed call you should just pass the base title. Then, for the query, modify the title.
function check_title($title, $i = 0) {
$qtitle = $title . ($i == 0 ? '' : "-$i");
$q=mysql_query("SELECT Title FROM posts WHERE Title = '$qtitle'");
$num=mysql_num_rows($q);
if($num==0) {
return $title . ($i == 0 ? '' : "-$i");
}else {
return check_title(++$i,$title);
}
}
PS, I also changed the order of parameters that way your initial call doesn't need to specify 0.
$title = check_title($title);
PPS, I should mention this is a solution to do it via recursion. However, a recursive solution is not the proper solution here as it needlessly makes return trips to the DB. Instead, you should use an sql query that selects all titles LIKE "$title%" Order by title asc. Then, iterate through each result and do a regex comparison with the title to see if it matches a pattern <title>|<title>-<#>. If it does you increment a duplicate counter. At the end you spit out the title with an appended counter value. I'll leave that solution as an exercise for the original poster.
Use a loop instead...
$record_exists = true;
$title_base = "I Am A Title";
$title = $title_base;
$i = 0;
while($record_exists) {
$q=mysql_query("SELECT Title FROM posts WHERE Title = '$title'");
$num=mysql_num_rows($q);
if($num==0) {
$record_exists = false;
// Exit the loop.
}
else {
$i++;
$title = $title_base . "-" . $i;
}
}
echo $title; // last existing title
However, optimally you'd do more work with a single SQL query and iterate the result, saving a lot of trips to and from the database.
And just for fun...
$title_base = "I Am A Title";
$title = $title_base;
for ($i=1, $num=1; $num != 0; $i++)
{
$q=mysql_query("SELECT Title FROM posts WHERE Title = '$title'");
$num=mysql_num_rows($q);
$title = $title_base . "-" . $i;
}
echo $title; // next title in sequence (doesn't yet exist in the db)
You lack a return in else branch.
Recursion is not the best idea for this application. Hint: do a query like this SELECT MAX(Title) FROM posts WHERE Title LIKE '$title%');
Your recursive function is fine except for 2 things:
The original title isn't maintained between recursive calls. Hence each time $title = $title . ' (' . $i++ . ')' runs, another parenthesis is appended to the title, like "abc", "abc (1)", "abc (1) (2)" and so on.
You are returning $title when no more matches are found but no title is returned in the ELSE. It is important to do so. When the execution reaches the IF, it returns the title but the returned title is not assigned anywhere and hence is lost.
Here is the revised code:
$orgTitle = 'I am a title';
function check_title($i, $title = '') {
global $orgTitle;
$q = mysql_query("SELECT Title FROM posts WHERE Title = '$title'");
$num = mysql_num_rows($q);
if ($num == 0) {
return $title;
} else {
$title = $orgTitle . ' (' . ++$i .')';
return check_title($i, $title);
}
}
echo check_title(0, $orgTitle);
Note the addition of new variable $orgTitle. I've replaced it in the assignment statement inside the ELSE. This does the fix for point 1 above.
Also note the return added before check_title call in the ELSE. This solves point 2.
Hope it makes sense!
Add-on: Recursions are confusing, logically complex and tricky to debug. Also, recursive calls consume more memory (not in case of simple operations like your example) because the compiler/interpreter had to maintain the state variables for all steps in a recursion.
In order to minimise MySql interactions I'd recommend something similar to the following.
function checkTitle($title)
{
/*Return all iterations of the title*/
$res = mysql_query("SELECT COUNT(title) AS titleCount FROM posts
WHERE SUBSTR(title, 1,". strlen($title) .") = '$title' ");
/*Return the incremented title*/
return $title. (mysql_result($res, 0, "titleCount") + 1);
}
Example:
mysql> select title from posts;
+----------+
| title |
+----------+
| firefox1 |
| firefox2 |
| shoe |
| firefox3 |
+----------+
4 rows in set (0.00 sec)
mysql> SELECT COUNT(title) AS titleCount FROM posts WHERE SUBSTR(title, 1,7) = 'firefox' ;
+------------+
| titleCount |
+------------+
| 3 |
+------------+
1 row in set (0.00 sec)
mysql>
---- Follow up test
Test table structure.
mysql>SHOW COLUMNS FROM posts;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| title | varchar(12) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
/*Test code and output*/
function checkTitle($title)
{
/*Return all iterations of the title*/
$res = mysql_query("SELECT COUNT(title) AS titleCount FROM posts
WHERE SUBSTR(title, 1,". strlen($title) .") = '$title' ");
/*Return the incremented title*/
return $title. (mysql_result($res, 0, "titleCount") + 1);
}
mysql_connect("localhost","root", "password");
mysql_select_db("test");
echo checkTitle("firefox");
Output: firefox4

Categories