unable to merge variables with array_merge: undefined index - php

I am trying to combine two variables that retrieves information from MySQL.
I have been suggested to use array_merge(), and it seems to work for the most part. I keep getting Warning: Illegal string offset after all the results has been returned from the database. Interesting is that the first 8 (the query has a LIMIT of 8) are error clean, after the 8 results has been printed, then a huge list appears with that error.
query
articleClass.php
public function latestArticles()
{
$sth = $this->db->prepare("SELECT * FROM articles
WHERE article_uid = article_uid
ORDER BY article_uid DESC LIMIT 8");
$sth->execute();
$row = $sth->fetchAll();
return $row;
}
public function articleTags()
{
$sth = $this->db->prepare("SELECT a.*, b.*
FROM articles a, article_tags b
WHERE b.tag_id = a.article_uid
");
$sth->execute();
$row = $sth->fetchAll();
return $row;
}
printing code
index.php
include 'libraries/articleClass/articleClass.php';
$articleClass = new articleClass();
$latestArticles = $articleClass->latestArticles();
$articleTags = $articleClass->articleTags();
foreach(array_merge($latestArticles, $articleTags) as $data)
{
$first_uid = $data['article_uid'];
$first_image = $data['article_image'];
$first_title = $data['article_title'];
$first_content = $data['article_content'];
$first_created = gmdate("d M Y", $data['article_created']);
$first_tags = $data['tag_name'];
echo '
<article>
<img src="path-to-image/'.$first_image.'"/>
<h1>'.$first_title.'</h1>
<p>'.$first_content.'</p>
<ul>
<li>'.$first_tags.'</li>
</ul>
</article>
';
}
Once index.php is loaded, 8 articles are printed on the page as they should, but I get :
Notice: Undefined index: tag_name in /var/www/new-design/index.php on line 74
Trial & (mostly) Failures
If I change public function article_tags to Fetch instead of FetchAll I get these errors:
Warning: array_merge(): Argument #2 is not an array in /var/www/new-design/index.php on line 67
Warning: Invalid argument supplied for foreach() in /var/www/new-design/index.php on line 67
I am unable to figure out how to succeed with this, any leads would be great. I've been at it since morning!
UPDATE
article_tags table
+--------------------------------+
| tag_id | article_id | tag_name |
+--------------------------------+
| 1 | 8 | awesome |
| 2 | 8 | sweet |
| 3 | 8 | gross |
+--------------------------------+
there is only one article_id corresponding to the articles that are being called, yet this article still receives undefined index: tag_name of course because in the array_merge they haven't been merged at all.

What happens here is that
array_merge($latestArticles, $articleTags)
simply appends one array to the other, meaning:
The first 8 entries in the resulting array are your articles (these have the "tag_name" field set).
The rest is filled with the contents of $articleTags (those don't have "tag_name" field - causing your error).
Here's some code to illustrate that (Indices 0 to 2 are your articles while 3 to 5 are your tags, notice how indices 3-5 of the resulting array don't have the tag_name field):
$latestArticles = array(
array("article_title" => "Some Title 1", "tag_name" => "SomeTag"),
array("article_title" => "Some Title 2", "tag_name" => "SomeOtherTag"),
array("article_title" => "Some Title 3", "tag_name" => "SomeTag"),
);
$articleTags = array(
array("name" => "SomeTag", "somefield" => "foo", "otherfield" => "bar"),
array("name" => "SomeTagOtherTag", "somefield" => "baz", "otherfield" => "test"),
array("name" => "YetAnotherTag", "somefield" => "test2", "otherfield" => "test3")
);
$result = array_merge($latestArticles, $articleTags);
print_r($result);
/** Resulting Array:
Array
(
[0] => Array
(
[article_title] => Some Title 1
[tag_name] => SomeTag
)
[1] => Array
(
[article_title] => Some Title 2
[tag_name] => SomeOtherTag
)
[2] => Array
(
[article_title] => Some Title 3
[tag_name] => SomeTag
)
[3] => Array
(
[name] => SomeTag
[somefield] => foo
[otherfield] => bar
)
[4] => Array
(
[name] => SomeTagOtherTag
[somefield] => baz
[otherfield] => test
)
[5] => Array
(
[name] => YetAnotherTag
[somefield] => test2
[otherfield] => test3
)
)
*/

Related

How to execute that in 1 query?

I have 2 tables customer and orders:
customers:
| custID | Name | Age |
|--------|-------|-----|
| 1 | Peter | 23 |
| 2 | Julie | 34 |
| 3 | Tom | 45 |
orders:
| custID | product | color |
|--------|---------|-------|
| 1 | shirt | blue |
| 1 | jacket | black |
| 2 | jacket | green |
| 3 | hat | grey |
| 3 | shirt | white |
I now want to get all customers and their orders, ordered as a list. So something like that:
Array
(
[0] => Array
(
[ID] => 1
[name] => Peter
[age] => 23
[orders] => Array
(
[0] => Array
(
[product] => shirt
[color] => blue
)
[1] => Array
(
[product] => jacket
[color] => black
)
)
)
[1] => Array
(
[ID] => 2
[name] => Julie
[age] => 34
[orders] => Array
(
[0] => Array
(
[product] => jacket
[color] => green
)
)
)
[2] => Array
(
[ID] => 3
[name] => Tom
[age] => 45
[orders] => Array
(
[0] => Array
(
[product] => hat
[color] => grey
)
[1] => Array
(
[product] => shirt
[color] => white
)
)
)
)
When I do:
SELECT name, age, product, color
FROM `customers`, `orders`
where `customers`.`id` = `orders`.id
group by name
I get:
| name | age | product | color |
|-------|-----|---------|-------|
| Peter | 23 | jacket | green |
| Julie | 34 | shirt | blue |
| Tom | 45 | hat | grey |
Is this even possible with only one query?
You could simply make the query below:
SELECT *
FROM customers
JOIN orders
USING custID
GROUP BY Name
ORDER BY custID ASC;
A couple of steps here...
First, you should run the following query:
SELECT
`customers`.`id`,
`customers`.`name`,
`customers`.`age`,
`orders`.`product`,
`orders`.`color`
FROM `customers`, `orders`
where `customers`.`id` = `orders`.`id`
order by `customers`.`id`
Which should give you de-normalized tabular data that looks something like this:
$array = array(
array("id" => 1, "name" => "Peter", "age" => 23, "product" => "shirt", "color" => "blue"),
array("id" => 1, "name" => "Peter", "age" => 23, "product" => "jacket", "color" => "black"),
array("id" => 2, "name" => "Julie", "age" => 34, "product" => "jacket", "color" => "green"),
array("id" => 3, "name" => "Tom", "age" => 45, "product" => "hat", "color" => "grey"),
array("id" => 3, "name" => "Tom", "age" => 45, "product" => "shirt", "color" => "white")
);
You can then transform the that data into your desired format as follows:
$transformed = array();
$i = 0;
while ($i < count($array)) {
$id = $array[$i]["id"];
$name = $array[$i]["name"];
$age = $array[$i]["age"];
$products = array();
while ($i < count($array) && $id == $array[$i]["id"]) {
array_push($products, array("product" => $array[$i]["product"], "color" => $array[$i]["color"]));
$i++;
}
array_push($transformed, array("id" => $id, "name" => $name, "age" => $age, "products" => $products));
}
http://sandbox.onlinephpfunctions.com/code/6fe856e1f71f699e84215b6f66d25589f71e255e
i think you should user INNER JOIN:
SELECT * FROM customers AS c INNER JOIN orders AS o ON c.custID = o.custID GROUP BY c.custID ORDER BY c.custID ASC;
There is no point in trying to achieve the desired outcome with single query. With the first query get the list of customers. Then perform a second query, which will load all the orders for the customers from the first query. And in a loop match orders to respective customers.
EDIT: something like this
$result = [];
$customers = $pdo->query("SELECT * FROM `customers`")->fetchAll();
foreach ($customers as $c) {
$result[$c['id']] = $c;
}
$orders = $pdo->query("SELECT * FROM `orders` WHERE `custID` IN (".implode(', ', array_keys($result).")");
foreach ($orders as $o) {
if (!isset($result[$o['custId']]['orders']))
$result[$o['custId']]['orders'] = [];
$result[$o['custId']]['orders'][] = $o;
}
Your sql SELECT name, age, product, color FROMcustomers,orderswherecustomers.id=orders.id group by name is fine, just add the customer id and order id also in the sql. Then, in PHP, as you iterate the result set, populate the customer info first (id, name, age) with customer id as the key and name, age as value as an array. Likewise, populate the order for that customer in the key 'orders' with the order id as key and value as an array (product, color).
Once you have the array populated, iterate over that array and keep putting things into a new array since the output you want is an array with sequential keys (0, 1, 2 etc) instead of customer id.
$initialList = array();
while($row = $result->fetch_assoc()) {
if(!array_key_exists($row['customer_id'], $initialList)) {
$initialList[$row['customer_id']] = array(
'name' => $row['name'],
'age' => $row['age'],
'orders' => array()
);
}
$initialList[$row['customer_id']]['orders'][] = array(
'product' => $row['product'],
'color' => $row['color']
);
}
$finalList = array();
foreach($initialList as $customerId => $customer) {
$customer['ID'] = $customerId;
$finalList[] = $customer;
}
//to print and check the array
print_r($finalList);
try this:
SELECT c.custID,c.name, c.age, group_concat(CONCAT_WS(':',o.product,o.color)SEPARATOR ',') as productos
FROM customers AS c
INNER JOIN orders AS o ON c.custID = o.custID
GROUP BY c.custID;
You just have to parse the products.
$array=array();
while($r = $res->fetch_assoc()) {
$id=$row['custID'];
$name=$row['name'];
$age=$row['age'];
$productos=$row['productos'];
$productsSeparats = explode(',',$productos);
$orders=array();
foreach ($productsSeparats as $value) {
$ar=explode(':',$value);
array_push($orders, array("product" => $ar[0], "color" => $ar[1]));
}
array_push($array, array("id" => $id, "name" => $name, "age" => $age, "orders" => $orders));
}

Array in array with PHP PDO fetch modes

Here is an extract of my PHP code:
A function that prints the query result from a PostgreSQL database:
function getOuvrage(){
$conn = PostgreConnection::getInstance();
$sth = $conn->prepare("SELECT * FROM ouvrage WHERE code = '01'");
$sth->execute();
$result = $sth->fetchAll();
print_r($result);
}
Result SQL query in pgAdminIII is:
code |forage | station | reserve
---------+--------+-----------+----------
01 | 2 | 12 | 87
Result of print_r() function is:
Array([0] => Array ([forage] => 2 [0] => 2 [station] => 12 [1] => 12 [reserve] => 87 [2] => 87))
My questions: why are there 2 arrays and how can I get a simple array like this:
Array([forage] => 2 [station] => 12 [reserve] => 87)
EDIT :
I tried this:
$result = $sth->fetchAll(PDO::FETCH_ASSOC);
I still get the 2 arrays:
Array([0] => Array([forage] => 2 [station] => 12 [reserve] => 87))
I tried this:
$result = $sth->fetchAll(PDO::FETCH_KEY_PAIR);
I get this:
Array()
I couldn't find an answer to my question, including in the « duplicated » question pointed by #Your Common Sense!
The solution is:
$result = $sth->fetch(PDO::FETCH_ASSOC);

Display Two tables data in Php

i have following tables
Author
id | author_name | author_detail | author_bio
books
id | author_id | book_name | book_detail
i want to display data in following way
Author Name ::
Author Detail ::
books :: 1.book1
2.book2
3.book3
4.book4
i have tried following query but didnt worked as per my requirement
select * from authors left join books on author.id=books.author_id
i have tried group concat but it gives books name with coma seperate.so i want to books detail in array
select author.author_name,author.author_detail,author.author_bio,group_concat(books.book_name) eft join books on author.id=books.author_id
i am expexting output like
Array
(
[0] => Array
(
[id] => 1
[name] => Norm
[books] => Array
(
[0] =>Array
(
[id] => 4
[book_name] => great wall
[created_at] => 2015-09-11 04:45:07
[updated_at] => 2015-09-11 04:45:07
)
[1] =>Array
(
[id] => 6
[book_name] =>new book
[created_at] => 2015-09-11 04:45:07
[updated_at] => 2015-09-11 04:45:07
)
)
)
[1] => Array
(
[id] => 2
[name] => Norm
[books] => Array
(
[0] =>Array
(
[id] => 2
[book_name] => amazing star
[created_at] => 2015-09-11 04:45:07
[updated_at] => 2015-09-11 04:45:07
)
[1] =>Array
(
[id] => 3
[book_name] =>way of journy
[created_at] => 2015-09-11 04:45:07
[updated_at] => 2015-09-11 04:45:07
)
)
)
i have checked this question also
displaying php mysql query result with one to many relationship
Can any one help me how to display data like above ?
thank you
Try this:
SELECT
A.id
A.author_name,
A.author_detail,
A.author_bio,
B.book_name,
B.created_at,
B.updated_at
FROM books AS B
LEFT JOIN author AS A
ON (A.id=B.author_id)
you will get result like this:
id | author_name | author_detail | author_bio | book_name
1 | ari | some detail | some bio | book_ari_1
1 | ari | some detail | some bio | book_ari_2
1 | ari | some detail | some bio | book_ari_3
2 | tester | some detail | some bio | book_tester_1
etc..
to make array as your expecting result you need to restructure your array result. i will asume your result array will be in $result variable
$new_result = array();
foreach ($result as $key => $value) {
if (empty($new_result[$value['id']]))
{
$new_result[$value['id']] = array(
'id' => $value['id'],
'name' => $value['name'],
'books' => array(
array(
'id' => $value['id'],
'book_name' => $value['book_name'],
'created_at' => $value['created_at'],
'updated_at' => $value['updated_at']
),
)
)
}
else
{
$new_result[$value['id']]['id'] = $value['id'];
$new_result[$value['id']]['name'] = $value['name'];
$new_result[$value['id']]['books'][] = array(
'id' => $value['id'],
'book_name' => $value['book_name'],
'created_at' => $value['created_at'],
'updated_at' => $value['updated_at']
);
}
}
the result will look like your expected. but the key number will be formated as id.
to reset key of $new_result as increment number you need to get only value use array_values() function
$new_result = array_values($new_result);
You could do it with your first query...but you'd have to check the author_id inside the record loop and show the author details only whenever the value changed (by comparing it with a value stored in a variable)...otherwise only show the book details.
So your code might (very roughly) look like this:
$query = "select whatever whatever...";
$records = $database->Execute($query);
foreach ($records as $fields) {
if ($fields['id'] != $previous_id) echo "Author ...";
echo "Book whatever whatever ...";
$previous_id = $fields['id'];
}
A more straightforward (although slightly longer) way would be to have a second query: a sub-query. And it would take place inside the loop through the results of the first (outer) query. So your outer query gets the authors and, after you show the author details, you have this separate query for books of the author...and you have a loop-within-the-outer-loop to show the details of each book.
So your code (very roughly) looks something like this:
$query = "select id, author_name, whatever from author";
$author_records = $database->Execute($query);
foreach ($author_records as $fields) {
echo "Author: {$fields['author_name']} whatever <br/>";
$subquery = "select whatever from books where id = whatever";
$book_records = $database->Execute($subquery);
foreach ($book_records as $otherfields) {
echo "Book whatever whatever";
}
}
you can do this in php no need to go in query itself but take both data in separate query i.e. books and author data
Remember i assumed $result as authors data and $result2 as books data
$item=array();
while($row=mysql_fetch_array($result))
{
$id=$row['id'];
$item[$id]['name']=$row['name'];
$item[$id]['id']=$row['id'];
$item[$id]['books']=array();
$temp=array();
while($row1=mysql_fetch_array($result2))
{
if($id==$row1['author_id'])
{
$temp['id']=$row1['id'];
$temp['book_name']=$row1['book_name'];
$temp['created_at']=$row1['created_at'];
$temp['updated_at']=$row1['updated_at'];
array_push($item['id']['books'],$temp);
}
}
}
Now here id is formatted as author's id. To get like array keys you can use array_values($item)

mysql - delete sql row where data not match with data in array

Please can I have some help on this. I'm trying to delete SQL row in a table that are not match the data in an array.
SQL Table:
| id | Name | No
------------------
| 1 | john | 14
| 2 | rui | 156
| 3 | ted | 148
| 4 | alex | 123
| 5 | depay | 56
Array:
Array
(
[0] => Array
(
[name] => john
[no] => 14
)
[1] => Array
(
[name] => ted
[no] => 148
)
[2] => Array
(
[name] => depay
[no] => 56
)
)
This may help you
[akshay#localhost tmp]$ cat test.php
<?php
$array = array (
array (
'name' => 'john',
'no' => '14'
),
array (
'name' => 'ted',
'no' => '148'
),
array (
'name' => 'depay',
'no' => '56'
)
);
$table = "some_table";
$sql = "DELETE FROM ".$table." WHERE (NAME,NO) NOT IN (". implode(",",array_map(function($_){ return sprintf("('%s',%d)",$_['name'],$_['no']);},$array)).")";
print $sql."\n";
?>
Output
[akshay#localhost tmp]$ php test.php
DELETE FROM some_table WHERE (NAME,NO) NOT IN (('john',14),('ted',148),('depay',56))
It would be much easier if you can return "id" aka primary key of the table as array. In that case you can just grab those ids and during delete operation exclude those from the equation.
$selectQ = 'select id from table_name'; // and no>10
$result = mysql_result($selectQ);
$ids = array();
while ($info = mysql_fetch_assoc($result)) {
$ids[] = $info['id'];
}
if($ids) {
$deleteQ = 'delete from table_name where id not in ('.implode(",", array_values($ids)).')';
mysql_query($deleteQ);
}
P.S : During select query make sure to include logic for finding those users. For example, who's "no" is greater than X.Otherwise this query in default will return all ids and eventually nothing will be deleted.

Merge multiple arrays (objects) and compare to another array

My Problem
Trying to create similar arrays so I can compare them.
I am creating a distribution list for files, the adding of the distribution list work fine, I list user surname, user forename and user department, these are selected and posted, foreach user I retrieve the users.user_id and store this in a distribution table (under distro_lis)t like so.
distro_id (AI, PK) | distro_list | policy_id
---------------------------------------------
1 | 1 23 21 34 | 13
2 | 10 22 21 34 | 15
3 | 1 27 26 40 | 34
Now I working on the editing of the distribution list, so for a row, lets say row 1, I fetch the distro_list and parse it to get each user ID (from distro_list) using.
$policyID is received in the method argument
$db = $this->dbh->prepare('SELECT distro_list FROM distro WHERE policy_id = :policy_id');
$db->bindParam(':policy_id', $policyID);
$db->execute();
$row = $db->fetch(PDO::FETCH_ASSOC);
$ids = explode(' ',$row);
foreach ($ids as $user) {
$db = $this->dbh->prepare('SELECT user_forename, user_surname, user_dept FROM users WHERE user_id = :user_id ORDER BY user_surname ASC');
$db->bindParam(':user_id', $user);
$db->execute();
$row = $db->fetch(PDO::FETCH_ASSOC);
var_dump($row);
}
the var_dump($row) returns an array of arrays (objects.. not sure of the terminology here) which looks like so (print_r).
Array
(
[user_forename] => fname1
[user_surname] => sname1
[user_dept] => dept1
)
Array
(
[user_forename] => fname2
[user_surname] => sname2
[user_dept] => dept2
)
Array
(
[user_forename] => fname3
[user_surname] => sname3
[user_dept] => dept3
)
the array that I want to compare it to looks like so (print_r).
array
(
[0] => Array
(
[user_forename] => fname1
[user_surname] => sname1
[user_dept] => dept1
)
[1] => Array
(
[user_forename] => fname2
[user_surname] => sname2
[user_dept] => dept2
)
[2] => Array
(
[user_forename] => fname3
[user_surname] => sname3
[user_dept] => dept3
)
)
I understand why the first array looks like that, because im var_dump'ing' after each iteration. How can I get the first array (array of arrays or objects) into a single array so I can compare it to the second array?
Try this
$list_users = array()
foreach ($ids as $user) {
//...
$list_users[] = $row;
}
var_dump($list_users);

Categories