Mysql Nested and declare as array - mysql

I have 2 table that want to call in and make another array from it.
The first table is groups
| id | name | type |
1 premium pr
2 basic bs
The second table is sub-groups
| id | group_id | name |
1 1 forever
2 2 short
Actually I want to show the code like this. To have another array function declare as sub-groups
Array (
[id] => 1
[name] => Premium
[type] => pr
)[sub-groups] => Array (
[0] => Array (
[id] => 1
[group_id] => 1
[name] => forever))
I created this PDO sql connection
=================EDITED CODE====================
function getGroups(){
global $conn;
$stmt = $conn->prepare("SELECT * FROM groups");
$stmt->execute();
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$groups = $stmt->fetchAll();
foreach($groups as $key => $val){
$stmt = $conn->prepare("SELECT * FROM sub_groups WHERE group_id = {$val['id']}");
$stmt->execute();
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$program = $stmt->fetchAll();
foreach($program as $key => $val){
$groups['sub-groups'] = $program;
}
}
return $groups;
}
The code successfully show the groups Premium and Basic, But it's not showing the sub-groups inside the main groups. Did I miss something?
Anyone with help will be nice.

Array keys have to be unique. If you have two columns with the same name, only one of them can appear in the resulting associative array for the rows.
You need to assign an alias to at least one of the columns with the same name so it will show up differently in the results.
SELECT g.name as group_name, sg.group_id, sg.id AS subgroup_id, sg.name AS subgroup_name
FROM groups AS g
LEFT JOIN subgroups AS sg ON sg.group_id = g.id
When you're creating the PHP result, $groups['sub-groups'] needs to be an array. You're overwriting it with a single element each time through the loop.
<?php
function getGroups(){
global $conn;
$groups = [];
$stmt = $conn->prepare("
SELECT g.name as group_name, sg.group_id, sg.id AS subgroup_id, sg.name AS subgroup_name
FROM groups AS g
LEFT JOIN subgroups AS sg ON sg.group_id = g.id");
$stmt->execute();
$stmt->setFetchMode(PDO::FETCH_ASSOC);
while ($row = $stmt->fetch()){
if (!isset($groups[$row['group_name']])) {
$groups[$row['group_name']] = $row;
$groups[$row['group_name']]['sub-groups'] = [$row['subgroup_name']];
} else {
$groups[$row['group_name']]['sub-groups'][] = $row['subgroup_name'];
}
}
return $groups;
}

Related

mysql - select result of two conditionals for the same table in one query

I am struggling to get correct results with this. I want to test if both, or either, exist. In results table, 'michael' exists while 'mike' does not.
$stmt = $dbnet->prepare("
SELECT * FROM
(SELECT cats AS cats1 FROM results WHERE name = :original) AS a,
(SELECT cats AS cats2 FROM results WHERE name = :parsed) AS b
");
$binding = array(
'original' => 'michael',
'parsed' => 'mike'
);
$stmt->execute($binding);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
//if there was a result then output
if($results)
{
echo '<pre>'.print_r($results,1).'</pre>';
}
I get no results with this even though 'michael' is in the database.
If I test for 'original' => 'michael', 'parsed' => 'michael' I get results...both the same of course since I tested the same value for each :
Array
(
[0] => Array
(
[cats1] => 6,11
[cats2] => 6,11
)
)
What I expect is one of the following :
no results meaning neither michael or mike exist
result for cats1 and empty for cats2 (michael exists mike does not)
empty for cats1 and result for cats2 (mike exists michael does not)
No, I cannot use WHERE name = 'michael' OR name = 'mike' because what I do after changes depending if both have results or just one or the other.
This is working as epxected... both always needs a result even if that is empty to return correctly.
$stmt = $dbnet->prepare("
SELECT
IFNULL( (SELECT cats AS cats1 FROM results WHERE name = :original), '') AS a,
IFNULL( (SELECT cats AS cats2 FROM results WHERE name = :parsed), '') AS b
");

Classic structure - self connected DB table, list

I have the following:
ID NAME PAREN_ID
1 a null
2 b null
3 c 2
4 d 3
I want to list the ID 4 item, and its all parent, so I would like to get:
4 d 3
3 c 2
2 b null
I tried something:
SELECT * FROM categories c1
JOIN categories c2 ON c2.ID = c1.PARENT_ID;
but thats not the good result, even if I try to filter to ID 4, it returns nothing.
Its MySQL!
I'm not really sure how you can do it with MySQL. I think your best bet would be fetching everything recursively.
function getCategories( $id ) {
$ret = array();
$cat = mysql_query( 'SELECT * FROM categories' );
$curid = $id;
do {
$ret[] = $cat[ $curid ];
$curid = $cat[ $curid ][ 'PARENT_ID' ];
} while ( $curid );
return $ret;
}
You should alter this so that it uses the PDO.
Only problem would be the query returning much data.

Sql (zend db select) of multiple selects

I need a bit of help.
I have (reference?) table with columns: id , user_id , key , value
It is pretty much a user profile table
and I would like to have SQL (I am using zend db table, but general SQL help will do) where I get "all 'user_id's where 'key' is somekey and 'value' is somevalue of that user_id but only if it also matches where 'key' is otherkey and 'value' is othervalue".
In other words I want to get users that have shoes of maker NIKE and color BLACK.
therefore 'key' is shoecolor and 'value' is BLACK and also another row with same user_id has 'key' is shoemaker and 'value' is NIKE.
This is what I could come up with, but doesn't work.
SELECT `user_profiles`.* FROM `user_profiles` WHERE
(`key` = 'shoecolor' AND `value` = 'BLACK') AND
(`key` = 'shoemaker' AND `value` = 'NIKE')
In case someone is knowledgable in zend db:
$where = array('shoecolor' => 'BLACK', 'shoemaker' => 'NIKE');
foreach ($where as $key => $value) {
$sql = $db->quoteInto('key = ?', $key);
$sql .= ' AND ' . $db->quoteInto('value = ?', $value);
$select->where($sql);
}
// make unique result
//$select->groupBy('user_id');
$resultSet = $zendTableInstance->fetchAll($select);
Please Help.
Thanx.
Because the key/value pair is in the row, your query is looking for a key that is 3 AND 4. No value can be 3 and 4 at the same time ;)
SELECT user_profiles.* FROM user_profiles WHERE (key = 3 AND value = 21) AND (key = 4 AND value = 55)
will not work.
You could do a join on yourself, and check for these values?
SELECT user_profiles.*
FROM user_profiles up1
JOIN user_profiles up2 ON up1.user_id = up2.user_id
WHERE
(up1.key = 3 AND up1.value = 21)
AND (up2.key = 4 AND up2.value = 55)

CI: Querying two tables in the model, explode

i'm thinking about this for days now and don't come to grasps (since i'm relativley new to MVC and CI). I'm not even sure whether this is an issue with MVC, MySQL or arrays.
Situation: 2 MySQL tables
Table data: id, title, list
Table values: id, name
Querying the data table results in an array like the following (excerpt):
[4] => Array
(
[id] => 3
[title] => Foo
[list] => 1,2,3,4,6,14
)
[5] => Array
(
[id] => 4
[title] => Bar
[list] => 2,6,9,12
)
The field list contains comma separated values that correspond to some IDs of the values table like
[3] => Array
(
[id] => 12
[name] => 'value12'
)
What I try to do for each row is:
take the list-values & explode it into an array
check with the result set from the values-table (via in_array() method)
return the name values of the IDs if
include it somehow into the main result set (e.g. as a 2-dimensional array):
[5] => Array (
[id] => 4
[title] => Bar
[list] => Array (
[0] => value6
[1] => value12
...
)
)
My naive approach so far was to
run a query on each of the 2 tables
compare the 2 result sets via in_array
My main problem (while trying to strictly separate model, controller and view): How can I include the name field from the values-table in the "main loop" of the data table result set?
if($q->num_rows() > 0)
{
$data[] = $q->result_array();
foreach ($q->result() as $row)
{
$data[] = $row;
}
return $data;
}
If I use the following (cumbersome) approach i naturally get a new item each time:
foreach ($q->result_array() as $row)
{
$data[]['id'] = $row['id'];
$data[]['title'] = $row['title'];
$data[]['list'] = $row['year'];
}
Since this is a MySQL database I see no way to do the explode and the comparison in SQL (with LIKE or something else).
Any hint, even a simple link to an info bit, is highly appreciated.
Thanks a trillion!
fab
There is a many-to-many relationship between lists and list values. The conventional way to model this in a relational database is to create a joining table. So I'd structure your schema like this.
lists : list_id, title
values : value_id, name
list_values : list_id, value_id
list_values is the joining table. It links lists with values.
To build a list you could have the following functions in your model
function build_list($list_id)
{
$list = $this->get_list($list_id);
$list->values = $this->get_list_values($list_id);
return $list;
}
function get_list($list_id)
{
$sql = 'select * from lists where list_id=?';
return $this->db->query($sql, array($list_id))->row();
}
function get_list_values($list_id)
{
$sql = 'select v.value_id, v.name
from list_values lv
join values v on v.value_id=lv.value_id
where lv.list_id=?';
return $this->db->query($sql, array($list_id))->result();
}

categories and items 1 big array

I've made some search on the forum without any good answers for my problem. If I missed something, feel free to link me to the question!
What I need to do is simple: a function that returns an array of the full tree of my categories and items. I only have 1 depth (item and a cat_id), so no recursion involved (though if you have a recursive solution, I would gladly accept it).
Right now, I've done this, but it's pretty bad, since I do multiple queries...
function build_tree()
{
global $wpdb;
$cats = $wpdb->get_results("SELECT * FROM wp_catering_cats");
foreach($cats as &$cat)
{
$id = $cat->id;
$cat->items = $wpdb->get_results("SELECT * FROM wp_catering_items WHERE cat_id = $id");
}
return $cats;
}
My tables are really simple:
wp_catering_items
id, cat_id, name, price
wp_catering_cats
id, name
Here is an exemple the results array I want:
Array
(
[0] => array
(
[id] => 1
[name] => Cat #1
[items] => Array
(
[0] => array
(
[id] => 1
[cat_id] => 1
[name] => Item #1
[price] => 5
),
...
)
),
...
);
If something is not clear, feel free to comment!
Thanks!
EDIT
I've made some modifications using the code bellow, but I' pretty sure there's a neater way to do this. Having to order one DESC and one ASC just doesn't sounds right..
function build_tree()
{
global $wpdb;
$cats = $wpdb->get_results("SELECT * FROM wp_catering_cats ORDER BY id DESC");
$items = $wpdb->get_results("SELECT * FROM wp_catering_items ORDER BY cat_id ASC");
$item = array_pop($items);
foreach($cats as &$cat)
{
while($item->cat_id == $cat->id)
{
$cat->items[] = $item;
$item = array_pop($items);
}
}
print_r($cats);
}
If you are just trying to optimize, then do the simple thing, instead of only grabbing the items for the specific cat you are on, grab all the items at once, and order them by catID. Then loop through your cats, and pop items off your item results until you hit the next cat.
function build_tree()
{
global $wpdb;
$cats = $wpdb->get_results("SELECT * FROM wp_catering_cats order by cat_id asc");
$items = $wpdb->get_results("SELECT * FROM wp_catering_items ORDER BY cat_id asc");
foreach($cats as &$cat)
{
$id = $cat->id;
$item = array_pop($items)
while($item['cat_id'] == $id)
{
$cats->item[] = $item;
$item = array_pop($items)
}
#do a little bookkeeping so you next cat gets its first item, and zero item cats get skipped.
}
}
Update: Thanks for the comment.. Forgot to add the pop in the while loop!
Second update: use array_shift instead of array_pop if you don't want reverse ordering to be a problem...