Array joining using an id as reference - php

I have 2 tables. The first table is an equipment table. A query from this table looks like this:
id name user_id
-----------------------
1 equip1 1001
2 equip2 1002
The seconde table is an users table. A query from this table looks like this:
id username
--------------
1001 user1
1002 user2
I want to achieve something like this:
id name user_id username
-----------------------------------
1 equip1 1001 user1
2 equip2 1002 user2
Is there a way to join both arrays like doing a join query? I can't use JOIN in my query, because the tables are on different databases (I know there is a way to do JOIN on different databases, but I'm not allowed to use that).
EDIT:
I'm adding the structure of these arrays.
$equipment = array(
[0] => array(
['id'] => 1,
['name'] => 'equip1',
['user_id'] => 1001
),
[1] => array(
['id'] => 2,
['name'] => 'equip2',
['user_id'] => 1002
)
);
$users= array(
[0] => array(
['id'] => 1001,
['username'] => 'user1'
),
[1] => array(
['id'] => 1002,
['username'] => 'user2'
)
);

You would likely have to join the queries yourself. I don't believe there is a built in function (not counting walk or map with a callback). This is what I would do
//empty array for indexing users under their id for faster loopups
$users = array();
//loop over the users result
foreach($usersResult as $row){
//index users under their id.
$users[$row['id']] = $row['username'];
}
//now loop over the equipment to join the arrays together
foreach($equipmentResult as $key=>$row){
//add the username column
$row['username'] = isset($users[$row['user_id']])?$users[$row['user_id']]:null;
//save back into the equipment row
$equipmentResult[$key] = $row;
}
//display
print_r($equipmentResult);
This could easily be turned into a function where you pass arguments that would build the "ON" portion for the column names.
Edit: Made it a function.
<?php
/**
* Joins two arrays as if they were joined in a query
* #param Array $arrayA The base (left) array to join into
* #param Array $arrayB The right array to join into A
* #param String $colA The column name to join on for arrayA
* #param String $colB [optional] The column name to join on for arrayB. If
* blank, then it is assumed the same column name as colA
* #param boolean $leftJoin [optional] Should this be a left join and include rows
* from A where no value exists in B?
* #return void
*/
function array_join($arrayA, $arrayB, $colA, $colB=null, $leftJoin=false){
//if no value was passed for colB, assume it is the same value as colA
if(is_null($colB)){
$colB = $colA;
}
//output data
$out = array();
//create an index for array B for faster lookups
$idxB = array();
$colsB = array();
foreach($arrayB as $row){
//get the value from B
$valB = $row[$colB];
//if the column doesn't exist in the index, add it
if(!isset($idxB[$colB])){
$idxB[$colB] = array();
}
//index the value
$idxB[$valB][] = $row;
//store the known column to an array for use below
if(empty($colsB)){
$colsB = array_keys($row);
}
}
//loop over array A
foreach($arrayA as $rowA){
//get the value for the column
$valA = $rowA[$colA];
//does the value from A exist in B
$rowB = isset($idxB[$valA])?$idxB[$valA]:null;
//join the rows
//add blank columns if left join
if($leftJoin && is_null($rowB)){
$rowBJoin = array_combine($colsB, array_fill(0, count($colsB), null));
//add the row to our output
$out[] = $rowA + $rowBJoin;
} else {
//inner join or value is not null
//loop over all the rows from the B index that we are joining on
foreach($rowB as $rowBJoin){
//add the row to our output
$out[] = $rowA + $rowBJoin;
}
}
}
return $out;
}

Related

Laravel Collections: Filter with two cloumns

So let's just begin with the question.
I have a database with following structure:
id
first_user_id
second_user_id
1
1
2
1
2
4
1
2
1
And let's say i have a variable with id=1
$id = 1
I find the needed records with this.
Model::where('status',1)
->where('first_user_id', $id)
->orWhere('second_user_id',$id)->get();
I want to get all of the ids that is not equals to the $id in some of the columns.
For exampe:
if first_user_id is equals to $id
return second_user_id column
if second_user_id is equals to $id
return first_user_id column
I want to done that with Laravel Collections if it is possible?
The result must be array with the ids from condition above.
Example output:
Array
(
[0] => 2 // second_user_id from first record
[1] => 2 // first_user_id from the last record.
)
For more clearly here is some pseudo php code for what i exactly want
<?php
$students = [
[
"first_user_id" => 1,
"second_user_id" => 2
],
[
"first_user_id" => 2,
"second_user_id" => 3
],
[
"first_user_id" => 1,
"second_user_id" => 3
],
[
"first_user_id" => 4,
"second_user_id" => 6
],
];
$var = 2; // Authenticated user
$arr = [];
foreach($students as $student) {
if($student['first_user_id'] == $var || $student['second_user_id'] == $var) {
if($student['first_user_id'] == $var) {
$arr[] = $student['second_user_id'];
} else $arr[] = $student['first_user_id'];
}
}
print_r($arr);
Output:
Array
(
[0] => 1
[1] => 3
)
Thank you.
I guess you can use union in that case
$first = DB::table('users')
->where('second_user_id',$id)
->select('first_user_id as user_id');
$users = DB::table('users')
->where('first_user_id',$id)
->select('second_user_id as user_id')
->union($first)
->get(['user_id']);
In SQL it would be like
select first_user_id as user_id from users where second_user_id = :id
union
select second_user_id as user_id from users where first_user_id = :id

Php mysql join to subarray with field names

I trying to join table using ONE query into sub array with column name => column value..
Short table(1) "users" structure with data:
user_id email ...
1 xxx#xx.xx ...
2 yyy#yy.yy ...
Short table(2) "users_permissions" structure with data:
user_id plugin_enter offers_view ...
1 1 0 ...
2 1 1 ...
If i use classic method - join left
SELECT `uperms`.*, `u`.*
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
I get classic output
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'plugin_enter' => 1,
'offers_view' => 0
),
[1] = array(
'user_id' => 2,
'email' => yyy#yy.yy,
'plugin_enter' => 1,
'offers_view' => 1,
...
),
All i need is output into subarray as this:
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'permissions => array(
'plugin_enter' => 1,
'offers_view' => 0
),
),
...
Is this possible to do with ONE query?
Table2 (permissions) contains about 60 columns. Is possible to CONCAT column's names with column value, if is joined to Table1 only one row?
MySQL doesn't have arrays or nested structures, so it's not possible to do this in SQL.
Change your query so you give all the fields from users_permissions a consistent naming style. Then you can use a PHP loop to collect all the array elements whose keys match that pattern into the permissions array.
Query:
SELECT u.*, up.plugin_enter AS perm_plugin_enter, up.offers_view AS perm_offers_view, ...
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
PHP:
foreach ($all_results as &$row) {
$permissions = array();
foreach ($row as $key => $value) {
if (strpos($key, 'perm_') === 0) {
$permission[substr($key, 5)] = $value;
unset($row[$key]);
}
}
$row['permissions'] = $permissions;
}
You could do it by concatenating all the column names and values in the table:
SELECT u.*, CONCAT_WS(',', CONCAT('plugin_enter:', plugin_enter), CONCAT('offers_view:', offers_view), ...) AS permissions
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
Then your PHP code can use explode() to split $row['permissions'] into array of name:value pairs, and then convert those to key=>value in the PHP array.
Another solution is to redesign your users_permissions table:
user_id permission_type value
1 plugin_enter 1
1 offers_view 0
...
2 plugin_enter 1
2 offers_view 1
...
Then you can query:
SELECT u.*, GROUP_CONCAT(permission_type, ':', value) AS permission
FROM users AS u
JOIN users_permissions AS up on u.user_id = up.user_id
Another possible sollution is to add prefixes to query.
Inspired by post: https://stackoverflow.com/a/9926134/2795923
SELECT `u`.*, ':prefix_start:', `uperms`.*, ':prefix_end:'
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
Output array looks like this:
[0] => array(
'user_id' => 1
'email' => xxx#xx.xx,
'prefix_start' =>
'plugin_enter' => 1,
'offers_view' => 0
'prefix_end' =>
)
...
Then easy PHP script to add all array data between prefix_start and prefix_end into own subarray.

How to Order a query

I have an array $sorted_array its value is
Array ( [0] => 3 [1] => 1 [2] => 6 )
Now based on the $sorted_array i created an array
$first_array = Yii::app()->db->createCommand()
->select('*')
->from('form_fields')
->where(array('not in', 'id', $sorted_array))
->andWhere('form_id=:form_id', array(':form_id'=>$form_id))
->queryAll();
$sorted_array value is the id (Primary key) of table form_fields.
When i run this query i get the array $first_array but not in the order in which i want it. ie, I will get an array in order $id=1,3,6.
Now my wanted order is 3,1,6 (exactly as $sorted_array). How can i get $first_array in that order?
You can do using ->order() Add order( 'id' ) to your code this way:
$first_array = Yii::app()->db->createCommand()
->select('*')
->from('form_fields')
->where(array('not in', 'id', $sorted_array))
->andWhere('form_id=:form_id', array(':form_id'=>$form_id))
->order('id')
->queryAll();
otherwise if is not possibile build the query you need with query builder you can use
Yii::app()->db->createCommand("select * from your_table")->queryAll();
and for binding param
Yii::app()->db->createCommand(
'select * from your_table where yuor_field =:your_param')->
bindValue('your_param',$yuor_value)->queryAll();
this returns all rows using a specified SQL statement
$sql = "select * from form_fields
where id not in (3,1,6)
and form_id = " . $form_id .
"order by field(id, 3,6,1);";
$first_array = Yii::app()->db->createCommand($sql)->queryAll();

PHP Mysql Updating positions and parents of an Id in a table

Please I have a table with three columns :
id (this is the id of my table)
parent (this is the parent)
position (and this is the position)
And I have this array $_arr['menu'] :
array (size=3)
13 =>
array (size=1)
'parent' => string '0' (length=1)
14 =>
array (size=1)
'parent' => string '13' (length=2)
25 =>
array (size=1)
'parent' => string '0' (length=1)
I want to update may table with those values in the array $_arr['menu'].
I imagine to do something like but in one query (perhaps using case in) :
UPDATE table SET position = 1, parent = 0 WHERE id = 13;
UPDATE table SET position = 2, parent = 13 WHERE id = 14;
UPDATE table SET position = 3, parent = 0 WHERE id = 25;
Please masters, how to get those values from that array and how to do the update !
Thanks a lot
I'm not sure I got your question, but I'll write my snippet. (I don't remember php syntax well and it's not tested, but I think it shows what I want to say)
try {
$db->beginTransaction();
$increment = 0;
foreach ($arr as $id => $innerArray) {
$db->query("UPDATE table SET position = ".(++$increment).", parent = ".$innerArray['parent']." WHERE id =".$id);
}
$db->commit();
} catch (Exception $e) {
$db->rollback();
}

JOIN in an associative array instead of separated records

Table stores
id name date
1 foo 2011-06-15 15:10:34
2 bar 2011-07-02 16:45:18
Table locations
storeid zipcode latitude longitude
1 90001 xxxxx xxxxx
1 45802 xxxxx xxxxx
2 32843 xxxxx xxxxx
How can i produce an associative array that contains a key called locations which is an array of all locations of a store?
My current SQL ( which separate each location in a record ):
SELECT stores.*, locations.* FROM locations INNER JOIN stores ON stores.id = locations.storeid
Example of what i want:
array(
[0] => array(
"id" => 1,
"name" => "foo",
"locations" => array(
[0] => array(
"zipcode" => 90001,
"latitude" => -45.48513,
"longitude" => 82.12432
)
[1] => array(
"zipcode" => 42802,
"latitude" => -31.48513,
"longitude" => 77.12432
)
)
)
)
and so on for other stores...
Thanks
So you can't extract the data in one query because SQL normally works per row and hasn't got data structure like PHP arrays. You can't nest the records using JOIN. That's why you'll have to do it with with separate queries in a PHP loop. Like so:
$query = "SELECT s.id,s.name FROM stores AS s";
$result = mysql_query($query);
$data = array();
while($row = mysql_fetch_assoc( $result )) {
$data[] = $row['id'];
$data[] = $row['name'];
$query2 = "SELECT l.zipcode, l.latitude, l.longitude FROM locations AS l WHERE storeid=".$row['id'];
$result2 = mysql_query($query2);
while($row2 = mysql_fetch_assoc( $result )) {
$data['locations']['zipcode'] = $row2['zipcode'];
$data['locations']['latitude'] = $row2['latitude'];
$data['locations']['longitude'] = $row2['longitude'];
}
}
Otherwise you can grab all results with JOIN and do as follows:
$query = "SELECT * FROM stores AS s
LEFT JOIN locations AS l
ON s.id = l.storesid";
$result = mysql_query($query);
$data = array();
while($row = mysql_fetch_assoc( $result )) {
$data[$row[id]]['id'] = $row['id'];
$data[$row[id]]['name'] = $row['name'];
$data[$row[id]]['locations'][] = array($row['zipcode'], $row['latitude'], $row['longitude']);
}
But this will make the main array's index to be set not sequential starting from 0 but each index will be equal to the ID of the "store" item

Categories