I need to generate a JSON String using this format:
{"content":{"brands":1},"brands":[{"id":"1","name":"brand 1","description":"description","icon":"icon","url":"example.com","categories":{"1":"true","2":"true","3":"false","4":"false","5":"false","6":"false"}},{"id":"2","name":"brand2","description":"description","icon":"icon","url":"example.com","categories":{"1":"true","2":"true","3":"false","4":"false","5":"false","6":"false"}}]}
From this tables:
brands:
| id | name | description | icon | url |
|----|--------|-------------|------|-----|
| 1 | name 1 | description | icon | url |
| 2 | name 2 | description | icon | url |
| 3 | name 3 | description | icon | url |
| 4 | name 4 | description | icon | url |
| 5 | name 5 | description | icon | url |
| 6 | name 6 | description | icon | url |
categories:
| id | name | description | icon | url |
|----|--------|-------------|------|-----|
| 1 | name 1 | description | icon | url |
| 2 | name 2 | description | icon | url |
| 3 | name 3 | description | icon | url |
| 4 | name 4 | description | icon | url |
| 5 | name 5 | description | icon | url |
| 6 | name 6 | description | icon | url |
objects:
| id | id_brand | id_category |name | description | icon | url |
|----|----------|-------------|-------|-------------|------|-----|
| 1 | 1 | 1 |name 1 | description | icon | url |
| 2 | 1 | 2 |name 2 | description | icon | url |
| 3 | 2 | 1 |name 3 | description | icon | url |
| 4 | 2 | 2 |name 4 | description | icon | url |
this is my relevant code so far
public function actionBrand($id = null) {
if (empty($id)) {
// Obtiene datos de la base
$sql = "SELECT DISTINCT objects.id_brand AS id, brands.name AS name, brands.description AS description, brands.icon AS icon, brands.url AS url, objects.id_category, categories.name AS category " .
"FROM objects " .
"LEFT JOIN brands ON objects.id_brand = brands.id " .
"LEFT JOIN categories ON objects.id_category = categories.id " .
"ORDER BY objects.id_brand, objects.id_category ";
} else {
// Obtiene datos de la base
$sql = "SELECT DISTINCT objects.id_brand AS id, brands.name AS name, brands.description AS description, brands.icon AS icon, brands.url AS url, objects.id_category, categories.name AS category " .
"FROM objects " .
"LEFT JOIN brands ON objects.id_brand = brands.id " .
"LEFT JOIN categories ON objects.id_category = categories.id " .
"WHERE brands.id = " . (int) $id . " " .
"ORDER BY objects.id_brand, objects.id_category ";
}
$data = Yii::$app->db->createCommand($sql)
->queryAll();
// Obtiene categorias
$categories = Yii::$app->db->createCommand('SELECT id FROM categories ORDER BY id')
->queryAll();
if (!empty($data)) {
// Construye primer registro
$brands[0]['id'] = $data[0]['id'];
$brands[0]['name'] = $data[0]['name'];
$brands[0]['description'] = $data[0]['description'];
$brands[0]['icon'] = $data[0]['icon'];
$brands[0]['url'] = $data[0]['url'];
$total = count($data);
for ($i = 1, $j = 0; $i < $total; $i++) {
if ($brands[$j]['id'] == $data[$i]['id']) {
continue;
} else {
$j++;
$brands[$j]['id'] = $data[$i]['id'];
$brands[$j]['name'] = $data[$i]['name'];
$brands[$j]['description'] = $data[$i]['description'];
$brands[$j]['icon'] = $data[$i]['icon'];
$brands[$j]['url'] = $data[$i]['url'];
}
}
} else {
$brands = array();
}
// Construye y envia JSON
$json['content']['brands'] = count($brands);
$json['brands'] = $brands;
echo json_encode($json);
}
It generates the first part of the JSON that i need, but im stuck at the categories part i need to select the data from the base and convert it to id : (true)(false) on each brand
{"content":{"brands":1},"brands":[{"id":"1","name":"brand 1","description":"description","icon":"icon","url":"example.com"},{"id":"2","name":"brand2","description":"description","icon":"icon","url":"example.com"}]}
Can you help me?
Regards
After you are done building the brands, loop on the categories, searching brands for the existing id match. If it matches, then adjust a true false value for the categories. Then when the categories are completed, append them to every brand in a final loop.
$cleancats = [];
foreach ($categories as $cat) {
$result = false;
foreach($brands as $brand) {
if ($cat['id'] == $brand['id']) {
$result = true; break;
}
}
$cleancats[ $cat['id'] ] = $result;
}
array_walk ($brands,function(&$brand) use ($cleancats) {
$brand['categories'] = $cleancats;
});
(note put this after your for ($i = 1, $j = 0; $i < $total; $i++) loop ends)
That should get the categories to every brand in brands, as you would like.
If you need the categories to be a LITERAL "true" and "false" then adjust this one line above:
$cleancats[ $cat['id'] ] = ($result?'true':'false');
Related
I have 2 tables in my product database:
product_list(id, Product_ID, Product_Name, Supplier),
product_option (id, Product_ID, Color, Size). both 'id's are primary keys with auto_increment.
I want to print all Color and Size values under each Product_Name (without repetition) that is from product_list table. I've been trying to figure out how to properly use foreach loop within while loop but now I'm out of related search result.
How my tables look:
product_list table:
|id | Product_ID | Product_Name | Supplier |
| -- | ---------- | ------------ | -------- |
| 1 |A1 | product1 | company1 |
| 2 |A2 | product2 | company2 |
| 3 |A3 | product3 | company3 |
| 4 |A4 | product4 | company4 |
product_option table:
|id |Product_ID | Color | Size |
| -- | --------- | ----- | ---- |
| 1 |A1 | red | S |
| 2 |A1 | red | M |
| 3 |A1 | black | S |
| 4 |A1 | black | M |
...
My expected output is:
| Product_ID | Product_Name | Supplier |
|:----------:|:------------:|:-----------:|
| A1 | Product1 | companyname |
| | red S | |
| | red M | |
| | black S | |
| | black M | |
| A2 | Product2 | companyname |
| | Large | |
Color and Size from product_option table with the same Product_ID will display under Product_Name row and Product_Name from product_list will only display once (instead of 4 times in the case of A1).
These are my code so far: (didn't write any table or styling for clean view)
include_once 'includes/dbh.inc.php';
$sql = "
SELECT
pl.Product_ID pid,
po.Product_ID poid,
pl.Product_Name,
po.Color color,
po.Size size,
pl.Supplier
FROM
product_list pl
LEFT JOIN
product_option po ON pl.Product_ID = po.Product_ID
ORDER BY
pl.Product_ID;";
$result = mysqli_query($conn, $sql) or die(mysqli_error());
if ($result -> num_rows > 0){
while ($row = $result -> fetch_assoc()) {
echo $row['pid'] . " " . $row['Product_Name'] . " " . $row['Supplier'] . "<br><br>";
if (!empty($row['color'] || $row['size'])) {
foreach ($row as $data) {
echo $data['color'] . ' /' . $data['size'] . '<br><br>';
}
}
}
}
Connection file: I use Xampp - phpmyadmin.
$dbServername = "localhost";
$dbUsername = "root";
$dbPassword = "";
$dbName = "product";
// Create Connection
$conn = new mysqli ($dbServername, $dbUsername, $dbPassword, $dbName);
// Check Connection
if ($conn -> connect_error) {
die("Connection Failed: " . $conn -> connect_error);
}
I'm ashamed to admit that the second 'if' and the foreach doesn't seem to work, and I don't know where to include the Product_ID match condition..
So far the output of this code is just 'A1 product1 company1', only the first result of the while loop.
From comment:
If it's ok for you to change how the data is being showed in the field, I suggest to make it horizontal with a query like this:
SELECT
pl.Product_ID pid,
po.Product_ID poid,
pl.Product_Name,
group_concat(concat(color,' ',size) separator ', ') AS Product_Name,
pl.supplier
FROM
product_list pl
LEFT JOIN
product_option po ON pl.Product_ID = po.Product_ID
GROUP BY pl.Product_ID, po.Product_ID,pl.Product_Name, pl.supplier
ORDER BY
pl.Product_ID;
Returns value like following:
+-----+------+---------------+---------------------------------+----------+
| pid | poid | Product_Name | Product_Name | supplier |
+-----+------+---------------+---------------------------------+----------+
| A1 | A1 | product1 | black M, black S, red M, red S | company1 |
.....
A fiddle of the tests
if ($result -> num_rows > 0)
mysqli_num_rows() This is a function so it is being ignored, it will always be "Zero" 0 so you will only get the indexed result which begins with '0'.. e.g [ 0,1,3]
Column title has a lot of duplicated values, more than once.
I need to update the column so, for example if 'gold' is duplicated - it becomes 'gold 1', 'gold 2', etc.
Something like this:
$st = $db->query("select id, title from arts order by title asc");
$st->execute();
$x = 0;
while($row = $st->fetch()){
$title = $row['title'];
//if($title.is duplicated){
$x++;
$title .= ' ' . $x;
$stb = $db->query("update arts set title = '" . $title . "' where id = " . $row['id']);
$stb->execute();
}
}
Any help?
It would be more efficient to do this in pure SQL rather than using PHP. Here is an approach that uses window functions, available in MySQL 8.0.
You can use a subquery to count how many title duplicates exists for each record, and assign a rank to each record within groups of records having the same title. Then, you can JOIN the subquery with the table to update. Where more than one record exists, you can append the row number to every record in the group.
Query:
UPDATE arts a
INNER JOIN (
SELECT
id,
title,
COUNT(*) OVER(PARTITION BY title) cnt,
ROW_NUMBER() OVER(PARTITION BY title ORDER BY id) rn
FROM arts
) b ON a.id = b.id
SET a.title = CONCAT(a.title, b.rn)
WHERE cnt > 1;
Demo on DB Fiddle
Sample data:
| id | title |
| --- | ------ |
| 10 | silver |
| 20 | gold |
| 30 | gold |
| 40 | bronze |
| 50 | gold |
| 60 | bronze |
Results after running the update query:
| id | title |
| --- | ------- |
| 10 | silver |
| 20 | gold1 |
| 30 | gold2 |
| 40 | bronze1 |
| 50 | gold3 |
| 60 | bronze2 |
Please see below code that working for me
// Create connection
$conn = new mysqli($servername, $username, $password,$dbname);
// get all row
$sql = "select id, title from arts order by title asc";
$result = $conn->query($sql);
while ($row=$result->fetch_assoc()) {
$title=$row['title'];
// select where title is same
$sql = "select * from arts where title='".$title."'";
$result2 = $conn->query($sql);
// if number of row is greater then one
if ($result2->num_rows > 1){
$x=0;
while ($row2=$result2->fetch_assoc()) {
$id=$row2['id'];
// skip first row
if($x>0){
$newTitle=$title.' '.$x;
$uquery = "update arts set title='".$newTitle."' where title='".$title."' and id=$id";
$update = $conn->query($uquery);
}
$x++;
}
}
}
and after query run
This works in MySql 5.7:
update arts a inner join (
select * from (
select t.id,
(
select count(*) + 1 from arts
where id < t.id and title = t.title
) counter
from arts t
) t
) t on t.id = a.id
set a.title = concat(a.title, ' ', t.counter)
where a.title in (
select h.title from (
select title from arts
group by title
having count(*) > 1
) h
);
See the demo.
For data:
| id | title |
| --- | -------- |
| 1 | silver |
| 2 | gold |
| 3 | diamond |
| 4 | bronze |
| 5 | gold |
| 6 | bronze |
| 7 | gold |
the result is
| id | title |
| --- | -------- |
| 1 | silver |
| 2 | gold 1 |
| 3 | diamond |
| 4 | bronze 1 |
| 5 | gold 2 |
| 6 | bronze 2 |
| 7 | gold 3 |
I think It would be more efficient to do this in SQL too, but you may can do a function to validate the duplicate, something like this:
function isDuplicated( $title, $db ){
$dp = $db->query("SELECT * FROM arts WHERE title = $title");
if ( $dp->num_rows > 1)
return true;
return false;
}
$st = $db->query("select id, title from arts order by title asc");
$st->execute();
$x = 0;
while($row = $st->fetch()){
$title = $row['title'];
if( isDuplicated( $title, $db ) ){
$x++;
$title .= ' ' . $x;
$stb = $db->query("update arts set title = '" . $title . "' where id = " . $row['id']);
$stb->execute();
}
}
I have two tables in my mySQL database:
table "animals":
| animal | name |
|:-----------|------------:|
| cat | Tom |
| dog | |
table "orders":
| id | animal |
|:-----------|------------:|
| 1 | cat |
| 2 | dog |
At first I select from the table "orders" the following data:
<?php
$pdo = Database::connect();
$sql = 'SELECT * FROM orders ORDER BY id ASC';
foreach ($pdo->query($sql) as $row) {
echo ('<td>a:'.$row['id'].'</td>');
echo ('<td>b:'.$row['animal'].'</td>');
echo ('<td>c:'.$row['animal'].'</td>');
}
Database::disconnect();
?>
Now I want to check if in my mySQL table "animal" the animal has a name. If yes print at position b the name. If there is no name print the animal:
| a:1 | b:Tom | c:cat |
| a:2 | b:dog | c:dog |
Thank you for your answers! I tried to work now with the answer of Jayo2k. I need to do a little change in my question, I found out I did a little mistake. So here I try to describe what I need as specific as possible:
table "animals":
| name | animal |
|:-----------|------------:|
| Tom | cat |
| Jerry | dog |
| Alfred | duck |
| Sam | |
| Donald | |
table "orders":
| id | animal |
|:-----------|------------:|
| 1 | cat |
| 2 | dog |
| 3 | duck |
| 4 | frog |
| 5 | pig |
With the following code from Jayo2k...
<?php
$pdo = Database::connect();
$sql = "SELECT * FROM animals, orders WHERE orders.animal = animals.animal";
foreach ($pdo->query($sql) as $row) {
echo '<tr> ';
echo('<td>a:'.$row['id'].' </td>');
echo('<td>a:'.$row['animal'].' </td>');
echo('<td>b:'.$row['name'].' </td>');
echo '</tr> ';
}
Database::disconnect();
?>
... I get this result:
| a:1 | b:cat | c:Tom |
| a:2 | b:dog | c:Jerry |
| a:3 | b:duck | c:Alfred |
But what I need is:
| a:1 | b:cat | c:Tom |
| a:2 | b:dog | c:Jerry |
| a:3 | b:duck | c:Alfred |
| a:4 | b:frog | c:frog |
| a:5 | b:pig | c:pig |
You can use LEFT JOIN, and use the IF condition to check the value is not empty, along with IFNULL, that will make null values in columns to blank.
SELECT O.id, IF(IFNULL(A.name, '') = '', A.animal, A.name) name, A.animal
FROM orders O
LEFT JOIN animals A
ON O.animal = A.animal
ORDER BY O.id DESC
What I do is (I am using PDO):
SELECT * FROM animal, orders WHERE orders.animal = animals.animal
It will select both animals and orders table and joint the animal row from orders with the animal row from animal.
you should get an array like this
[0] =>
id = 1
name = tom
animal = cat
[1] =>
id = 2
name =
animal = dog
Now up to you to do all the modification you want
I have comma-separated field base_users in my database. How do I query to count the totaluser of that group? I have no problem to calculate the totaluser if the data is not in comma-separated field.
SELECT COUNT(base_u_id) AS totaluser
FROM base_users
WHERE base_u_group =".$row['base_gp_id']."
1)base_users
|base_u_id | base_u_name | base_u_group |
------------------------------------------
| 1 | username1 | 1, 2, 4 |
| 2 | username2 | 3 |
| 3 | username3 | 3, 4 |
| 4 | username4 | 1, 4 |
2)base_groups
| base_gp_id | base_gp_name |
------------------------------
| 1 | group1 |
| 2 | group2 |
| 3 | group3 |
| 4 | group4 |
| 5 | group5 |
From the sample database above, my expected result will be:
Total User of group1 = 2
Total User of group2 = 1
Total User of group3 = 2
Total User of group4 = 3
Total User of group5 = 0
This is what I have tried so far:
<?php
$getUser = base_executeSQL("SELECT * FROM base_users");
while($row_getUser = base_fetch_array($getUser))
{
$explodeData = explode(", ",$row_getUser['base_u_group']);
foreach($explodeData as $data)
{
$getUserGroupSQL = base_executeSQL("SELECT COUNT(base_u_id) AS totaluser FROM base_users as user, base_groups as gp WHERE gp.base_gp_id ='".$data."' ");
while($UserGroupProfile_row = base_fetch_array($getUserGroupSQL))
if (base_num_rows($getUserGroupSQL)!= 0)
$totaluser = $UserGroupProfile_row["totaluser"];
elseif (base_num_rows($getUserGroupSQL)== 0)
$totaluser = 0;
}
}
?>
Use below logic: Just HINT
$group = array(1=>0,2=>0,3=>0,4=>0,5=>0);
$base_u_group = array('1,2,4','3','3,4','1,4');
foreach($base_u_group as $gr) {
$split = explode(',', $gr);
if (!empty($split)) {
foreach($split as $val) {
if ($val) {
$group[$val] = $group[$val] + 1;
}
}
}
}
var_dump($group);
Try this:
SELECT COUNT(u.base_u_id), g.base_gp_name FROM base_users u
INNER JOIN base_groups g ON IF(POSITION(',' IN u.base_u_group) > 0, u.base_u_group LIKE ('".$row['base_gp_id'].",%') OR u.base_u_group LIKE ('%, ".$row['base_gp_id'].",%') OR u.base_u_group LIKE ('%, ".$row['base_gp_id']."'), u.base_u_group = '".$row['base_gp_id']."')
WHERE g.base_gp_id = ".$row['base_gp_id']."
i have table in database:
Group:
| id | Category | title |
| 1 | 1 | group1 |
| 2 | 2 | group2 |
| 3 | 1 | group3 |
| 4 | 3 | group4 |
| 5 | 2 | group5 |
| 6 | 1 | group6 |
News:
| id | Group | title | body |
| 1 | 3 | title1 | body1 |
| 2 | 2 | title2 | body2 |
| 3 | 1 | title3 | body3 |
| 4 | 4 | title4 | body4 |
| 5 | 1 | title5 | body5 |
| 6 | 5 | title6 | body6 |
| 7 | 3 | title7 | body7 |
| 8 | 2 | title8 | body8 |
| 9 | 1 | title9 | body9 |
| 10 | 6 | title10| body10 |
| 11 | 1 | title11| body11 |
| 12 | 5 | title12| body12 |
how can i show this as:
-GROUP1, GROUP3 and GROUP6
//GROUP1 (category1)
--title3
--title5
--title9
//GROUP3 (category1)
--title1
--title7
//GROUP6 (category1)
--title10
-GROUP2 and GROUP5
//GROUP2 (category2)
--title2
--title8
//GROUP5 (category2)
--title6
--titl12
-GROUP4
//GROUP4 (category3)
--title4
i will make this in foreach. thanks for help!
Your exact requested output makes this complicated.
$sql = 'SELECT n.title, n.Group AS group_id, g.Category AS cat_id
FROM News AS n
JOIN Group AS g ON g.id = group_id
ORDER BY cat_id, group_id, n.id';
$result = mysql_query($query);
$categories = array();
while ($row = mysql_fetch_assoc($result)) {
$catID = $row['cat_id'];
$groupID = $row['group_id'];
$title = $row['title'];
$categories[$catID]['groups'][$groupID]['titles'][] = $title;
}
foreach ($categories as $catID => $groups) {
$catGroups = '-GROUP'.implode(', GROUP',array_keys($groups)).PHP_EOL;
$lastComma = strrpos($catGroups,',');
if ($lastComma !== false) {
$catGroups = substr($catGroups,0,$lastComma-1).
' AND ' .substr($catGroups,$lastComma+1);
}
echo $catGroups;
foreach ($groups as $groupID => $titles) {
echo "//GROUP$groupID (category$catID)".PHP_EOL;
foreach ($groups as $group => $titles) {
echo '--'.$title.PHP_EOL;
}
}
}
If you didn't need such fancy output, this would be much simpler.
$sql = 'SELECT n.title, n.Group AS group_id, g.Category AS cat_id
FROM News AS n
JOIN Group AS g ON g.id = group_id
ORDER BY cat_id, group_id, n.id';
$result = mysql_query($query);
$lastCatID = null;
$lastGroupID = null;
while ($row = mysql_fetch_assoc($result)) {
$catID = $row['cat_id'];
$groupID = $row['group_id'];
$title = $row['title'];
if ($catID !== $lastCatID){
echo "*** CATEGORY $catID\n";
$lastCatID = $catID;
}
if ($groupID !== $lastGroupID){
echo "GROUP $groupID\n";
$lastGroupID = $groupID;
}
echo "-- $title\n";
}
You told, you have your values in the database. So you have to get them first, e.g. with the following database query:
SELECT
g.`title` AS `group_title`
, n.`title` AS `news_title`
FROM
`Group` AS g
INNER JOIN
`News` AS n
ON
g.`id` = n.`Group`
ORDER BY
g.`Category`
, n.`Group`
, n.`title`
Store the data in an array. Now you can use a foreach loop to iterate over the array.
===
Here my update:
First fill the array while reading from the database (example query see above).
<?php
$data = array();
$res = mysql_query('SELECT ...');
while (($row = mysql_fetch_assoc($res)) !== false) {
$data[$row['group_title']][] = $row['news_title'];
}
?>
Then write the array to the screen:
<?php
foreach ($data as $group_title => $groups) {
echo $group_title . "\n";
foreach ($groups as $news) {
echo "\t" . $news . "\n";
}
}
?>