PHP PDO fetchAll, PDO::FETCH_CLASS and joins - php

I have a problem in the following code:
$query = 'SELECT user.id as id, pet.name as name FROM user
LEFT JOIN pet on pet.user_id = user.id
WHERE user.id = 15';
$result = $pdo->query($query);
This code will produce something similar to this:
***************
| id | name |
***************
| 1 | Mikey |
***************
| 1 | Stewie |
***************
| 1 | Jessy |
***************
Now, I'd like to use PDO::FETCH_CLASS to get an object. However, this method, at least to me, works fine only with simple SELECT statements. When you have a join statement, then it will fetch everything in a single class. In other words:
$user = $result->fetchAll(PDO::FETCH_CLASS, 'User');
echo $user->name; // this will print the pet name (which is weird)
Therefore, I'd like to have something similar:
$pets = $user->pets; // an array holding Pet Objects
foreach ($pets as $pet)
echo $pet->name . "-";
which will produce:
Mikey - Stewie - Jessy -
How can I achieve this?

You can't rely on PDO to do the job for you. PDO has no way to know where the dataset columns come from and it obviously can't figure out where you want to dump the data.
The simplest answer is that you have to write your own code. Fetch rows as arrays and populate your classes with it as it's always been done ;-)
The technique you describe is ORM (Object-relational mapping). There're some third-party libraries that implement it, such as Doctrine or Propel.

I open sourced a very small function that will transform joined results into a hierarchy. This avoids using heavy ORMs if you just need this small feature. https://github.com/afilina/nestedsql
You'd give it a statement like this:
SELECT album.id AS albums__id, photo.id AS albums__photos__id
FROM album
LEFT JOIN photo ON photo.album_id = album.id;
and it will produce something this:
stdClass Object
(
[albums] => Array
(
[1] => stdClass Object
(
[id] => 1
[photos] => Array
(
[1] => stdClass Object
(
[id] => 1
)
)
)
)
)
Optionally, you can replace stdClass by your own classes.

Related

Find the matching row in laravel

Here is my Table
Id | No |Group
1 | 1 |Alpha
1 | 1,2 |Alpha
1 | 2,4,5|Alpha
How can i find the the row which has No as 5 using laravel eloquent
$Match = MyModel::whereIn('No', array(5))->get();
But it didn't return any rows.
When i try to see the query executed it shows me
select * from `table` where `No` in (5)
How can i do this in php and laravel
As a pure Eloquent workround, you might be able to do something like:
$id = 5
$Match = MyModel::with(array('No' => function($query) use($id) {
$query->where_id($id);
}))->get();
Using Raw and FIND_IN_SET, something like:
$Match = MyModel::whereRaw(
'find_in_set(?, `No`)',
[5]
)->get();
(Untested)
But this will never be an efficient query because it can't use indexes; and there are many other reasons why a comma-separated list is a bad idea (such as lack of referential integrity)
The real solution will always be to normalize your database properly

Combine two rows into one string

i have dynamic database, and i want to search in this table
FieldID | Content | TypeID
--------------------------
ABC-123 | jon | 1
EFG-456 | doe | 1
HIJ-789 | man | 1
So my SELECT query looks something like this:
SELECT
GROUP_CONCAT(fieldsContent.Content SEPARATOR '|*|') AS Content,
GROUP_CONCAT(fieldsContent.FieldID SEPARATOR '|*|') AS FieldID,
FROM (`customers`)
LEFT OUTER JOIN `fieldsContent` ON `fieldsContent`.`TypeID` = `customers`.`ID`
GROUP BY `fieldsContent`.`TypeID`
ORDER BY `customers`.`Created` DESC
And the result looks like this
Array
(
[0] => stdClass Object
(
[Content] => jon|*|doe|*|man
[FieldID] => ABC-123|*|EFG-456|*|HIJ-789
)
)
And when i'm adding HAVING and searching only for jon, it will return me the result
HAVING Content LIKE "%jon%"
But, when i'm trying to search jon doe it will return empty result
HAVING Content LIKE "%jon doe%"
Because jon doe don't exists in the string, only jon|*|doe
So how can i combine these two rows to one string without the SEPARATOR for me the search in them jon doe ?
BUT!! keep in mind that i need to obtain the SEPARATOR because i need to combine the data to be used in php.
ex:
$field = explode('|*|',$data->FieldID);
$content = explode('|*|',$data->Content);
foreach($field as $k => $FieldID){
switch($FieldID){
case 'ABC-123':
$res['first_name'] = $content[$k];
break;
case 'EFG-456':
$res['last_name'] = $content[$k];
break;
case 'HIJ-789':
$res['gender'] = $content[$k];
break;
}
}
Any ideas will be appreciated :)
TRY THIS #1
HAVING Content LIKE "%jon%doe%"
TRY THIS #2
HAVING Content LIKE "%jon" AND Content LIKE "%doe%"
TRY THIS #3
HAVING REPLACE(Content,'|*|',' ') LIKE "%jon doe%"
GIVE IT A TRY !!! :-)
Use:-
HAVING Content LIKE "%jon%" AND Content LIKE "%doe%"

Fetch all records from MySQL as lazy="false" with PHP

I have 2 tables in my database users and users_roles, like so:
users:
id | username | user_role_id
----------------------------
1 | User1 | 1
2 | User2 | 1
3 | User3 | 2
users_roles:
id | role
----------
1 | admin
2 | user
So, in Java I just had to write in Hibernate mappings an attribute lazy="false" to just get a list of all users automatically containing users_roles objects too, each specifically for each record in users table, but in PHP? I just came across an option in the PDO called FETCH_ASSOC, but I cannot understand how it works.
My get all users list method looks like this:
public function getAll() {
$conn = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD);
$sql = $conn->prepare("SELECT * FROM users ORDER BY id DESC");
$sql->execute();
$list = $sql->fetchAll(PDO::FETCH_OBJ);
$conn = null;
return $list;
}
and the piece of code from the Smarty template:
{foreach from=$usersList item=item}
{$item->username}
{$item->users_roles.role}
{/foreach}
Would you mind helping me a little to get on the right way to it?
FETCH_ASSOC option fetches the rows into an associative array like:
Array
(
[0] => Array
(
[id] => 1
[name] => name1
)
[1] => Array
(
[id] => 2
[name] => name2
)
)
If you want top get all the users, who have a corresponding record in users_roles table, you can use this request:
SELECT
*
FROM
users
INNER JOIN
users_roles
ON
users_roles.id=users.user_role_id
ORDER BY
users.id DESC
Unless you are using PHP frameworks such as CakePHP or Yii, you will have to create your own query to fetch related data.
SELECT * FROM users
LEFT JOIN users_roles ON users.user_role_id = users_roles.id
After that you can fetch the records and use them in your code.
The equivalent of PDO in Java is JDBC: you have statements and result sets, not business objects. Hibernate is an object-relational-mapping (ORM) library that allows mapping tables into business objects.
There are several ORMs for PHP, for example Doctrine and Propel. Search for "PHP ORM" on the Internet.
Or you can use plain SQL, writing the JOIN and WHERE conditions yourself.

Iterative appending of array with arrays from sql results

am new here, but have enjoyed reading others' questions and answers. I'm fairly new to PHP and am working on a project - basic table look-ups in MySQL, etc.
What I want to end up with is an array of arrays, the form of which is shown below with condiments (not my actual project). The content is coming from two different tables. For each of the condiment names (from table 1) I look up in table 2 the types of condiments, linked by ID. The searching and grabbing stuff is fine, but I'm having trouble looping and building my final $Condiments array.
The first part of the loop, I grab the condiment name from the $row and append it to the array. But I need each of these condiment names to be an empty array to put something in, in the next step. I've looked around but couldn't find a good way to iteratively append new placeholder arrays into an array. Is there an elegant solution? Some cool function I'm not taking advantage of? Thanks!
// SQL search for condiment words, blah blah, leading to...
$rowsnumber = mysql_num_rows($result);
for ($j = 0 ; $j < $rowsnumber ; ++$j)
{
$row = mysql_fetch_row($result); // $row is an array featuring a condiment name and other stuff.
$Condiments[] = $row[1]; // condiment name goes in array.
$CondimentType = searchTable2($row[0]);
// using the condiment name's ID, I look up its matching types via a function.
// $CondimentType is now an array of IDs and types from Table2 that I want to append to the condiment name I just added above.
$Condiments[$row[1]] = $CondimentType;
// I repeat the process for the next name
}
// Final desired result...
$Condiments=
Array
(
[Pickles] => Array
(
[34] => Dill
[23] => Butter
)
[Mustard] => Array
(
[22] => Hot
)
[Relish] => Array
(
[3] => Pickle
)
)
so like i said , you need to use join to perform the needed task.
you can find more explanation here about joins
http://dev.mysql.com/doc/refman/5.0/en/join.html
in your case , this query should do the job
select t1.word,t3.word
from table1 as t1 join table2 as t2 on t1.id =t2.id
left join table1 as t3 on t3.id = t2.linkid
i ran the query in my machine and these are the results
+---------+--------+
| word | word |
+---------+--------+
| Pickles | Dill |
| Pickles | Butter |
| Mustard | Hot |
| Relish | Pickle |
+---------+--------+
so instead of looping through each row, just perform a join and get the results. in php then you can do the needed format of the array.
hopefully this will help you

Mysql query with multiple ID columns and php

I have 2 joined tables, each one has a primary key column named id.
SELECT t1.*, t2.* from t1 join t2 on t1.fk_id=t2.id
When I run the query above, both id fields are selected (t1.id and t2.id). My question is, how can I select the correct ID while I am looping through the result set? If I select $result->id, I will get the t2.id. Is there any way that I can get the t1.id also without explicitly selecting it in the query (i.e. t1.id as t1_id?) Also, please, let us know about some of your practices when it comes to naming the primary key columns.
Thanks!
SELECT t1.id as id1, t2.id as id2, t1.*, t2.* from t1 join t2 on t1.fk_id=t2.id
You are probably using mysqli_result::fetch_assoc to return each row of your result set as an associative array. MySQL will let you have two columns with the same name in a query, but these do not map to an associative array the way you want them to—even though the associative array is doing exactly as it should.
Assume two tables, book and author, linked by the junction table book_author. In MySQL, you can run the following query, which returns two id columns:
SELECT b.*, a.*
FROM book AS b
JOIN book_author AS ba ON ba.book_id = b.id
JOIN author AS a ON a.id = ba.author_id
LIMIT 2;
+----+-----------------+----+--------------+
| id | title | id | name |
+----+-----------------+----+--------------+
| 1 | Design Patterns | 1 | Erich Gamma |
| 1 | Design Patterns | 2 | Richard Helm |
+----+-----------------+----+--------------+
If you try to map one of these rows to an associative array, you end up with a single id element in your array:
$row = $result->fetch_assoc();
print_r($row);
Array
(
[id] => 1
[title] => Design Patterns
[name] => Erich Gamma
)
The last id column in the row will overwrite any that precede it. Here’s the second row from the result set:
Array
(
[id] => 2
[title] => Design Patterns
[name] => Richard Helm
)
This is just the same as modifying the value of an element in an associative array;
$row = array();
$row['id'] = 1;
print_r($row);
Array
(
[id] => 1
)
$row['id'] = 2;
print_r($row);
Array
(
[id] => 2
)
If you give each column a unique name in your query, either by doing so in the table itself, or giving it an alias in the query, the problem is avoided:
SELECT b.id AS book_id, b.title,
a.id AS author_id, a.name
FROM book AS b
JOIN book_author AS ba ON ba.book_id = b.id
JOIN author AS a ON a.id = ba.author_id
LIMIT 2;
+---------+-----------------+-----------+--------------+
| book_id | title | author_id | name |
+---------+-----------------+-----------+--------------+
| 1 | Design Patterns | 1 | Erich Gamma |
| 1 | Design Patterns | 2 | Richard Helm |
+---------+-----------------+-----------+--------------+
$row = $result->fetch_assoc();
print_r($row);
Array
(
[book_id] => 1
[title] => Design Patterns
[author_id] => 1
[name] => Erich Gamma
)
Alternatively, you could (and almost certainly should) use prepared statements instead. Although this can get round the problem of duplicate column names, using unique column names in your queries still makes things much easier to read and debug:
$sql = 'SELECT b.*, a.* ' .
'FROM book AS b ' .
'JOIN book_author AS ba ' .
'ON ba.book_id = b.id ' .
'JOIN author AS a ' .
'ON a.id = ba.author_id';
$stmt = $mysqli->prepare($sql);
$stmt->execute();
$stmt->bind_result($book_id, $book_title, $author_id, $author_name);
while ($stmt->fetch()) {
printf("%s, %s, %s, %s\n",
$book_id,
$book_title,
$author_id,
$author_name);
}
You'll often see the primary key for table XXX named xxx_id. This keeps the name of the same "information identifier" the same everywhere: for example in another table YYY, you'll have YYY.xxx_id with a foreign key constraint to XXX.xxx_id. This makes joins easier (you don't have to specify the "on" constraint at all in many databases) and it solves the problem you're running into as well.
I'm not saying you should prefix every column name to create a faux-namespace, but in the case of "id" it is actually useful and descriptive. It is, after all, not just any kind of ID, it's a user ID, site ID, game ID, contact ID, what have you.

Categories