Iterative appending of array with arrays from sql results - php

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

Related

Join 1 Row to Multiple Rows in PDO

Here is my scenario:
Database Name: Children
+-------------+---------+---------+
| child_id | name | user_id |
+-------------+---------+---------+
1 Beyonce 33
2 Cher 33
3 Madonna 33
4 Eminem 33
Database Name: Parents
+-------------+---------+---------+
| parent_id | child_id | parent_name |
+-------------+---------+---------+
1 1 Obama
2 1 Michelle
3 4 50cents
4 4 Gaga
Desired Output:
+-------------+---------+---------+
| child_id | name | parent Name |
+-------------+---------+---------+
1 Beyonce Obama (Row 1) Michelle (Row 2)
PHP SQL Query in PDO:
$sql = "SELECT Children.child_id, Children.name, Parents.parent_name
FROM Children
LEFT JOIN Parents
ON Children.child_id = Parents.child_id
WHERE Children.user_id = ?
";
$stmt = $db_PDO->prepare($sql);
if($stmt->execute(array($userId))) // $userId defined earlier
{
// Loop through the returned results
$i = 0;
foreach ($stmt as $row) {
$fetchArray[$i] = array (
'childId' => $row['child_id'],
'childName' => $row['name'],
'parentName' => $row['parent_name'],
// How do I save the multiple parents from other rows here ????
);
$i++;
}
}
How can I run a query that Joins 1 row to multiple rows in second table in PDO? I have read other topics here but I am unsure. Is it easier to add a second query that gets the linked parents for each child_id separately in a loop? I am worried that will be too much query. Can someone help me solve this?
Well, took me some fiddling to test it all out but here you go.
Unfortunately one cannot easely pivot tables in mysql but there are alternatives.
http://sqlfiddle.com/#!9/1228f/26
SELECT GROUP_CONCAT(
CONCAT_WS(':', Parents.parent_id,Parents.parent_name) ) FROM Parents where Parents.child_id=1
;
SELECT
Children.child_id,
Children.name,
GROUP_CONCAT(
CONCAT_WS(':', Parents.parent_id,Parents.parent_name) ) as parents
FROM
Children
LEFT JOIN Parents
ON Children.child_id = Parents.child_id
WHERE Children.user_id = 33
Group by Children.child_id
This query uses the group concat to concatenate all resulsts we want into a colon seperated string with the values we want, and comma's between the individual fields.
We could do some tricky magic to make them individual fields but that would break our php because we wouldnt know how much fields each query would return(adopted, orphan, no known parents, etc...)
In php you could feed them into an object
$parents = array();
$loop1 = explode(',',$row['parents']);
foreach($loop1 as $parentset) {
$parentdetail = explode(":",$parentset);// decide yourself how much detail you want in here... I jsut went with name and id.
$parent = new stdClass();
$parent->id = $parentdetail[0];
$parent->name = $parentdetail[1];
array_push($parents,$parent);
}
var_dump($parents);
Execute the below query . You will get the output as required, i just used the group by which will group the records as per the selected column
select a.child_id, name ,group_concat(parent_name) from children a, parents b where a.child_id =b.child_id group by a.child_id
HI this query works only if you are passing child id ,
select a.child_id, name ,group_concat(parent_name ) parent_name from children a, parents b where a.child_id =b.child_id and a.child_id=1
here i am using a function called group_concat which is used for concatinating the rows.It automatically takes the rows whose count is greater than 1.So no need of the extra code again

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.

mySQL function to check column value and perform new action

Is it possible to write a function within mySQL that checks the value of a SELECT query, and if it != 0, continue running the function and add to the result array?
I have a few entries marked as related_id = 0 The rest have actual positive numbers attached.
I am trying to create a single query that will continually loop through a sql function, check and see if the retrieved related_id result is 0. If not, then it will run again, add the newly checked row to the result array and continue until it finds a 0.
The way the DB is set up, a 0 will always occur, and it will be searching via id,so there should only be one result.
I am using a slightly modified tagging system.
keywords_id | keyword | related_id
------------------------------------
1 | sports | 0
2 | baseball | 1
3 | football | 1
4 | pitchers | 2
If I pass in related_id = 2 I'm looking to return an array that yields:
array
[0]
keyword => 'sports'
keywords_id => '1'
related_id => '0'
[1]
keyword => 'baseball'
keywords_id => '2'
related_id => '1'
[2]
keyword => 'pitcher'
keywords_id => '4'
related_id => '2'
I tried my luck with using IF and THEN but i just haven't seen enough examples and its tough to find solid tutorials online. Thanks!
SELECT k.*
FROM keywords k
WHERE keywords_id = 2
The above query would essentially start it off. The keywords_id is the related_id that is passed. Therefore the above would return keywords_id: 2 |keyword: baseball |related_id: 1
Because related_id 1 is NOT 0, i would need to run it again.
I realize this can be done in PHP through a few extra queries...is that the way I should do this? I assume it could be done in mySQL after reading about functions. I just couldn't figure it out.
MySQL doesn't support returning an array from a function. Would suggest creating a table (or possibly a temporary table) to hold the results and then writing a stored procedure to populate it instead.
Not sure exactly what you are trying to achieve but maybe something along the lines of this?
CREATE TABLE results (keywords_id INT, keyword VARCHAR(2000), related_id INT);
CREATE PROCEDURE populateResults(IN keyword_id_in INT)
BEGIN
DECLARE num_results INT;
DECLARE max_results INT;
DECLARE next_keyword_id INT;
SET next_keyword_id = keyword_id_in;
SET max_results = 5;
SET num_results = 0;
DELETE FROM results;
the_loop: LOOP
INSERT INTO results
SELECT keywords_id, keyword, related_id
FROM keywords
WHERE keywords_id = next_keyword_id;
SELECT related_id
FROM keywords
WHERE keywords_id = next_keyword_id
INTO next_keyword_id;
IF (next_keyword_id = 0) || (num_results >= max_results) THEN
LEAVE the_loop;
END IF;
SET num_results = num_results + 1;
END LOOP the_loop;
END
See SQL Fiddle Demo
My understanding from above sample - need to get all records checked until a match is found ( the above sample for related_id = 2 ).
If so you can try using mysql cursors http://dev.mysql.com/doc/refman/5.0/en/cursors.html
in order to loop the result set.

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