I have created a MySQL database table where I want to show the menu structure based on their parent. The menu table contains the following data:
id | menuname | parentid
---+-------------------+---------
1 | dashboard | 0
2 | Content | 0
3 | Home Page Content | 2
4 | Banners | 2
5 | Settings | 0
6 | Block Content | 3
7 | Site Content | 3
So that the menu structure will look like:
dashboard
Content
Home Page Content
Block Content
Site Content
Banners
Settings
I have gone though the post over here Recursive menu tree from array
however, unable to understand the basics. However, the idea I understood that I need to write a recursive function to sort out this. Can someone give me some ideas how to generate the above?
Imagine you are selected from database with sql query
SELECT * FROM my_table ORDER BY parentid ASC, id ASC
and you have this array in PHP
$arr = [
[
"id"=>1,
"username"=>"dashboard",
"parentid"=>0
],
[
"id"=>2,
"username"=>"dashboard",
"parentid"=>0
],
[
"id"=>5,
"username"=>"dashboard",
"parentid"=>0
],
[
"id"=>3,
"username"=>"dashboard",
"parentid"=>2
],
[
"id"=>4,
"username"=>"dashboard",
"parentid"=>2
],
[
"id"=>6,
"username"=>"dashboard",
"parentid"=>3
],
[
"id"=>7,
"username"=>"dashboard",
"parentid"=>3
],
];
$categories = [];
foreach ($arr as $item){
if($item["parentid"]==0){
$categories[$item["id"]] = $item;
}else{
$categories[$item["parentid"]]["subs"][] = $item;
}
}
Related
I have an array, $submenus, in my app that I implode to a delimited string:
$subs = implode(',', $submenus);
The string will look something like this: 'ml_,nc_,msr_'. These values are stored in a field called group_prefix in my submenus table. Each submenu row has a unique group_prefix.
The following code builds menus and submenus from a database:
$menus = $this->Menus->find('all', [
'order' => ['Menus.display_order ASC'],
'conditions' => $conditions,
'contain' => [
'Submenus' => [
'conditions' => [
'Submenus.status' => 1,
'FIND_IN_SET("' . $subs . '", Submenus.group_prefix)'
],
]
]
]);
$this->set('menus', $menus);
It works fine until I add the FIND_IN_SET condition on Submenus. When I do, I get no submenus returned, just the main menus. Debug confirms that the string is formatted propery. Doesn't error out, I just get no resultset.
When I run the submenus query in MySQL, it works.
set #prefixes = 'ml_,nc_,msr_';
SELECT `id`, `name` FROM `submenus` WHERE `status` = 1 AND FIND_IN_SET(`submenus`.`group_prefix`, #prefixes);
+----+---------------------------+
| id | name |
+----+---------------------------+
| 4 | Mission Lessons Module |
| 5 | MSR Module |
| 8 | Work Authorization Module |
+----+---------------------------+
What am I missing?
Answer was to reverse the order of arguments in FIND_IN_SET.
Im trying to build a SQL Query that will select all orders from a table that matches options that i defined.
Databse i use: Mysql
Language: PHP
Basicly i have a array that looks like this.
[
[
"user_id" => 1,
"product_id" => 5548,
"variation_id" => 14
],
[
"user_id" => 1,
"product_id" => 5548,
"variation_id" => 15
],
[
"user_id" => 1,
"product_id" => 4422,
"variation_id" => 4
]
]
This means that the user(id: 1) has one product with the "id" of 5548, and then he also has 2 variations of that product that are "id" 14 and 15. You can also see that the same user owns the product(id:4422) that has variation(id:4).
I then have a "order_lines" table that looks like this
order_lines
+----+-----+---------+-----------------------------+
| id | uid | user_id | product_id | variation_id |
+----+-----+---------+-----------------------------+
| 1 | 1 | 1 | 5548 | 14 |
+----+-----+---------+-----------------------------+
| 2 | 2 | 1 | 5548 | 15 |
+----+-----+---------+-----------------------------+
| 3 | 3 | 1 | 4422 | 4 |
+----+-----+---------+-----------------------------+
| . | . | . | .... | .. |
+----+-----+---------+-----------------------------+
I now need a SQL Query that selects all the rows where there is a match between the user_id, product_id and variation_id that are defined in the array.
The output should contain all rows that meet these conditions.
I hope someone can pin me in the right direction.
I'm building in Laravel if you got the query builder just at your hand. Else i very much appreciate an SQL Query.
if I am getting you right, below code will help you, using just Core PHP
foreach($array as $arr){
$user_id = $arr['user_id'];
$prodct_id = $arr['prodct_id'];
$variation_id = $arr['variation_id'];
$query = "SELECT * FROM order_lines WHERE user_id = $userId AND product_id = $productId AND variation_id = $variationId";
$queryResult = mysql_fetch_assoc($query);
$yourCollection[] = $queryResult;
}
print_r($yourCollection);
Try below code to use Laravel Query Builder, below code will help you to get results for multiple users based on product and variation.
$qb_order_lines = DB::table('order_lines');
$where_condition = [
['user_id' => '', 'product_id' => '', 'variation_id' => ''],
];
foreach ($where_condition as $condition) {
$qb_order_lines->orWhere(function($query) use ($condition) {
$query->where('user_id', $condition['user_id'])
->where('product_id', $condition['product_id'])
->where('variation_id', $condition['variation_id']);
});
}
$obj_result = $qb_order_lines->get();
If you want to get it for only one user, use below code
$obj_result = DB::table('order_lines')
->where('user_id', $condition['user_id'])
->where('product_id', $condition['product_id'])
->where('variation_id', $condition['variation_id'])
->get();
You can modify the above query builders based on your requirements like select fields or group by.
Let me know if you need any help.
For anyone interesting.
My problem was that i needed to count of many matches that were between my array and my database.
Instead of selecting and outputting. I eneded up using sql count() function in a query, that did the job.
My database is storing a list like this:
ID | name
--- -----
1 | search
2 | search.categories
3 | search.categories.accessories
4 | search.categories.accessories.glasses
5 | search.categories.accessories.hats
6 | filters
7 | filters.payments
8 | filters.payments.creditcard
9 | filters.payments.debitcard
Now I want to SELECT it in a recursivelly array just like this:
[
name, childs[
name, childs[ ... ],
name, childs[ ... ],
name, childs[
name, childs[ ... ],
name, childs[ ... ],
],
],
name, childs[
name, childs[ ... ],
name, childs[ ... ],
name, childs[
name, childs[ ... ],
name, childs[ ... ],
],
]
]
What is the best way to achive this? Directly from MySQL or manually string handling?
If you are working with Laravel you can build a nested array by using array_set and using as key the name column of your table, taking advantage that you are already storing on dot notation.
Despite you are not exposing what's the purpose of this and why you want to build this structure this way, follows one possible approach.
Initialize an empty array ($structure = [])
Retrieve all table records an iterate them (use a DB select or model get as you prefer)
For each table row, perform an array_set($structure, $listname, $value)
In your example, I don't see where $value could be coming from, but I guess you will grasp the idea.
$structure = [];
foreach($rows as $row)
{
array_set($structure, $row->name, $value);
}
Im trying to get all id's that are related to a specific list but my query is only returning the first related id in the table and not the others.
Tables
List | id | person_id | name | description
| 1 | 10 | Test List | null
List_Ref | id | list_id | data_id
| 1 | 1 | 100
| 2 | 1 | 101
Query
$lists = DB::table('List')
->leftJoin('List_Ref', 'List_Ref.list.id', '=', 'List.id')
->select('List.id', 'List.name', 'List_Ref.data_id')
->where('person_id', Auth::user()->person_id)
->groupBy('List.id')
->orderBy('List.id')
->get();
Result (Laravel Die and Dump)
#items: array:1 [
0 => {
"id" : 1
"name" : "Test List"
"data_id" " 100
}
]
I would like to produce a result like the following
#items: array:1 [
0 => {
"id" : 1
"name" : "Test List"
"data_id" => {
"id" : 100
"id" : 101
}
}
]
If you want to get available grouped items don't use group by while building your query.
Do like this:
$lists = DB::table('List')
->leftJoin('List_Ref', 'List_Ref.list.id', '=', 'List.id')
->select('List.id', 'List.name', 'List_Ref.data_id')
->where('person_id', Auth::user()->person_id)
->get();
$lists->groupBy('List.id')->orderBy('List.id');
Use laravel collection's groupBy and orderBy method to get the grouped items. Hope it helps you!
I dont know laravel but you are doing a left join from "List" to "List_Ref".
So every entry in Talbe List will be matched with ONE entry of List_Ref.
Try Full join.
Don't use groupBy('List.id') It will group the data on the basis of id of List table & always return only single data.
I have two tables, a main one, and one that supports the main table, very very similar to what wordpress has, posts and posts_meta.
Main table:
id
title,
content
id | title | content
1 | one | content one
2 | two | content two
Meta table:
id
item_id
key
value
id | item_id | key | value
1 | 1 | template | single
2 | 1 | group | top
1 | 2 | template | page
2 | 2 | group | bottom
And my goal is, in the end, have an array with the data from the main table, merged with the meta table. example:
$data = array(
array(
'id' => 1,
'title' => 'one',
'content' => 'content one',
'template' => 'single',
'group' => 'top'
),
array(
'id' => 2,
'title' => 'two',
'content' => 'content two',
'template' => 'page',
'group' => 'bottom'
)
);
What is the best way to achieve this in a way that preforms good?
I am using PDO to connect to my database, and how Im doing right now is, I first query the data on the first table, and then for each result, i query the meta table, I use prepared statements for this, since it's suposed to be fast, but even so, it's harming the performance of my script.
Thank you
Instead of querying meta table for each result from first query
you should extract the ids from the first result:
$rows = q('SELECT * FROM posts');
$byIds = [];
foreach ($rows as &$row)
{
$byIds[$row['id']] =& $row;
}
and run second query:
$rows2 = q('SELECT * FROM posts_meta WHERE item_id IN (' . implode(',', array_keys($byIds)) . ')');
Then loop the results in PHP and merge with first query results.
foreach ($rows2 as $row2)
{
$byIds[$row2['item_id']][$row2['key']] = $row2['value'];
}
You have your merged results in $rows variable now:
var_dump($rows);
This way you will have only 2 db requests.
Please note that i have used $byIds as array of references so i dont have to search row with specific id in second loop. This way order of elements in $rows are preserved.