Adding a key to a multidimensional array from another multidimensional array - php

I have seen lots on adding to multidimensional arrays but I can't figure out how they apply to my situation. I am trying to end up with one large multi-dimensional array.
I have a multidimensional associative array compiled from a mysql query of a membership database. All my arrays are compiled using while loops.
Array(
[0] => Array ( [full_name] => Amy Smith [id] => 00111111 [member_ref] => 1 [type] => 1 )
[1] => Array ( [full_name] => Bob Smith [id] => 00222222 [member_ref] => 2 [type] => 0 )
[2] => Array ( [full_name] => Cam Smith [id] => 00333333 [member_ref] => 3 [type] => 2 )
)
This was compiled from the mysql_query
SELECT full_name, id, member_ref, type
FROM members
ORDER BY full_name asc
I then have a list of [id] numbers in another table for people who have paid membership. This is provided by another organisation. This will become the [paid] key.
Array(
[0] => Array ( [id] => 00111111 )
[1] => Array ( [id] => 00333333 )
[2] => Array ( [id] => 00444444 )
)
From query:
SELECT * FROM paid
And finally a table that counts members attendances within a specified timeframe, to be the [log] key.
Array(
[0] => Array ( [member_ref] => 1 [COUNT(member_ref)] => 17 )
[1] => Array ( [member_ref] => 2 [COUNT(member_ref)] => 10 )
[2] => Array ( [member_ref] => 3 [COUNT(member_ref)] => 1 )
)
From
SELECT member_ref, COUNT(member_ref)
FROM log
WHERE timestamp >= STR_TO_DATE('$from')
AND timestamp < STR_TO_DATE('$to')
GROUP BY member_ref
What i want to end up with is: (Note that Bob Smith hasn't paid)
Array(
[0] => Array ( [full_name] => Amy Smith [id] => 00111111 [member_ref] => 1 [type] => 1 [paid] => 00111111 [log] => 17)
[1] => Array ( [full_name] => Bob Smith [id] => 00222222 [member_ref] => 2 [type] => 0 [paid] => 0 [log] => 10)
[2] => Array ( [full_name] => Cam Smith [id] => 00333333 [member_ref] => 3 [type] => 2 [paid] => 00333333 [log] => 1)
)
I can then output it as necessary, but crucuially I can sort the data by any of the keys.
I am open to doing this with a single mysql query with the sort key being a php $var, but I can't figure out the JOIN elements, it's just far too complex for me to understand.
Thanks

Working from the answer of NSjonas:
SELECT m.full_name,
m.id,
m.member_ref,
m.type,
(p.id IS NOT NULL) paid,
COUNT(l.member_ref) log
FROM members m
LEFT JOIN paid p
ON m.id = p.id
LEFT JOIN log l
ON m.member_ref = l.member_ref
AND l.timestamp >= '$from'
AND l.timestamp < '$to'
GROUP BY m.full_name, m.id, m.member_ref, m.type, p.id
ORDER BY m.full_name ASC

My mySQL is a bit rusty but I think this is basically what your looking for. Definitely possible in 1 query
SELECT m.full_name, m.id, m.member_ref, m.type, COUNT(l.member_ref) log,
Case WHEN p.Id != null
THEN true
ELSE false paid
FROM members m
LEFT JOIN paid p
ON m.id = p.id
LEFT JOIN log l
ON m.member_ref = l.member_ref
WHERE l.timestamp >= STR_TO_DATE('$from')
AND l.timestamp < STR_TO_DATE('$to')
ORDER BY m.full_name asc

Related

How can i reformat array this array?

So i have this database table
From that table i want to achievie this (My Expected result)
I don't know the best way to handle this, so for now i create two query.
My first query
SELECT * FROM ( select convert(created_date,date) created_date,code,'' code2,count(code) total, 0 total2
from morning_briefing
where convert(created_date,date) = convert('" . $selected_date . "',date) and code IS NOT NULL
group by code order by created_date desc) a order by total desc
My second query
SELECT * FROM ( select convert(created_date,date) created_date,''code,code2,0 total,count(code2) total2
from morning_briefing
where convert(created_date,date) = convert('" . $selected_date . "',date)
and code2 IS NOT NULL
group by code2 order by created_date desc) a order by total2 desc
Below is result for my query
Array
(
[0] => stdClass Object
(
[created_date] => 2021-03-16
[code] => AA
[code2] =>
[total] => 2
[total2] => 0
)
[1] => stdClass Object
(
[created_date] => 2021-03-16
[code] => AB
[code2] =>
[total] => 1
[total2] => 0
)
[2] => stdClass Object
(
[created_date] => 2021-03-16
[code] => BB
[code2] =>
[total] => 1
[total2] => 0
)
)
then my second query result is this
Array
(
[0] => stdClass Object
(
[created_date] => 2021-03-16
[code] =>
[code2] => AB
[total] => 0
[total2] => 2
)
[1] => stdClass Object
(
[created_date] => 2021-03-16
[code] =>
[code2] => AA
[total] => 0
[total2] => 1
)
)
So, i want to merge both of the array , then i want to order total column desc, the second order is total2
Btw, i'm using mysql table. So how can i achieve my expected result (above), thanks in advance.
You can loop through your $results1 and $result2 and create a new array that contains data in your expected result format.
$total = max(count($result1), count($result2));
$formatted = [];
for($i = 0; $i < $total; $i++) {
$formatted[] = [
'code' => isset($result1[$i]) ? $result1[$i]->code : '-',
'total' => isset($result1[$i]) ? $result1[$i]->total : 0,
'code2' => isset($result2[$i]) ? $result2[$i]->code2: '-',
'total2' => isset($result2[$i]) ? $result2[$i]->total2 : 0
];
}

Is there any possibility to assign an alias to all columns of a table at once?

As mentioned above, I am trying to assign an alias to all columns of a table at once as there is an obvious problem in PDO if a column name is used in more than one table.
If I'm trying this SQL statement:
SELECT t12.*,t1.*,t2.* FROM `tableone2tabletwo` t12
LEFT JOIN tableone t1 ON t12.idone=t1.id
LEFT JOIN tabletwo t2 ON t12.idtwo=t2.id
I'll receive an array like this with$stmt->fetch():
Array
(
[id] => 2
[0] => 1
[idone] => 1
[1] => 1
[idtwo] => 2
[2] => 2
[3] => 1
[name] => Test2TwoText
[4] => Test1Text
[5] => 2
[6] => Test2TwoText
)
As you see, the field gets overwritten(the last time by the last element with this name... ;-)), even though the table has an alias.
fetch(PDO::FETCH_ASSOC) as Andrii Filenko recommended returns this:
Array
(
[id] => 2
[idone] => 1
[idtwo] => 2
[name] => Test2TwoText
)
So here the data is even lost, not only just available via the numeric indices.
fetch(PDO::FETCH_NAMED) as Nigel Ren recommended returns this:
Array
(
[id] => Array
(
[0] => 1
[1] => 1
[2] => 2
)
[idone] => 1
[idtwo] => 2
[name] => Array
(
[0] => Test1Text
[1] => Test2TwoText
)
)
Is there a simple and stylish solution for this problem or will I have to do this one by one?
(My DB is available at DB-fiddle if you want to take a look!)

Pivoting table in mysql

I have entries and entrymeta table structure as. id is the primary key and entry_id in entrymeta is foreign key to id in entries table.
entries table:
id created_at
1 2017-04-03
2 2017-07-05
entrymeta table:
id entry_id(foreign key to id) meta_key meta_value
1 1 Name Smith
2 1 Address Saniply
3 1 Profession Student
4 2 Name John
5 2 Address Aviero
6 2 Profession Businessman
When I execute a query:
$query = 'SELECT entry_id, created_at, meta_key, meta_value FROM entries INNER JOIN entrymeta WHERE entries.id = entrymeta.entry_id';
$wpdb->get_results( $query );
I get the result like:
Array
(
[0] => stdClass Object
(
[entry_id] => 1
[created_at] => 2017-04-03
[meta_key] => Name
[meta_value] => Smith
)
[1] => stdClass Object
(
[entry_id] => 1
[created_at] => 2017-04-03
[meta_key] => Address
[meta_value] => Saniply
)
[2] => stdClass Object
(
[entry_id] => 1
[created_at] => 2017-04-03
[meta_key] => Profession
[meta_value] => Student
)
[3] => stdClass Object
(
[entry_id] => 2
[created_at] => 2017-07-05
[meta_key] => Name
[meta_value] => John
)
[4] => stdClass Object
(
[entry_id] => 2
[created_at] => 2017-07-05
[meta_key] => Address
[meta_value] => Aviero
)
[5] => stdClass Object
(
[entry_id] => 2
[created_at] => 2017-07-05
[meta_key] => Profession
[meta_value] => Businessman
)
)
How can I achieve something like this instead?
Array
(
[0] => stdClass Object
(
[entry_id] => 1
[created_at] => 2017-04-03
[Name] => Smith
[Address] => Saniply
[Profession] => Student
)
[1] => stdClass Object
(
[entry_id] => 2
[created_at] => 2017-07-05
[Name] => John
[Address] => Aviero
[Profession] => Businessman
)
)
I am using wordpress, if it has any other simpler methods to achieve this please let me know. Thanks!
I am writing your array of objects (resultset) as $array. My method will assign temporary keys to merge the duplicate entry-id objects. Using isset() means that no unnecessary values overwrites occur while iterating.
Code: (Demo)
$array=[
(object)['entry_id'=>1,'created_at'=>'2017-04-03','meta_key'=>'Name','meta_value'=>'Smith'],
(object)['entry_id'=>1,'created_at'=>'2017-04-03','meta_key'=>'Address','meta_value'=>'Saniply'],
(object)['entry_id'=>1,'created_at'=>'2017-04-03','meta_key'=>'Profession','meta_value'=>'Student'],
(object)['entry_id'=>2,'created_at'=>'2017-07-05','meta_key'=>'Name','meta_value'=>'John'],
(object)['entry_id'=>2,'created_at'=>'2017-07-05','meta_key'=>'Address','meta_value'=>'Aviero'],
(object)['entry_id'=>2,'created_at'=>'2017-07-05','meta_key'=>'Profession','meta_value'=>'Businessman']
];
foreach($array as $obj){ // iterate all objs
$id=$obj->entry_id; // cache for more readable code
if(!isset($result[$id])){ // first occurrence of entry_id
$result[$id]=new \stdClass(); // avoid Warning: Creating default object from empty value
$result[$id]->entry_id=$id; // store entry_id
$result[$id]->created_at=$obj->created_at; // store created_at
}
$result[$id]->{$obj->meta_key}=$obj->meta_value; // unconditionally store meta_key and meta_value
}
var_export(array_values($result)); // remove temporary indexes and display
Output:
array (
0 =>
stdClass::__set_state(array(
'entry_id' => 1,
'created_at' => '2017-04-03',
'Name' => 'Smith',
'Address' => 'Saniply',
'Profession' => 'Student',
)),
1 =>
stdClass::__set_state(array(
'entry_id' => 2,
'created_at' => '2017-07-05',
'Name' => 'John',
'Address' => 'Aviero',
'Profession' => 'Businessman',
)),
)
You have to join entrymeta once for every key you want to include in your result, which isn't very scalable.
SELECT
e.*,
m_name.meta_value Name,
m_addr.meta_value Address,
m_prof.meta_value Profession
FROM
entries e
JOIN entrymeta m_name ON m_name.entry_id = e.id
AND m_name.meta_key = 'Name'
JOIN entrymeta m_addr ON m_addr.entry_id = e.id
AND m_addr.meta_key = 'Address'
JOIN entrymeta m_prof ON m_prof.entry_id = e.id
AND m_prof.meta_key = 'Profession'

mysql select all, group by orderid

I was wondering if anyone could help me with selecting information from my table, but grouping the results depending on the order id. I'm sure this is quite simple, but I can't seem to get the code working.
Here's my attempt - which is only showing 1 result, instead of 6:
4 results with orderid 55542
2 results with orderid 55543
SQL:
SELECT *
FROM #__users_orders
WHERE userid = 22
GROUP BY orderid
ORDER BY date DESC
Any help would be appreciated :)
EDIT:
I'd like to acheive this (or something similar)
Array[55542]
(
[0] => stdClass Object
(
[id] => 6
[userid] => 66
[orderid] => 55542
[date] => 2011-08-05 16:30:24
[code] => 121021
[title] => 7 STAR CHICKEN A/KING 71198 1.3KG
[units] => 2
[ctns] =>
)
[1] => stdClass Object
(
[id] => 1
[userid] => 66
[orderid] => 55542
[date] => 2011-08-05 16:06:12
[code] => 302371
[title] => ANCHOVY FILL 730GM
[units] => 2
[ctns] =>
)
[2] => stdClass Object
(
[id] => 6
[userid] => 66
[orderid] => 55542
[date] => 2011-08-05 16:30:24
[code] => 121021
[title] => 7 STAR CHICKEN A/KING 71198 1.3KG
[units] => 2
[ctns] =>
)
[3] => stdClass Object
(
[id] => 1
[userid] => 66
[orderid] => 55542
[date] => 2011-08-05 16:06:12
[code] => 302371
[title] => ANCHOVY FILL 730GM
[units] => 2
[ctns] =>
)
)
Array[55543]
(
[0] => stdClass Object
(
[id] => 6
[userid] => 66
[orderid] => 55543
[date] => 2011-08-05 16:30:24
[code] => 121021
[title] => 7 STAR CHICKEN A/KING 71198 1.3KG
[units] => 2
[ctns] =>
)
[1] => stdClass Object
(
[id] => 1
[userid] => 66
[orderid] => 55543
[date] => 2011-08-05 16:06:12
[code] => 302371
[title] => ANCHOVY FILL 730GM
[units] => 2
[ctns] =>
)
)
SELECT *
FROM #__users_orders
WHERE userid = 22
ORDER BY orderid DESC
Just select your items like this and create your object/array hierarchy in the frontend by iterating over the results and creating a new array for every new orderid that comes by.
SELECT orderid, COUNT(*)
FROM #__users_orders
WHERE userid = 22
GROUP BY orderid
ORDER BY date DESC
Normally, you have to use an aggregate (eg COUNT, SUM) and GROUP BY matched. So that columns in the SELECT but not in the COUNT or SUM are in the GROUP BY
Only MySQL allows you to not follow this rule. Other DB engines would give an error.
the query seems ok, maybe your extracting the results the wrong way
SELECT * FROM table GROUP BY field1;
should return same number of rows than
SELECT field1, field2 FROM table GROUP BY field1;
but different number than
SELECT * FROM table;
You should not select "*" in this query.
When you group by "some columns". You can only select "some columns" or some_aggregate_function(other columns).
e.g. If you want to get the aggregate ordersize and latest date for each order id, you would do something like -
SELECT orderid, sum(ordersize), max(date) FROM #__users_orders WHERE userid = 22 GROUP BY orderid ORDER BY max(date) DESC

Recursively sort array to levels

I've been working on a site that uses binary mlm system.
Illustration here
So I have a two tables in database, users anad relationships. There is ID and personal data columns in users. Relationships has 4 columns: ID, parentID, childID, pos. Where pos is either left or right.
I have succesfully written a function that recursively lists all children of given pid (parentID). However I need to sort it in levels (for display and calculation purposes).
I have an array of children of user ID = 1:
Array
(
[0] => Array
(
[id] => 2
[parentID] => 1
[pos] => l
)
[1] => Array
(
[id] => 4
[parentID] => 2
[pos] => l
)
[2] => Array
(
[id] => 8
[parentID] => 4
[pos] => l
)
[3] => Array
(
[id] => 5
[parentID] => 2
[pos] => p
)
[4] => Array
(
[id] => 3
[parentID] => 1
[pos] => p
)
[5] => Array
(
[id] => 6
[parentID] => 3
[pos] => l
)
[6] => Array
(
[id] => 7
[parentID] => 3
[pos] => p
)
)
Now I have function named get_levels that returns an multidimensional array that should look like this:
Array
(
[0] => Array
(
[0] => Array
(
[id] => 2
[parentID] => 1
[pos] => l
)
[1] => Array
(
[id] => 3
[parentID] => 1
[pos] => p
)
)
[1] => Array
(
[0] => Array
(
[id] => 4
[parentID] => 2
[pos] => l
)
[1] => Array
(
[id] => 5
[parentID] => 2
[pos] => p
)
[2] => Array
(
[id] => 6
[parentID] => 3
[pos] => l
)
[3] => Array
(
[id] => 7
[parentID] => 3
[pos] => p
)
)
ETC.
)
Here's the function:
function get_levels($pid,$level, $level_id){
$children = children_array($pid,1);
if (sizeof($children) > 0):
foreach ($children as $child):
if ($child["parentID"] == $pid):
get_levels($child["id"], $level, $level_id+1);
$level[$level_id][] = $child;
endif;
endforeach;
endif;
return $level;
}
function children_array($pid, $depth) returns the children ... for $depth = 1 it returns immediate children (0 or 1 or 2), for $depth = 0 it returns all children
Can anyone help me with this function? I think the function works, however I don't know how to recursively use and add to array.
Looks like you're using a data structure within the wrong context. It's a binary tree, yet it's represented into a multilevel array which in short doesn't define its boundaries and rules of use.
When using the tree, I would use something like a Node class that has two children, left and right. Iterating through the tree would be piece of cake, inserting/deleting/editing into it is easily done depending on which set of rules you want to follow. When storing the tree, I would use some kind of Ahnentafel list which can easily be done in a relational database.
I would in no way mix both iteration and storage processes because if I change the rules of storage, I might also have to change the rules of iteration and vice versa.

Categories