Merge multiple arrays (objects) and compare to another array - php

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);

Related

How to create a three dimensional array from sql query PHP

I have 2 tables in a database, 1 of them are linked with a foreign key to the first one. Each row on table 1 is linked to multiple rows in table 2. I am trying to make a query that looks at a WHERE from table 2 and returns multiple rows from table 2 which are sorted into the rows they linked with in table 1 and then put this all into one big multi dimensional array, so it should work something like this:
$array[0][column_name][0] this would use row 1 from table 1 and give me a the first result in the column called column_name
$array[1][column_name][0] this would use row 2 from table 1 and give me a the first result in the column called column_name
$array[1][column_name][3] this would use row 2 from table 1 and give me a the 4th result in the column called column_name
etc
How can I query this and store it in a 3 dimensional array using PHP.
I have tried to word this in as clear manner as possible, if you are unsure what I am asking, please comment and I will update my question to make it clearer.
Assume that we have two tables, Company and Employee:
Company
------------------
ID Company_Name
1 Walmart
2 Amazon.com
3 Apple
Employee
---------------------------------
ID Company_Id Employee_Name
1 1 Sam Walton
2 1 Rob Walton
3 1 Jim Walton
4 1 Alice Walton
5 2 Jeff Bezos
6 2 Brian T. Olsavsky
7 3 Steve Jobs
8 3 Tim Cook
The easiest way to envision a multi-dimensional (nested) array is to mimic the looping required to get it: outer loop is the company, inner loop is the employees:
// ignoring database access, this is just pseudo code
$outer = [];
// select id, company_name from company
foreach $companyResult as $companyRow {
// select * from employee where company_id = ? {$companyRow['id']}
$inner= [];
foreach $employee_result as $employeeRow {
$inner[] = $employeeRow; // ie, ['id'=>'1','Company_Id'=>'1','Employee_Name'=>'Sam Walton']
}
$outer[] = $inner;
}
print_r($outer);
// yields ====>
Array
(
[0] => Array
(
[0] => Array
(
[id] => 1
[Company_Id] => 1
[Employee_Name] => Sam Walton
)
[1] => Array
(
[id] => 2
[Company_Id] => 1
[Employee_Name] => Rob Walton
)
[2] => Array
(
[id] => 3
[Company_Id] => 1
[Employee_Name] => Jim Walton
)
[3] => Array
(
[id] => 4
[Company_Id] => 1
[Employee_Name] => Alice Walton
)
)
[1] => Array
(
[0] => Array
(
[id] => 5
[Company_Id] => 2
[Employee_Name] => Jeff Bezos
)
[1] => Array
(
[id] => 6
[Company_Id] => 2
[Employee_Name] => Brian T. Olsavsky
)
)
[2] => Array
(
[0] => Array
(
[id] => 7
[Company_Id] => 3
[Employee_Name] => Steve Jobs
)
[1] => Array
(
[id] => 8
[Company_Id] => 3
[Employee_Name] => Tim Cook
)
)
)
It is also possible to do if you use associative arrays. Consider the flat file that this query produces:
select company.id company_id, company.name company_name,
emp.id employee_id, emp.employee_name
from company
inner join employee on company.id = employee.company_id
-----
company_id company_name employee_id employee_name
1 Walmart 1 Sam Walton
1 Walmart 2 Rob Walton
1 Walmart 3 Jim Walton
1 Walmart 4 Alice Walton
2 Amazon.com 5 Jeff Bezos
2 Amazon.com 6 Brian T. Olsavsky
3 Apple 7 Steve Jobs
3 Apple 8 Tim Cook
Just use the primary IDs as the keys for your arrays:
$employeeList = [];
foreach($result as $row) {
$cid = $row['company_name'];
$eid = $row['employee_name'];
// avoid uninitialized variable
// $employeeList[$row['company_name']] = $employeeList[$row['company_name']] ?? [];
// easier to read version of above
$employeeList[$cid] = $employeeList[$cid] ?? [];
// assign it...
$employeeList[$cid][$eid] = $row;
}
Or, if you simply want each company row to hold an array of employee names,
$employeeList[$cid][] = $row['employee_name'];
The way that I've shown you is useful if you know the company_id and want to find the associated rows:
foreach($employeeList[2] as $amazon_guys) { ... }
But it's not at all useful if you're trying to group by employee, or some other field in the employee table. You'd have to organize the order of your indexes by your desired search order.
In the end, it's almost always better to simply do another query and let the database give you the specific results you want.

store all leave to array

I am trying to fetch all employee leave data to an array. But first leave data of my employee is replacing by last leave data. I do not want that.
my data set:
id | emp_id | leave_from | leave_to
2894 886 2019-11-26 2019-11-27
2896 1970 2019-11-20 2019-11-24
2897 1016 2019-11-23 2019-11-23
2898 1870 2019-11-10 2019-11-10
2899 1895 2019-11-09 2019-11-11
2900 1895 2019-11-23 2019-11-23
2901 287 2019-11-27 2019-11-30
my sql query:
$leave_sql = "SELECT l.* FROM 0_employee e right join (SELECT * FROM 0_leave_ledger WHERE (leave_approved_from && leave_approved_to BETWEEN '".$fisrt_date."' AND '".$last_date."' )) l ON l.emp_id = e.emp_id where e.inactive=0";
$leave = get_tb($leave_sql);
$leave_date = array();
foreach ($leave as $leave_d) {
$leave_date[$leave_d["emp_id"]]['type'] = $leave_d["leave_type"];
$leave_date[$leave_d["emp_id"]]['lto'] = $leave_d["leave_approved_to"];
$leave_date[$leave_d["emp_id"]]['lfrom'] = $leave_d["leave_approved_from"];
}
let's look emp_id 1895.It has two rows in my data set. So I am expecting to insert those two rows in my array. But I am getting only last rows of data in my array.
my expecting output from $leave_date is:
[1895] => Array ( [type] => 4 [lto] => 2019-11-09 [lfrom] => 2019-11-11 )
[1895] => Array ( [type] => 4 [lto] => 2019-11-23 [lfrom] => 2019-11-23 )
but I am getting only
[1895] => Array ( [type] => 4 [lto] => 2019-11-23 [lfrom] => 2019-11-23 )
Your problem is that you have an employee who has taken multiple leaves, and the entries for each leave overwrite any previous ones in your array because they have the same array index. You need to change your data structure to allow for that. Try something like this:
$leave_date = array();
foreach ($leave as $leave_d) {
$leave_date[$leave_d["emp_id"]][] = array(
'type' => $leave_d["leave_type"],
'lto' => $leave_d["leave_approved_to"],
'lfrom' => $leave_d["leave_approved_from"]
);
}
For your sample data, this will give you something like
[1895] => Array (
[0] => Array ( [type] => 4 [lto] => 2019-11-09 [lfrom] => 2019-11-11 )
[1] => Array ( [type] => 4 [lto] => 2019-11-23 [lfrom] => 2019-11-23 )
)
The structure of your array $leave_date means it can only store one set of leave data per emp_id. When you iterate, it first fills up with the first leave record, and then the second iteration it gets replaced. If you were to put a print_r() at the end of your foreach you would see this happen for each iteration.
What you may want to do is try something like this:
foreach ($leave as $leave_d) {
$record = [
'type' => $leave_d["leave_type"],
'lto' => $leave_d["leave_approved_to"],
'lfrom' => $leave_d["leave_approved_from"],
]
if(array_key_exists($leave_d['emp_id'], $leave_date) {
$leave_date[$leave_d['emp_d']][] = $record;
} else {
$leave_date[$leave_d['emp_d'] = [$record];
}
This way, $leave_date[1234] will always be an array of leave records.

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)

unable to merge variables with array_merge: undefined index

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
)
)
*/

Return a value not found in the table with MySQL?

Assuming the following array:
$users = array(
// User ID => Username
'72' => 'jack192',
'23' => 'robert1984',
'253' => 'mary111',
'4' => 'jason92'
);
and the following table:
Table myTable:
username | colFoo | colBar
I would like run a query like the following, however I would like the output to additionally include a column not in the table (The user's ID from the array):
$user_string = implode("','", array_values($users));
$query = "SELECT username, colFoo, colBar FROM myTable WHERE username IN ('$user_string')";
This would normally output something like this:
Array
(
[0] => Array
(
[username] => jack192
[colFoo] => 98
[colBar] => 7
)
[1] => Array
(
[username] => robert1984
[colFoo] =>
[colBar] => 2
)
[2] => Array
(
[username] => mary111
[colFoo] => 41
[colBar] => 9
)
[3] => Array
(
[username] => jason92
[colFoo] => 46
[colBar] => 13
)
)
However, I would like the output to look like this, with user_id corresponding to the key in the original array:
Array
(
[0] => Array
(
[username] => jack192
[colFoo] => 98
[colBar] => 7
[user_id] => 72
)
[1] => Array
(
[username] => robert1984
[colFoo] =>
[colBar] => 2
[user_id] => 23
)
[2] => Array
(
[username] => mary111
[colFoo] => 41
[colBar] => 9
[user_id] => 253
)
[3] => Array
(
[username] => jason92
[colFoo] => 46
[colBar] => 13
[user_id] => 4
)
)
I suppose I basically want to just feed the user's ID into the query and get it back out as output, without MySQL doing anything further with it. Is this possible to do purely in SQL without any additional PHP code?
Note: I do not have write access to the DB I'm pulling this data from, and I did not create the schema, so I can't add a user_id field to it or anything.
Here is another way to do it, almost a mashup of the other 2 answers. You can build a 'fake' table and JOIN it to myTable.
SELECT t.username, t.colFoo, t.colBar, s.user_id
FROM myTable t
LEFT JOIN
(
SELECT 72 as user_id, 'jack192' as username
UNION SELECT 23 as user_id, 'robert1984' as username
UNION SELECT 253 as user_id, 'mary111' as username
UNION SELECT 4 as user_id, 'jason92' as username
) s
ON t.username = s.username;
SQLFiddle example - sqlfiddle.com/#!2/64650/2
The fake table structure can be created by a php foreach loop.
$select = '';
foreach ($users as $k => $v){
$select .= "UNION SELECT $k as user_id, '$v' as username\n";
}
echo ltrim($select, "UNION ");
Still a tedious, and not ideal solution, but another option.
You might try CASE
SELECT username, colFoo, colBar,
CASE `username`
WHEN 'jack192' THEN SELECT 72;
WHEN 'robert1984' THEN SELECT 23;
ELSE SELECT NULL;
...
END CASE userid
FROM myTable ...
It will get a bit cumbersome if there are a lot of values in the array.
http://dev.mysql.com/doc/refman/5.0/en/case.html
You can't do this with SQL alone because the id is not defined in the table (not withstanding the cumbersome case statement proposed by Hulka).
Less directly answer the question but providing an alternate solution:
However, you can make a 'small' modification to your php which will accomplish the desired result:
$user_string = implode("','", array_values($users));
foreach ($users as $k => $v){
$query[$k] = "SELECT \"$v\"
,username
,colFoo
,colBar
FROM myTable WHERE username IN ('$user_string')";
}
the query is is basically the same as 'SELECT "6" as user_id, field from TABLE;' for each user, this which would return
6 field
----------
6 value1
6 value2
...
depending on your interface you may be able to prepare and execute, but you did not give enough details to produce specific code.
You would have to run the query multiple times, but you could push or array_merge. Although, I personally think you should use the user_ids as the indexes for this new array. That would require a modest rewrite of above.

Categories