I have 2 tables. The first one contain some global information, and the second contain a list of images.
When I execute this request:
SELECT table1.title, table1.description, table2.image LEFT JOIN table2 ON table2.table1_id = table1.table1_id
Tables structure:
TABLE1
| table1_id | title | description |
| 1 | title1 | description1 |
| 2 | title2 | description2 |
| 3 | title3 | description3 |
TABLE2
| id | table1_id | image |
| 1 | 1 | img/img1.png |
| 2 | 1 | img/img2.png |
| 3 | 1 | img/img3.png |
| 4 | 2 | img/img4.png |
| 5 | 2 | img/img5.png |
| 6 | 3 | img/img6.png |
I got something like that:
<?php
array(
array('title' => 'title1', 'description' => 'description1', 'image' => 'img/img1.png'),
array('title' => 'title1', 'description' => 'description1', 'image' => 'img/img2.png'),
array('title' => 'title1', 'description' => 'description1', 'image' => 'img/img3.png'),
array('title' => 'title2', 'description' => 'description2', 'image' => 'img/img4.png'),
array('title' => 'title2', 'description' => 'description2', 'image' => 'img/img5.png'),
array('title' => 'title3', 'description' => 'description3', 'image' => 'img/img6.png')
);
?>
The problem with this kind of structure is duplicated title, description.
I'd like to get something like that:
<?php
array(
array('title' => 'title1', 'description' => 'description1', 'image' =>
array('img/img1.png', 'img/img2.png', 'img/img3.png')
),
array('title' => 'title2', 'description' => 'description2', 'image' =>
array('img/img1.png', 'img/img2.png')
),
array('title' => 'title3', 'description' => 'description3', 'image' =>
array('img/img6.png')
)
);
?>
My questions are:
Is it possible to get this kind of structure of data just with a SQL request (No PHP manipulation..)
If not, what kind of PHP manipulation I have to do to transform my first array to my second array?
Thanks!
Have a look at group clause and group_concat function. I'm not sure whether it creates an array in PHP, but it's almost what you want:
SELECT table1.title, table1.description, GROUP_CONCAT(table2.image) LEFT JOIN table2 ON table2.id = table1.id GROUP BY table1.id
You can use explode function in PHP to transform the result of GROUP_CONCAT(table2.image) to PHP array
See the documentation of MySQL's group_concat and PHP's explode functions.
You can do a select on all the distinct (Name, Description) tuples. Then you'll have an array of Name,Descriptions, and a null third element. Then loop through this array and get all the images for that distinct tuple. Then take that result and insert it into the third element.
Query get array of name/descriptions:
select distinct table1.title, table2.description left join table2 on table2.id = table1.id
Query to find all images of the distinct name/description tuples:
select table2.image inner join table1 on table1.id = table2.id where table1.name = arr[0] and table1.description = arr[1]
You can quite easily build the structure you're after when you iterate over the results, either was you're going to have to manipulate the result-set.
<?php
$items = array();
foreach ($rows as $row) {
if ( ! isset($items[ $row['title'] ])) {
$items[ $row['title'] ] = array(
'title' => $row['title'],
'description' => $row['description'],
'images' => array($row['image']),
);
continue;
}
$items[ $row['title'] ]['images'][] = $row['image'];
}
$items = array_values($items);
Anthony.
PHP code:
<?php
/*here is your result array*/
$result = array(
array('title' => 'tile1', 'description' => 'description1', 'image' => 'img/img1.png'),
array('title' => 'tile1', 'description' => 'description1', 'image' => 'img/img2.png'),
array('title' => 'tile1', 'description' => 'description1', 'image' => 'img/img3.png'),
array('title' => 'tile2', 'description' => 'description2', 'image' => 'img/img4.png'),
array('title' => 'tile2', 'description' => 'description2', 'image' => 'img/img5.png'),
array('title' => 'tile3', 'description' => 'description3', 'image' => 'img/img6.png')
);
/*creating a new formatted array*/
$newResult = array();
foreach($result as $value){
$newResult[$value['title']]['title'] = $value['title'];
$newResult[$value['title']]['description'] = $value['description'];
$newResult[$value['title']]['image'][] = $value['image'];
}
/*printing new final formatted array*/
print_r($newResult));
?>
Related
i made a navigation where a MySQL Database is needed.
This is my connection to the database to get all informations.
$stmt = $pdo->prepare("SELECT * FROM navigation");
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_OBJ);
if($stmt->rowCount() > 0){
$primary_nav = [];
foreach ($results as $result){
if($result->sub == 0){
$primary_nav[] = array(
'name' => $result->name,
'url' => $result->url,
'icon' => $result->icon,
);
}elseif($result->sub == 1){
$primary_nav[] = array(
'name' => $result->name,
'icon' => $result->icon,
'sub' => array(
array(
'name' => $result->name_sub,
'url' => $result->url_sub
)
)
);
}
}
}
This works fine, if I add the navigation into the database everything looks perfect and works amazing.
Now the problem i've now is when I want to a new sub menu than everytime I get a new top menu entrie with just 1 sub menu.
So my question is, how do I get this part working without breaking the code.
Normally the code looks like this:
// first sub
array(
'name' => 'Test1',
'icon' => 'fa fa-bullhorn',
'sub' => array(
array(
'name' => 'First Sub 1',
'url' => 'sub1.php'
),
array(
'name' => 'First Sub 2',
'url' => 'sub2.php'
)
)
),
// second sub
array(
'name' => 'Test3',
'icon' => 'fa fa-bullhorn',
'sub' => array(
array(
'name' => 'Second Sub',
'url' => 'sub1_1.php'
)
)
)
database structure:
|-----name-----|----url----|----icon----|----sub----|----name_sub----|----url_sub----|----category----|
| Dashboard | index.php | icon | 0 | | | |
------------------------------------------------------------------------------------------------------
| Test | test.php | icon | 0 | | | |
------------------------------------------------------------------------------------------------------
| Test1 | | icon | 1 | First Sub 1 | sub1.php | 1 |
------------------------------------------------------------------------------------------------------
| | | icon | 1 | First Sub 2 | sub2.php | 1 |
------------------------------------------------------------------------------------------------------
| Test3 | | icon | 1 | Second Sub | sub1_1.php | 2 |
------------------------------------------------------------------------------------------------------**
So if the category equals the same number as the other it should be doing this:
Test1
-- First Sub 1
-- First Sub 2
Test3
-- Second Sub
but with my code it looks like this:
Test1
-- First Sub 1
Test2 (it would be empty because in the database it is empty just for example I puted Test2)
-- First Sub 2
Test3
-- Second Sub
maybe someone understand what I need, because my english is not the best to explain it. Thanks for any help/solution for this problem.
$stmt = $pdo->prepare("SELECT * FROM navigation");
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_OBJ);
if($stmt->rowCount() > 0){
$categories = [];
$primary_nav = [];
foreach ($results as $result){
if ($result->name) {
if ($result->category) {
$categories[$result->category] = sizeof($primary_nav);
}
$primary_nav[] = array(
'name' => $result->name,
'url' => $result->url,
'icon' => $result->icon,
);
}
if ($result->name_sub) {
$primary_nav[$categories[$result->category]]['sub'][] = array(
'name' => $result->name_sub,
'url' => $result->url_sub
);
}
}
}
I've added an extra $categories array.
For each "parent" entry with a category, the $categories array stores the category value from the database and the key of the "parent" entry in the $primary_nav array.
The $categories array can then be used to add subsequent subcategories to the correct parent entry using their category value.
In your current setup however, the database allows you to have subcategories without a parent category and (sub)categories without a name.
So I would suggest using a table setup like this instead:
id name url icon parent
1 Dashboard index.php icon null
2 Test test.php icon null
3 Test1 null icon null
4 First sub 1 sub1.php null 3
5 First sub 2 sub2.php null 3
6 Test3 null icon null
7 Second sub Sub1_1.php null 6
Parent categories have the column "parent" set to null, and subcategories have their "parent" column set to the id of their parent entry.
This also allows you to have sub-sub-(and so on)-categories.
You would need to query it recursively:
function buildNav($pdo, $id = null) {
$array = [];
if ($id) {
$stmt = $pdo->prepare("SELECT * FROM navigation WHERE parent = :id");
$stmt->bindValue('id', $id);
} else {
$stmt = $pdo->prepare("SELECT * FROM navigation WHERE parent IS NULL");
}
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_OBJ);
if ($stmt->rowCount() > 0){
foreach ($results as $result){
$array[] = array(
'name' => $result->name,
'url' => $result->url,
'icon' => $result->icon,
'sub' => buildNav($pdo, $result->id)
);
}
}
return $array;
}
$primary_nav = buildNav($pdo);
I'm trying to get the content I need from a joined query and properly use values as an array key so that I can build some DIV lists properly
My php query and array:
$getTickers = "
SELECT d.ID as displayID, d.display_name as display, l.location_name as locationName, d.location_id as location, t.id as ticker, tc.id as contentID, tc.content
FROM displays d
INNER JOIN locations l on d.location_id = l.id
INNER JOIN tickers t on d.id = t.display_id
INNER JOIN ticker_content tc on t.id = tc.ticker_id;
";
$tickers = $mysqlConn->query($getTickers);
$tickerDisplays = array();
foreach($tickers as $subArray) {
if(!array_key_exists($subArray['displayID'], $tickerDisplays)) {
$tickerDisplays[$subArray['displayID']] = array();
}
// here you add `display_name` under key `display_id`
$tickerDisplays[$subArray['displayID']][$subArray['location']] = $subArray['display'];
}
All examples and code below, but I don't need the html structure help with this, just how to restructure the array/key to give me the desired results and how I should loop them on the front end.
I'm getting 4 divs as I expect right now (one for each unique display/location)
but I need to figure out how to correcty arrange it so I can echo the DIsplay name as the h4, the location as h5, and then each content in my list
So the query result gives me this:
displayID | display | locationName | location | ticker | contentID | content |
1 Office Building 4 4 1 1 testing content
2 Lobby Building 4 4 2 2 testing content 2
3 Lobby Building 1 1 3 3 testing content 3
4 Office Building 1 1 4 4 testing content 4
4 Office Building 1 1 4 5 testing content again
I'm trying to loop on this with the expected result of having a a div for each location/display combo like so:
OFFICE
Building 4
testing content
---------------
LOBBY
Building 4
testing content 2
------------------
LOBBY
Building 1
testing content 3
------------------
OFFICE
Building 1
testing content 4
testing content again
----------------------
Here's the way I'm currently trying to loop that
<?php foreach($tickerDisplays as $key => $ticker):?>
<h4><?php echo $key ?></h4> //so this should be the display Name (office, lobby)
<h5><?php echo //location?></h5> //this should be the location name (Building 1, Building 4)
//This will be another foreach for any content associated with the location/display
<ul class="tickerContent">
<li>
</ul>
</div>
</div>
<?php endforeach;?>
The approach here is to make a child array for each display line to contain all
the multiple content records.
// Dummy the data from the query
$tickers = [
['displayID' => 1, 'display' => 'Office', 'locationName' => 'Building 4', 'location' => 4, 'ticker' => 1, 'contentID' => 1, 'content' => 'testing content'],
['displayID' => 2, 'display' => 'Lobby', 'locationName' => 'Building 4', 'location' => 4, 'ticker' => 2, 'contentID' => 2, 'content' => 'testing content 2'],
['displayID' => 3, 'display' => 'Lobby', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 3, 'contentID' => 3, 'content' => 'testing content 3'],
['displayID' => 4, 'display' => 'Office', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 4, 'contentID' => 4, 'content' => 'testing content 4'],
['displayID' => 4, 'display' => 'Office', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 4, 'contentID' => 5, 'content' => 'testing content again']
];
// A place to keep the reorganized data
$tickerDisplays = [];
// Walk through the query result
foreach($tickers as $row) {
$displayID = $row['displayID']; // for convenience and readability
$location = $row['location']; // for convenience and readability
$display = $row['display'];
$contentID = $row['contentID'];
if ( ! array_key_exists($row['displayID'], $tickerDisplays) ) {
$tickerDisplays[$displayID] = [
'displayID' => $row['displayID'],
'display' => $row['display'],
'ticker' => $row['ticker'],
'contentID' => $row['contentID'],
'content' => $row['content'],
'location' => $row['location'],
'locationName' => $row['locationName'],
'#content' => [] // to store the content data
];
}
$tickerDisplays[$displayID]['#content'][$contentID] = ['content' => $row['content']];
}
print_r($tickerDisplays);
foreach ( $tickerDisplays as $key => $ticker ) {
// Output the display and location name
out($ticker['display']);
out($ticker['locationName']);
// Output all the content records.
foreach ( $ticker['#content'] as $contentID => $content ) {
out($content['content']);
}
out('------------');
}
// Just a utility function
function out($msg) {
echo "$msg\n";
}
Output:
Office
Building 4
testing content
------------
Lobby
Building 4
testing content 2
------------
Lobby
Building 1
testing content 3
------------
Office
Building 1
testing content 4
testing content again
------------
How can using php mysql create a dynamic tree for this tables
tbl_folder
db_id db_foldername
1 accounting
2 hr
3 it
tbl_subfolder
db_id db_folderid db_subfoldername
1 1 xxx
2 1 yyy
3 2 zzz
tbl_childsubfolder
db_id db_subfolderid db_childsubfoldername
1 1 ffff
2 2 llll
tbl_subchild
db_id db_childsubfolderid db_subchildname
1 1 eee
2 1 ppp
accounting
xxx
fff
eee
ppp
yyy
lll
hr
zzz
it
include("include/connect.php");
--SELECT--
$name";
}
?>
if(isset($_POST['add'])){
$foldername=$_POST['txt_name'];
$select=$_POST['txt_select'];echo $select;
$explod=explode("-",$select);
$path=$explod['0'].';'.$explod['1'];
if($path==";"){$path="";}
$parent_id=$explod['1'];
if($foldername==""){echo"enter a name";}
else{
$insert_query=mysqli_query($conn,"insert into tbl_folders(parent_id,path,name)values('$parent_id','$path','$foldername')")or die(mysqli_error($conn));
header("location:index.php");
}
}
$sql=mysqli_query($conn,"select * from tbl_folders where parent_id='0'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sql)){
$name=$row['name'];
$id=$row['db_id'];
echo $name;echo"<br/>";
$sqli=mysqli_query($conn,"select * from tbl_folders where parent_id='$id'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sqli)){
$name=$row['name'];
$id=$row['db_id'];
$path=$row['path'];
$x=explode(";",$path);echo $path;echo"<br/>";
$pa=$x['1'];
echo $name;echo"<br/>";
$sqli=mysqli_query($conn,"select * from tbl_folders where parent_id='$id' and path='$pa'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sqli)){
$name=$row['name'];
$id=$row['db_id'];
$path=$row['db_path'];
echo $name;echo"<br/>";}
}
}
Building the tree
You can build one table with the following fields:
`id (int), parent_id (int), path (vachar), name`
id - is the identifier
parent_id - refers to the id of the parent in the same table
path - is the path of parent ids to the given element
Example entries in the table:
|id | parent_id | path | name|
-------------------------------
|1 | 0 | | A |
-------------------------------
|2 | 1 |;1; | B |
-------------------------------
|3 | 2 |;1;2; | C |
where A is the parent, B is child of A, and C is child of B.
In your backend logic you need to have the following:
When you add/edit new item in this table - if it is root parent (with no parents above it) you insert it with parent_id=0 and path=''
When you add/edit new item in this table - if it has parent then you insert it with parent_id=:idOfParent and path=CONCAT(:parentPath, ';', :idOfParent, ';')
where :idOfParent - is the parent id value and :parentPath is the path of the parent which you concatenate with the ;:idOfParent;
; - is the separator for the ids in the path
Path column gives you the advantage of directly getting all the parents of given element without using recursive approaches.
So if you select an item with path ';1;2;3;' and you need the info for the parents also you will have 1 + 3 SELECT queries in total.
And when deleting an item you can do this:
DELETE FROM table WHERE path LIKE (';:deleteId;')
where :deletedId is the id of the deleted element. This query will delete all the entries that have deleted item as a parent.
Visualization of the tree
you can get the $data with this query
'SELECT id, parent_id, path, name FROM table WHERE 1;'
But for the test i use the following example array
$data = [
0 => ['id' => 1, 'parent_id' => 0, 'path' => '', 'name' => 'A'],
1 => ['id' => 2, 'parent_id' => 1, 'path' => ';1;', 'name' => 'B'],
2 => ['id' => 3, 'parent_id' => 2, 'path' => ';1;2;', 'name' => 'C'],
3 => ['id' => 4, 'parent_id' => 3, 'path' => ';1;2;3;', 'name' => 'D'],
4 => ['id' => 5, 'parent_id' => 1, 'path' => ';1;', 'name' => 'E'],
5 => ['id' => 6, 'parent_id' => 2, 'path' => ';1;2;', 'name' => 'G'],
6 => ['id' => 7, 'parent_id' => 0, 'path' => '', 'name' => 'H'],
];
$ref = null;
$tree = [];
foreach($data as $item) {
if($item['path']) {
$path = ltrim($item['path'], ';');
$path = rtrim($path, ';');
$pathArray = explode(';', $path);
$i = 0;
foreach($pathArray as $parentId) {
if($i === 0) {
if(!isset($tree[$parentId])) {$tree[$parentId] = ['name' => [], 'children' => []];}
$ref = &$tree[$parentId]['children'];
}
else {
if(!isset($ref[$parentId])) $ref[$parentId] = ['name' => [], 'children' => []];
$ref = &$ref[$parentId]['children'];
}
$i++;
}
if($ref !== null) {
$ref[$item['id']]['name'] = $item['name'];
$ref[$item['id']]['children'] = [];
}
}
else {
$tree[$item['id']]['name'] = $item['name'];
$tree[$item['id']]['children'] = [];
}
}
Output part:
print '<pre>';
print_r($tree);
print '</pre>';
So here you change the code according to your needs. Print it in the way you want (may be you will need recurrsion to access every tree node)
I would like to, in one query select orders and have their items attached to them (right now I'm selecting the orders, then using a separate query selecting the order_items - this is proving very slow on a large amount of orders...
orders: id | name | total
order_items: id | order_id | price | qty
order_items_info: id | order_id | order_item_id | tracking_no
The last thing I want to do is: add my order_items_info table to the item array.
$orders = array(
array(
'id' => '',
'name' => '',
'items' => array(
array(
'order_item_id' => '',
'price' => '',
'qty' => '',
'item_info' => array()
),
array(
'order_item_id' => '',
'price' => '',
'qty' => '',
'item_info' => array()
),
...
)
)
);
SELECT o.id,name,total,item_info,price,qty FROM orders o
JOIN order_items oi ON o.id=oi.order_id
JOIN order_items_info oii ON oii.order_id=o.id
AND oii.order_item_id=oi.id
Just a wild guess until you post your table info.
select * from orders join order_items on (orders.id = order_id)
How can I convert record set from database to array?
It has 1 table named: tblproduct, with the following schema:
product_id | product_name | product_desc | product_price | product_img
When I select data from the database I would like an array in the following format:
$product_array = array(
"105" => array('product_id' => '105', 'product_name' => 'Blackberry 8900',
'product_desc' => '', 'product_price' => '1150.00',
'product_img' => 'products/product5.jpg'),
"106" => array('product_id' => '106', 'product_name' => 'Headphone with mic',
'product_desc' => '', 'product_price'=>'148.85',
'product_img' => 'products/product8.jpg')
);
Best regards
Assuming you are using MySQL (You didn't specify your DBMS) and have a line like:
$result = mysql_query('SELECT * FROM `tblproduct`');
You can use:
while($row = mysql_fetch_assoc($result))
$product_array[$row['product_id']] = $row;