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...
Related
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;
}
Is there a more efficient way of deleting multiple entities by id
$data = $this->request->data ['missing_lexicon_id'];
foreach ( $data as $id ) {
$missingLexicon = $this->MissingLexicons->get ( $id );
$this->MissingLexicons->delete ( $missingLexicon )
}
This should work
$this->MissingLexicons->deleteAll(['MissingLexicons.column IN' => $keys]);
Where $keys is an array with the ids to be deleted.
Most efficient way to delete multiple entities using deleteALL().
$this->MissingLexicons->deleteAll(['id IN' => $multiItemsArray]);
OR
$this->MissingLexicons->deleteAll(['id' => $multiItemsArray[]]);
MissingLexicons = Your Model name.
$multiItemsArray = Your deleted entities id
Read More Here
Earlier this day a asked a question about an update query. But now i want to select some things ( and it is working ) but I also want to order them and put a limit on it.
This is the code to select all the food :
public function getFood($id)
{
$id = (int)$id;
$rowset = $this->tableGateway->select(array('kindOfFood_id' => $id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
But how can i do this :
Select * from KindOfFood ==> order by kindOfFood_votes DESC ?
I saw on the documentation you can do something like this, but it doesn't work with me?
$rowset = $artistTable->select(function (Select $select) {
$select->where->like('name', 'Brit%');
$select->order('name ASC')->limit(2);
});
Are you looking to return only single row or multiple rows.
Try this for multiple rows -
use Zend\Db\Sql\Select; //at the top of the page among other use statements.
public function getFood($id)
{
$id = (int) $id;
$select = new Select(TABLE_NAME); //CHANGE TABLE_NAME as per needs
$select->where('kindOfFood_id = ' . $id);
$select->order('kindOfFood_votes DESC');
$resultSet = $this->tableGateway->selectWith($select); //Will get array of rows.
//$row = $rowset->current(); THIS IS FOR RETURNING ONLY SINGLE ROW NOT ALL ROWS
if (!$resultSet) {
throw new \Exception("Could not find rows with food id - $id");
}
return $resultSet;
}
Can access the returned resultSet via loop. Eg: foreach
foreach($resultSet as $row) {
echo $row->kindOfFood_id; //or something
}
Note:
If you need only
Select * from KindOfFood order by kindOfFood_votes DESC
then remove the $select->where('kindOfFood_id = ' . $id); line from above.
I'm trying to find a way to retrieve every combination of values from two columns in a table, where each combination matches a value in a third column.
Say part of the table looks like this:
products_id options_id options_values_id
1487 2 1
1487 2 61
1487 3 60
1487 5 52
My desired output, when working with products_id 1487, would be the following two strings:
2-1, 3-60, 5-52
2-61, 3-60, 5-52
I've got the impression that those strings would need to be assembled recursively, but I ran into trouble trying it that way because not every products_id has the same options_ids, or the same number of them.
Edited to add: I've tried variations of a couple of the solutions below, but to no avail. I think I should have been more descriptive.
I'm trying to have it retrieve every combination of unique options_id and its corresponding options_values_id. (In other words, not every single possible combination of numbers from those two columns.) Options_id represents product options like "color" and "size," and options_values_id represents choices of those options, like "red" or "small." So I'm trying to come up with every possible combination of options for a given products_id. In the example above, there are two possible option combinations for that item-- "2-1, 3-60, 5-52" and "2-61, 3-60, 5-52".
Join the table against itself for each distinct option.
Do a select first to retrieve the number of options.
$tables = array();
$rs = mysql_query(
'SELECT DISTINCT options_id FROM table WHERE products_id = '.$id);
while ($row = mysql_fetch_row($rs)) {
$tables[$row['options_id']] =
'SELECT options_values_id FROM table WHERE products_id = '.$id.
' AND options_id = '.$row['options_id'];
}
mysql_free_result($rs);
Then, for each option, join it in as a separate table in your query. Do not include any joining clauses comparing values, just join every record against every other record.
$sql = 'SELECT ';
$count = 0;
foreach ($tables AS $id => $query) {
if ($count++) $sql .= ', ;
$sql .= 'table_'.$id.'.options_values_id AS value_'.$id;
}
$sql .= ' FROM ';
$count = 0;
foreach ($tables AS $id => $query) {
if ($count++) $sql .= ', ';
$sql .= '('.$query.') AS table_'.$id;
}
Finally, execute that query. Each row will contain one column per options_id. There will be one row per unique combination of values.
or for a mixed, php/sql approach, try using that SQL query:
SELECT products_id, options_id, options_values_id WHERE products_id = '$var_with_product_id';
fetch the results into an array, say $results:
$pairs = array();
foreach($results as $result) {
// build array with pairs (array_push to avoid overwriting)
array_push($pairs, array( $result['options_id'] => $result['options_values_id'];
}
// a bit extra complication, as array_push adds e.g. [0] => array( options_id => options_values_id ) :)
$pairs = array_values($pairs);
// check for double options_id
$found_double_options_id = false;
do {
// check for duplicates... use a lot of array functions
} while (count($pairs) && $found_double_options_id);
"Every combination" is the Cartesian product:
SELECT DISTINCT e1.options_id, e2.options_values_id
FROM Entity e1, Entity e2
WHERE e1.products_id = 1487 AND e2.products_id=1487
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();
}