I am confused. I don't know how to create a tree view in MySQL using stored procedure. I tried searching in Google and I don't understand how to query.
I have
deptid | dept_code | dept_name | parent_deptid
1 1 wadir Umum 0
2 101 bagian umum 1
3 10101 kepala umum 2
4 102 bagian privasi 1
5 1010101 SUb bagian Tu 3
6 1010102 bagian umum 3
and I want to make it like this
deptid | dept_code | dept_name | parent_deptid
1 1 wadir Umum 0
2 101 -bagian umum 1
3 10101 --kepala umum 2
5 1010101 ---Sub bagian Tu 3
6 1010102 ---bagian umum 3
4 102 -bagian privasi 1
Since department code pattern looks to be convenient, I didn't spent time on parent_id. According to your department code pattern, following should help.
Simply padding the dept code and getting the sortable uniform codes.
Change your tableName in query please.
SELECT *
FROM tableName
ORDER BY RPAD(dept_code, 5, '0')
EDIT: Actually if parent_deptid was the actual parent's id then you would have just needed to sort by parent_deptid, then dept_code. However, parent_deptid doesn't look like the corresponding parent's id but something like "depth" instead.
EDIT2: Sorry, your parent_deptid looks to be ok, just needed to see more data showing other parent ids too. So I missed it. All you need to sort as following:
SELECT *
FROM tableName
ORDER BY parent_deptid, dept_code;
EDIT3 - According to edited question: Back to my initial suggestion by changing the padded string length - Following is the most suitable solution for your data structure.
SELECT *
FROM tableName
ORDER BY RPAD(dept_code, 10, '0')
10 could be the max length of your dept_code.
Chnage your dept_code column type to VARCHAR and use next query
SELECT *
FROM tableName
ORDER BY dept_code
The following query will create a markup output:
SELECT group_concat(
CONCAT(
REPEAT(' ', (CHAR_LENGTH(t.dept_code) - 1) / 2),
'- ',
t.dept_name
)
ORDER BY t.dept_code
SEPARATOR '\n'
) AS markup
FROM Table1 t
sqlfiddle
Result:
- wadir Umum
- bagian umum
- kepala umum
- SUb bagian Tu
- bagian umum
- bagian privasi
Will be rendered to:
wadir Umum
bagian umum
kepala umum
SUb bagian Tu
bagian umum
bagian privasi
Update
To match the question update:
SELECT t.*,
CHAR_LENGTH(t.dept_code) - CHAR_LENGTH(REPLACE(t.dept_code, '0', '')) AS indent,
CONCAT(
REPEAT('-', CHAR_LENGTH(t.dept_code) - CHAR_LENGTH(REPLACE(t.dept_code, '0', ''))),
t.dept_name
) AS indented_name
FROM Table1 t
ORDER BY t.dept_code
sqlfiddle
Update 2
The benefit of your design is that you do not need a stored procedure for such tasks. See the dept_code as the full tree path with 0 as separator. 1010102 could also be written as 1/1/1/2. If designed correctly you can just order by dept_code. To get node depth you just need to count the separator (0) in the path (dept_code).
Update 3
If you want to create a recursive structure, you better do in a procedural language like PHP:
Store SQL result from a simple query (SELECT * FROM depts) into an array, which would look like:
// result from query: SELECT * FROM depts
$depts = array(
array( // row #0
'deptid' => 1,
'dept_code' => '1',
'dept_name' => 'wadir Umum',
'parent_deptid' => 0,
),
array( // row #1
'deptid' => 2,
'dept_code' => '101',
'dept_name' => 'bagian umum',
'parent_deptid' => 1,
),
array( // row #2
'deptid' => 3,
'dept_code' => '10101',
'dept_name' => 'kepala umum',
'parent_deptid' => 2,
),
array( // row #3
'deptid' => 4,
'dept_code' => '102',
'dept_name' => 'bagian privasi',
'parent_deptid' => 1,
),
array( // row #4
'deptid' => 5,
'dept_code' => '1010101',
'dept_name' => 'SUb bagian Tu',
'parent_deptid' => 3,
),
array( // row #5
'deptid' => 6,
'dept_code' => '1010102',
'dept_name' => 'bagian umum',
'parent_deptid' => 3,
),
);
Build a recursive structure with two foreach loops:
$nodes = array();
$roots = array();
// init nodes
foreach ($depts as $dept) {
$dept['childs'] = array(); // init childs
$nodes[$dept['deptid']] = $dept;
}
foreach ($depts as $dept) {
if ($dept['parent_deptid'] == 0) {
$roots[] = $dept['deptid']; // add root
} else {
$nodes[$dept['parent_deptid']]['childs'][] = $dept['deptid']; // add to parents chlids list
}
}
The arrays $roots and $nodes will look like:
$roots = array (0 => 1,);
$nodes = array(
1 => array(
'deptid' => 1,
'dept_code' => '1',
'dept_name' => 'wadir Umum',
'parent_deptid' => 0,
'childs' => array(
0 => 2,
1 => 4,
) ,
) ,
2 => array(
'deptid' => 2,
'dept_code' => '101',
'dept_name' => 'bagian umum',
'parent_deptid' => 1,
'childs' => array(
0 => 3,
) ,
) ,
3 => array(
'deptid' => 3,
'dept_code' => '10101',
'dept_name' => 'kepala umum',
'parent_deptid' => 2,
'childs' => array(
0 => 5,
1 => 6,
) ,
) ,
4 => array(
'deptid' => 4,
'dept_code' => '102',
'dept_name' => 'bagian privasi',
'parent_deptid' => 1,
'childs' => array() ,
) ,
5 => array(
'deptid' => 5,
'dept_code' => '1010101',
'dept_name' => 'SUb bagian Tu',
'parent_deptid' => 3,
'childs' => array() ,
) ,
6 => array(
'deptid' => 6,
'dept_code' => '1010102',
'dept_name' => 'bagian umum',
'parent_deptid' => 3,
'childs' => array() ,
) ,
)
Demo
Now you can write some recursive function to walk through the tree:
function getSubtreeHTMLList($deptsids, $nodes) {
$result = '<ul>';
foreach ($deptsids as $deptsid) {
$result .= '<li>';
$result .= $nodes[$deptsid]['dept_name'];
if (count($nodes[$deptsid]['childs'] > 0)) {
$result .= getSubtreeHTMLList($nodes[$deptsid]['childs'], $nodes);
}
$result .= '</li>';
}
$result .= '</ul>';
return $result;
}
echo getSubtreeHTMLList($roots, $nodes);
Created HTML:
<ul><li>wadir Umum<ul><li>bagian umum<ul><li>kepala umum<ul><li>SUb bagian Tu<ul></ul></li><li>bagian umum<ul></ul></li></ul></li></ul></li><li>bagian privasi<ul></ul></li></ul></li></ul>
Demo
Rendered:
wadir Umumbagian umumkepala umumSUb bagian Tubagian umumbagian privasi
Related
Concept:
Adding Floors and Room counts and Room Numbers in a Hotel and saving it in a db
Front end Design:
Please have a look at this image
Backend what i am getting now:
"floor" => array:3 [▼
0 => "3"
1 => "2"
2 => "1"
]
"room_count" => array:3 [▼
0 => "3"
1 => "3"
2 => "5"
]
"room_number" => array:11 [▼
0 => "101"
1 => "102"
2 => "103"
3 => "201"
4 => "202"
5 => "203"
6 => "101"
7 => "102"
8 => "103"
9 => "104"
10 => "105"
]
The Question is:
How can i loop through to get:
Floor 3 has the room numbers 101, 102, 103
Floor 2 has the room numbers 201, 202, 203
Floor 1 has the room numbers 101, 102, 103, 104, 105
Iterate through each floor, count the number of rooms, and then determine which room numbers are associated with that floor by working through the array of room numbers.
Given the array structure you're working with, the trick is that you'll need to have a loop like this one that can track the $prev_index by incrementing $prev_index by the room count at each floor.
<?php
$array = array(
'floor' => array(
0 => '3',
1 => '2',
2 => '1',
),
'room_count' => array(
0 => '3',
1 => '3',
2 => '5',
),
'room_number' => array(
0 => '101',
1 => '102',
2 => '103',
3 => '201',
4 => '202',
5 => '203',
6 => '101',
7 => '102',
8 => '103',
9 => '104',
10 => '105',
),
);
for ($prev_index = 0, $i = 0; $i < count($array['floor']); ++$i) {
$floor = $array['floor'][$i];
$room_count = $array['room_count'][$i];
$room_numbers = array_slice($array['room_number'], $prev_index, $room_count);
$prev_index = $prev_index + $room_count;
echo 'Floor '.$floor.' has '.$room_count.' rooms, with room numbers '.implode(', ', $room_numbers)."\n";
}
Floor 3 has 3 rooms, with room numbers 101, 102, 103
Floor 2 has 3 rooms, with room numbers 201, 202, 203
Floor 1 has 5 rooms, with room numbers 101, 102, 103, 104, 105
I have an array:
Array
(
[10 - 20] => 3
[20 - 30] => 43
[30 - 40] => 5
[40 - 50] => 1
[50 - 60] => 0
[60 - 70] => 0
)
I want to make new array that will send via json. Now I have result in json like this(thanks for guys below who answered my question):
{"success":true,"data":["3","43","5","1","0","0"]}
I need json to be {"success":true,"data":[3,43,5,1,0,0]}, cause only with that format data show in line chart of highchart
Sorry for my stupid questionThank You
Update
Here's how you can get your response...
$values = array
(
'10 - 20' => 3,
'20 - 30' => 43,
'30 - 40' => 5,
'40 - 50' => 1,
'50 - 60' => 0,
'60 - 70' => 0,
);
$data = array_values($values);
$response = array('sucess' => true, 'data' => $data);
echo json_encode($response);
Use array_values, this can be done like so:
$values = array
(
'10 - 20' => 3,
'20 - 30' => 43,
'30 - 40' => 5,
'40 - 50' => 1,
'50 - 60' => 0,
'60 - 70' => 0,
);
$values = array_values($values);
$data = json_encode($values);
echo data;
Output:
[3,43,5,1,0,0]
You might be new to php, Declaration of associative array should be like below
$arr=array(
'[10 - 20]' => 3,
'[20 - 30]' => 43,
'[30 - 40]' => 5,
'[40 - 50]' => 1,
'[50 - 60]' => 0,
'[60 - 70]' => 0
);
array('Key'=>value,'key2'=> value);
Write forearch/for/ any loop to get the values, This is useful if you want to extract both key and values at the same time
foreach ($arr as $key=>$value) {
echo "$value <br>";
}
If you want to get only values then use array_values($arr)
You need to use array_values.
PHP Array
$arr = array("10 - 20" => 3,
"20 - 30" => 43,
"30 - 40" => 5,
"40 - 50" => 1,
"50 - 60" => 0,
"60 - 70" => 0
);
Array values from the array.
$arr2 = array_values($arr);
print_r($arr2);
Output Array
Array
(
[0] => 3
[1] => 43
[2] => 5
[3] => 1
[4] => 0
[5] => 0
)
If you need only the values as string then use implode.
echo implode(" , ", $arr2);
Result
3 , 43 , 5 , 1 , 0 , 0
I am trying to execute this query in codeigniter 2.2. I read the documentation http://www.codeigniter.com/user_guide/database/results.html.
My controller code is this
$query = $this->db->query("SELECT a.id, a.child, a.immune, a.immun_date, b.id, b.fname, b.lname, c.id, c.name
FROM immun a, children b, immun_master c
WHERE a.child = b.id
AND c.id = a.immune
");
$immun = array();
foreach ($query->result()as $row) {
$immun[] = array(
$row->id,
$row->child,
$row->immune,
$row->immun_date,
);
}
The results that are turned is this:
array (
0 =>
array (
0 => '2',
1 => '1001',
2 => '2',
3 => '2011-04-23',
),
1 =>
array (
0 => '3',
1 => '1001',
2 => '3',
3 => '2011-04-30',
),
2 =>
array (
0 => '6',
1 => '1002',
2 => '6',
3 => '2011-04-30',
),
3 =>
array (
0 => '5',
1 => '1002',
2 => '5',
3 => '2011-04-29',
),
4 =>
array (
0 => '1',
1 => '1003',
2 => '1',
3 => '2011-01-06',
),
5 =>
array (
0 => '3',
1 => '1005',
2 => '3',
3 => '2010-10-04',
),
6 =>
array (
0 => '3',
1 => '1231',
2 => '3',
3 => '2014-08-01',
),
)
These are wrong results. I was expecting is the merged results of the query. Below is what I get when I run the query in phpmyadmin
id child immune immun_date id fname lname id name
1 1001 2 2011-04-23 1001 Johny Jame 2 Swine Flu Vaccine
2 1001 3 2011-04-30 1001 Johny Jame 3 Bird Flu Vaccine
3 1002 6 2011-04-30 1002 Chelsea James 6 Hepatitis B
4 1002 5 2011-04-29 1002 Chelsea James 5 Measles Vaccine
5 1003 1 2011-01-06 1003 Charles Jacob 1 H1N1 Vaccine
6 1005 3 2010-10-04 1005 Hansome Little 3 Bird Flu Vaccine
7 1231 3 2014-08-01 1231 Jennifer Ylanan 3 Bird Flu Vaccine
Now, it would be nice if I could get CI to return the same set of merged data. I can see that is it only returning the table query for immun and CI is not join data from the other table.s I read somewhere that CI was not build to handle complex queries? Is that true?
Any ideas how to get the data I need?
Thanks!
You could see the query CI ran in your database.
Put the following code on the controller that render the page where this query is used:
$this->output->enable_profiler(TRUE);
This way CI will output a profiler in the end of the page with lots of information, including the executed queries needed for rendering the page.
This should help.
Another hint, you must use alias in case you need to select columns with equal names from different tables. CI don't handle it well.
function immChild() {
$this->db->select('c.id, c.name, b.id, b.fname, b.lname, a.id, a.child, a.immune, a.immun_date');
$this->db->join('immun_master as c', 'c.id = a.immune','true');
$this->db->join('children as b', 'a.child = b.id', 'true');
$query = $this->db->get('immun as a')->result();
return $query;
}
This is the correct query for the cross join for codeigniter. In my original post, I did not have conditionals. I found it here
https://ellislab.com/codeIgniter/user-guide/database/active_record.html
in the section about join. I seen that there was a place for conditions of the join. Once I added the conditions. I got the correct result set returned.
TABLE `people`
+----+------------+-------+
| sn | name | upper |
+----+------------+-------+
| 1 | Clement | 0 |
| 2 | Jean | 1 |
| 3 | Annie | 1 |
| 4 | Yuan | 2 |
| 5 | Mei | 2 |
| 6 | Blue | 3 |
| 7 | Yang | 5 |
| 8 | Lorinda | 0 |
+----+------------+-------+
The structure is like:
Clement
Jean
Yuan
Mei
Yang
Annie
Blue
Lorinda
The column upper states the upper person of himself/herself.
The problem is: How can I get a nested/multi-dimensional array from MySQL?
I thought I could use loops to fetch, but I failed to automated fetch all the lowers.
The array could be like this:
Array
(
[1]=>Array
(
[self]=>Clement
[2]=>Array
(
[self]=>Jean
[4]=>Array
(
[self]=>Yuan
)
[5]=>Array
(
[self]=>Mei
[7]=>Array
(
[self]=>Yang
)
)
)
[3]=>Array
(
[self]=>Annie
[6]=>Array
(
[self]=>Blue
)
)
)
[8]=>Array
(
[self]=>Lorinda
)
)
Since we don't know how many 'upper' persons does one have, the solution should be an automated function that build a complete array, not just for three or four dimension.
In other word, the function should deep into all the lower person from a top person.
Given your input as:
$input = array(
array('sn' => 1, 'name' => 'Clement', 'upper' => 0),
array('sn' => 2, 'name' => 'Jean', 'upper' => 1),
array('sn' => 3, 'name' => 'Annie', 'upper' => 1),
array('sn' => 4, 'name' => 'Yuan', 'upper' => 2),
array('sn' => 5, 'name' => 'Mei', 'upper' => 2),
array('sn' => 6, 'name' => 'Blue', 'upper' => 3),
array('sn' => 7, 'name' => 'Yang', 'upper' => 5),
array('sn' => 8, 'name' => 'Lorinda', 'upper' => 0),
);
using references you can build a tree with the following loop:
$map = array();
foreach ($input as $node) {
// init self
if (!array_key_exists($node['sn'], $map)) {
$map[$node['sn']] = array('self' => $node['name']);
}
else {
$map[$node['sn']]['self'] = $node['name'];
}
// init parent
if (!array_key_exists($node['upper'], $map)) {
$map[$node['upper']] = array();
}
// add to parent
$map[$node['upper']][$node['sn']] = & $map[$node['sn']];
}
print_r($map[0]);
demo: http://3v4l.org/vuVPu
Assuming the data is like this
$data = array(
array(1, 'Clement', 0),
array(2, 'Jean ', 1),
array(3, 'Annie ', 1),
array(4, 'Yuan ', 2),
array(5, 'Mei ', 2),
array(6, 'Blue ', 3),
array(7, 'Yang ', 5),
array(8, 'Lorinda', 0),
);
this recursive function might work:
function tree($data, $node) {
foreach($data as $e)
if($e[2] == $node[0])
$node['children'] []= tree($data, $e);
return $node;
}
Use it like this:
$tree = tree($data, array(0));
print_r($tree);
using a reference map
$input = array(
array('sn' => 1, 'name' => 'Clement', 'upper' => 0),
array('sn' => 2, 'name' => 'Jean', 'upper' => 1),
array('sn' => 3, 'name' => 'Annie', 'upper' => 1),
array('sn' => 4, 'name' => 'Yuan', 'upper' => 2),
array('sn' => 5, 'name' => 'Mei', 'upper' => 2),
array('sn' => 6, 'name' => 'Blue', 'upper' => 3),
array('sn' => 7, 'name' => 'Yang', 'upper' => 5),
array('sn' => 8, 'name' => 'Lorinda', 'upper' => 0),
);
$map = []; // map a reference by id for each item
foreach ($input as &$inp) {
$map[$inp['sn']] = &$inp;
}
foreach ($map as &$_inp) { // assign each item to its parent, with help of the map
if ($_inp['upper']) {
$map[$_inp['upper']]['children'] = &$map[$_inp['upper']]['children'] ?? [];
$map[$_inp['upper']]['children'][] = &$_inp;
}
}
$result = array_filter($map, fn($item) => !$item['upper']);
print_r($result);```
This is a follow-up to Detect future duplicate values while iterating through MySQL results in PHP.
I have an SQL query which produces the results:
team_id division_id wins
-------------------------------
10 2 44
9 2 42
5 1 42
2 1 42
3 1 41
11 2 40
1 1 36
8 2 31
7 2 29
12 2 24
4 1 20
6 1 18
I'm trying to calculate a given team's overall and divisional rankings.
For example, team_id = 1:
Overall: 7
Divisional: 4
For team_id = 3:
Overall: 5
Divisional: 3
For team_id = 9:
Overall: T-2 //must indicate tie
Divisional: 2
As you can see from the linked previous question/answer, I can calculate the Overall rank just fine. The issue comes with calculating the divisional rank as well (including properly handling ties).
I've tried storing the results in a multi-dimensional array like $arr['wins']['division_id']['team_id'], such as...
44 => 2 => 10
42 => 1 => 5
2
2 => 9
41 => 1 => 3
40 => 11 => 2
...
But am stuck as to how to iterate through and get my two respective ranks, as well as detecting ties appropriately for each.
Try something like this:
// Dataset as defined on question
$arr = array(
array('team_id' => 10, 'division_id' => 2, 'wins' => 44),
array('team_id' => 9, 'division_id' => 2, 'wins' => 42),
array('team_id' => 5, 'division_id' => 1, 'wins' => 42),
array('team_id' => 2, 'division_id' => 1, 'wins' => 42),
array('team_id' => 3, 'division_id' => 1, 'wins' => 41),
array('team_id' => 11, 'division_id' => 2, 'wins' => 40),
array('team_id' => 1, 'division_id' => 1, 'wins' => 36),
array('team_id' => 8, 'division_id' => 2, 'wins' => 31),
array('team_id' => 7, 'division_id' => 2, 'wins' => 29),
array('team_id' => 12, 'division_id' => 2, 'wins' => 24),
array('team_id' => 4, 'division_id' => 1, 'wins' => 20),
array('team_id' => 6, 'division_id' => 1, 'wins' => 18));
$divisionTeam = array();
$divisionWins = array();
foreach($arr as $team) {
$divisionTeam[$team['division_id']][] = $team['team_id'];
$divisionWins[$team['division_id']][] = $team['wins'];
}
echo "<pre>";
foreach (array_keys($divisionTeam) as $division_id) {
$rank = 0;
$prevWins = -1;
echo "DIVISION $division_id \n";
foreach ($divisionTeam[$division_id] as $index => $team_id) {
if ($prevWins == $divisionWins[$division_id][$index]) {
echo $team_id . " T - " . $rank . "\n";
}
else {
$rank++;
echo $team_id . " " . $rank . "\n";
}
$prevWins = $divisionWins[$division_id][$index];
}
}
echo "</pre>";