How to display data one to many relationship using php and mysql - php

I have a lot of products and each product has many flavour. How can i display one product name with multiple flavor. below is the script that i have tried.
It doesn't display anything. I'm really new to php.
$res = $conn->query("SELECT as_product.p_id,GROUP_CONCAT(as_product_flavour.pfl_prod_id) as flavours FROM as_product
LEFT JOIN as_product_flavour ON as_product.p_id = as_product_flavour.pfl_prod_id
WHERE as_product.p_id = 28 GROUP BY as_product.p_id");
$currGroup = -1;
while($row = $res->fetch_assoc())
{
echo 'Product Name: '.$row['product_name'];
if($row['flavours'] != $currGroup)
{
$currGroup = $row['p_id'];
echo 'Flavour Id: ' . $row['pfl_id'] . '\n';
echo 'Falvour Name: ' . $row['pfl_flavour'] . '\n';
}
}

I would start with a simpler query...
SELECT p.p_id
, f.pfl_prod_id
FROM as_product p
LEFT
JOIN as_product_flavour f
ON p.p_id = f.pfl_prod_id
WHERE p.p_id = 28
...and handle any remaining display issues in the application code, so a simple transformation of your resulting array.

Related

inner join gives back multiple values

I have products, All of these products have for example. An id, name and price. All of these products are connected in the database like this:
Since I don't have 10 reputation... Here is a link to a picture http://puu.sh/oS95c/b7b5b17427.png
What I want to achieve is to have products that are connected to another product show up on the screen using inner join. However instead of getting the connected items back I get back every item of the right column even if they are not connected.
Here is a link to get a better view of the database: http://puu.sh/oSBF2/1af1ce3751.png
$sql = "SELECT AFBEELDING_KLEIN, PRODUCTNAAM, PRIJS
FROM PRODUCT
inner JOIN PRODUCT_GERELATEERD_PRODUCT
ON PRODUCT.PRODUCTNUMMER=PRODUCT_GERELATEERD_PRODUCT.PRODUCTNUMMER_GERELATEERD_PRODUCT";
$result = sqlsrv_query($db, $sql);
$data = sqlsrv_fetch_array($result);
while($data = sqlsrv_fetch_array($result)) {
$big_picture = '<img src="../' . $data["AFBEELDING_KLEIN"] . '"' . 'alt="product">';
$link = '<a href="../productpaginas/' . $data["PRODUCTNAAM"] . '.php"<p> ' . $data["PRODUCTNAAM"] . '</p></a>';
$price = '<h2> €' . $data["PRIJS"] . '</h2>';
echo '<div class="product">';
echo $big_picture;
echo $link;
echo $price;
echo '</div>';
}
Since you immune to questions and don't provide more information, we can only guess.
You might want a m:n link back to the product table itself.
SELECT
p1.PRODUCTNUMMER, p2.AFBEELDING_KLEIN, p2.PRODUCTNAAM, p2.PRIJS
FROM
PRODUCT AS p1
INNER JOIN
PRODUCT_GERELATEERD_PRODUCT AS pgp
ON
p1.PRODUCTNUMMER = pgp.PRODUCTNUMMER
INNER JOIN
PRODUCT AS p2
ON
pgp.PRODUCTNUMMER_GERELATEERD_PRODUCT = p2.PRODUCTNUMMER
;

store multiple row result from mySQL left join query as one variable

I am new to php and mySQL. I have a left join query that I am using to find all the products a customer has registered. My query works in phpmyadmin, and I can echo it in php with the following code:
$custProds = "SELECT t.prodType, s.sizes, c.color FROM registeredProducts p LEFT JOIN prodTypes t ON t.id = p.prodType LEFT JOIN prodSizes s ON s.id = p.prodSize LEFT JOIN prodColors c ON c.id = p.prodColor WHERE p.customerID = '".$thisCust."'";
$allCustProds = mysql_query($custProds);
while($prodRow = mysql_fetch_array($allCustProds)){
echo $prodRow['prodType']. " - ". $prodRow['sizes']. " - ". $prodRow['color'];
echo "<br />";
}
However, I don't want to echo it for the user to see, I want to store the result in a variable for later use. I have tried doing this instead:
while($prodRow = mysql_fetch_array($allCustProds)){
$allProds = $prodRow['prodType']. " - ". $prodRow['sizes']. " - ". $prodRow['color'];
}
but that only gives me the most recent row inserted instead of all results. Same with using my_fetch_assoc as seen here. I have also tried this:
while($prodRow = mysql_fetch_array($allCustProds)){
$allProds = array($prodRow['prodType']. " - ". $prodRow['sizes']. " - ". $prodRow['color']);
}
which echos 'Array'. I followed this post and used print_r($allProds); which once again only gave me the last inserted row. I have spent hours researching this and would be so grateful for any help. Thank you.
I figured it out and wanted to post in case any one else has this issue. Needed to declare $allProds as an array, and then use array_push to store each instance. Then used implode to store into one variable for later use.
$custProds = "SELECT t.prodType, s.sizes, c.color FROM registeredProducts p LEFT JOIN prodTypes t ON t.id = p.prodType LEFT JOIN prodSizes s ON s.id = p.prodSize LEFT JOIN prodColors c ON c.id = p.prodColor WHERE p.customerID = '".$thisCust."'";
$allCustProds = mysql_query($custProds);
$allProds = array();
while($prodRow = mysql_fetch_assoc($allCustProds)){
array_push($allProds, $prodRow['prodType']. " - ". $prodRow['sizes']. " - ". $prodRow['color']);
}
$custProds = implode('<br>', $allProds);
As you figured out, you needed to push the rows into an array variable. This is another form of that, using a unique ID, if you have one, in case you want to pull a specific row out later.
while($prodRow = mysql_fetch_array($allCustProds)){
$allProds[$prodRow['prodID']] = array($prodRow['prodType']. " - ". $prodRow['sizes']. " - ". $prodRow['color']);
}
foreach ( $allProds as $prodID => $prodRow ) {
echo "$prodID: $prodRow<br>";
}
// can also be accessed by:
echo $allProds[$getProdID];

php foreach in foreach in foreach

This is a hypothetical question. If I have 3 arrays from 3 separate sql db queries that all relate to another. For example...
//db
schools
id | school_name
classes
id | class_name | school_id
students
id | student_name | class_id
And I want to display everything in a huge list like this...
//php
foreach(schools as school){
echo '<h1>' . $school->school_name . '<h1>';
foreach(classes as class){
if($class->school_id == $school->id){
echo '<h2>' . $class->class_name . '<h2>';
foreach(students as student){
if($student->class_id == $class->id){
echo '<h3>' . $student->student_name . '<h3>';
}
}
}
}
}
I have to make 3 database calls. Is there a way to grab all this information in a single db query? Like maybe an array in an array in an array and then somehow loop through? Or is this the best way to do this?
You can do a join which will allow you to have 1 for each. Are you wanting everything or any sort of filter ?
You can join those table, to get one big array with flattened data. When looping through this data, you can check if the id of the previous record still matches the id of the current record. If not, you can output a new header. It is important, though, that the resultset is properly sorted for this.
SELECT
s.id AS school_id,
s.school_name,
c.id AS class_id,
c.class_name,
st.id AS student_id,
st.student_name
FROM
schools s
INNER JOIN classes c ON c.school_id = s.id
INNER JOIN students st ON st.class_id = c.id
ORDER BY
s.id,
c.id,
st.id
If you have it all in a flattened structure, you can even make it into a nested array structure again something like this:
foreach ($resultset as $row)
{
$schools[$row->school_id]->school_name =
$row->school_name;
$schools[$row->school_id]->classes[$row->class_id]->class_name =
$row->class_name;
$schools[$row->school_id]->classes[$row->class_id]->students[$row->student_id]->student_name =
$row->student_name;
}
var_dump($schools);
After that, you can still use the nested for loops to process the array, but it will be in a more efficient way, since the data is already sorted out: classes are already added to the school they belong to, and student are already added to the right class.
<?php
try {
$pdo = new PDO("mysql:host=127.0.0.1;dbname=school", "username");
} catch (PDOException $e) {
echo "PDO Connection failed: " . $e->getMessage();
exit(1);
}
$sql = <<<SQL
SELECT schools.school_name, classes.class_name, students.student_name
FROM
schools INNER JOIN classes ON (schools.id = classes.school_id)
INNER JOIN students ON (classes.id = students.class_id)
ORDER BY 1, 2;
SQL;
$result = $pdo->query($sql);
if ($result == false) {
die("query failed?!");
}
$school = "";
$class = "";
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
if ($school != $row['school_name']) {
$school = $row['school_name'];
echo "\nSchool: $school\n\n";
}
if ($class != $row['class_name']) {
$class = $row['class_name'];
echo " Class: $class\n\n";
echo " Student list:\n";
}
echo " {$row['student_name']}\n";
}
$res = mysql_query('SELECT school_name, class_name, student_name, sc.id AS scid, c.id AS cid, st.id AS stid FROM schools sc LEFT JOIN classes c ON (sc.id = c.school_id) LEFT JOIN students st ON (c.id = st.class_id) ');
$arr = array();
while ($v = mysql_fetch_assoc($res)) {
$arr[$v['school_name']][$v['class_name']][$v['stid']] = $v['student_name'];
}
print_r($arr);
You could do it all in one SQL query that might look something like:
SELECT schools.schoolname, classes.class_name, students.student_name
FROM
schools INNER JOIN classes ON (schools.id = classes.school_id)
INNER JOIN students ON (classes.id = students.class_id)
ORDER BY 1, 2;
Then you could walk the result set in one loop, but you'd probably want to add some logic to only display the school name and class name once for each time it changes.

Prestashop product features PHP SQL

We are wanting to do a quick compare on the product page that compares the current product and then the two top sellers in that category after that. I have all the SQL to get the current product and the two that are top sellers, but am having trouble adding the features to those. This is what I am facing.
This is just as an example. This SQL would pull the product features within a category.
SELECT ps_product.id_product, ps_feature_lang.name, ps_feature_value_lang.value FROM ps_product LEFT JOIN ps_feature_product ON ps_feature_product.id_product = ps_product.id_product LEFT JOIN ps_feature_lang ON ps_feature_lang.id_feature = ps_feature_product.id_feature LEFT JOIN ps_feature_value_lang ON ps_feature_value_lang.id_feature_value = ps_feature_product.id_feature_value WHERE ps_product.id_category_default = '6' AND ps_feature_lang.id_feature IS NOT NULL
It returns
id_product | name | value
9 Height 5
9 Width 5
9 Depth 5
9 Weight 5
10 Height 10
I have tried to group by id_product, but of course that will only show on of the values from the features list for that product. I have also tried putting them into arrays by products, but can't get them to line up correctly on the front end.
I wasn't sure if prestashop already had a built in function to pull product features
With MySQL you can try to use GROUP_CONCAT() that could help for this query. However, we wrote a quick code snippet to give you an overview of what you can do.
This code:
Retrieves the two best sellers of the current product's category
Retrieves the features list for the 3 products (Current product + 2 best sellers)
Group these and display them into an HTML table
Here is the final result:
Product comparison
Code:
<?php
include(dirname(__FILE__).'/config/config.inc.php');
include(dirname(__FILE__).'/init.php');
ini_set('display_errors', 'On');
$id_product = 1; /* Current Product ID */
$id_category = 2; /* Current Category ID */
$id_lang = 1; /* Current Language ID */
/* Retrieve the two Best sellers for this category, excluding the current product */
$best_sellers = Db::getInstance()->ExecuteS('
SELECT ps.id_product, pl.name product_name
FROM '._DB_PREFIX_.'product_sale ps
LEFT JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = ps.id_product)
LEFT JOIN '._DB_PREFIX_.'product p ON (p.id_product = cp.id_product)
LEFT JOIN '._DB_PREFIX_.'product_lang pl ON (pl.id_product = p.id_product)
WHERE cp.id_category = '.(int)$id_category.' AND cp.id_product != '.(int)$id_product.' AND p.active = 1 AND pl.id_lang = '.(int)$id_lang.'
ORDER BY ps.sale_nbr DESC
LIMIT 2');
if (count($best_sellers))
{
$products_to_compare = array();
$products_names = array();
foreach ($best_sellers as $best_seller)
{
$products_to_compare[] = (int)$best_seller['id_product'];
$products_names[(int)$best_seller['id_product']] = $best_seller['product_name'];
}
$products_to_compare[] = (int)$id_product;
$products_names[(int)$id_product] = 'Current product'; /* Replace by the current product name */
$features = Db::getInstance()->ExecuteS('
SELECT fp.id_product, fp.id_feature, fl.name feature_name, fvl.value feature_value
FROM '._DB_PREFIX_.'feature_product fp
LEFT JOIN '._DB_PREFIX_.'feature_lang fl ON (fl.id_feature = fp.id_feature)
LEFT JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = fp.id_feature_value)
WHERE fp.id_product IN ('.pSQL(implode(',', $products_to_compare)).')');
$features_to_display = array();
foreach ($features as $feature)
{
if (!isset($features_to_display[(int)$feature['id_feature']]))
{
$features_to_display[(int)$feature['id_feature']] = array();
$features_to_display[(int)$feature['id_feature']]['name'] = $feature['feature_name'];
}
$features_to_display[(int)$feature['id_feature']][(int)$feature['id_product']] = $feature['feature_value'];
}
echo '
<table cellpadding="5" cellspacing="0" border="1">
<tr>
<td></td>';
foreach ($products_to_compare as $product_to_compare)
echo '<td>'.($product_to_compare == $id_product ? '<b>' : '').Tools::safeOutput($products_names[(int)$product_to_compare]).($product_to_compare == $id_product ? '</b>' : '').'</td>';
echo '</tr>';
foreach ($features_to_display as $feature_to_display)
{
echo '
<tr>
<td>'.Tools::safeOutput($feature_to_display['name']).'</td>';
foreach ($products_to_compare as $product_to_compare)
echo '<td>'.($product_to_compare == $id_product ? '<b>' : '').Tools::safeOutput($feature_to_display[(int)$product_to_compare]).($product_to_compare == $id_product ? '</b>' : '').'</td>';
echo '
</tr>';
}
echo '
</table>';
}
else
die('Sorry, no best sellers for this category');
This code can be improved to save memory and transmit the results to Smarty (instead of displaying these directly in the controller).

MySQL - Datas all included in larger data set

So I have 2 tables:
user_selection (id, user_id, fiche_id)
fiche (id, title, ...)
(fiche = sheet)
I have a research request which gives me some fiche ids
SELECT fiche.*, IF(fiche.fiche_type_id = 2,fiche.instance,fiche_type_texte.type_texte) AS type_texte, IF(fiche.fiche_type_id = 2,CONCAT(fiche.affaire," - ", fiche.titre),fiche.titre) AS titre, IF(fiche.fiche_type_id = 1,fiche.date_publication,fiche.date_texte) AS date_publication
FROM enviroveille_bascule.fiche
LEFT JOIN enviroveille_bascule.fiche_type_texte ON(fiche.fiche_type_texte_id = fiche_type_texte.id)
LEFT JOIN enviroveille_bascule.fiche_x_keyword ON(fiche_x_keyword.fiche_id = fiche.id)
LEFT JOIN enviroveille_bascule.fiche_x_theme ON(fiche_x_theme.fiche_id = fiche.id)
LEFT JOIN enviroveille_bascule.fiche_echeance ON(fiche_echeance.fiche_id = fiche.id)
LEFT JOIN enviroveille_bascule.fiche_x_activite ON(fiche_x_activite.fiche_id = fiche.id) LEFT JOIN enviroveille_bascule.fiche_x_nomenclature ON(fiche_x_nomenclature.fiche_id = fiche.id)
WHERE 1 = 1
AND fiche_echeance.fiche_echeance_type_id IN(2)
GROUP BY fiche.id
I'd like to know if all results from my research query is in the user selection.
So I tried :
// fiche_ids is an array of fiche.id resulting from research request
SELECT COUNT(*) AS nb
FROM " . $this->bdd . $this->table_user_selection . "
WHERE user_id = '" . $user->datas_user['id'] . "'
AND fiche_id IN ('" . implode("','", $fiche_ids) . "')
if($ds['nb'] == count($fiche_ids) && count($fiche_ids) > 0) {
return true;
} else {
return false;
}
That works well
Problem is that I have some research request giving 10K+ results.
And I have to do it several time on the same page, which makes server lags.
Is there a easy way to know if all my results are in my selection?
Note that selection may contain more fiche_id than the research result.
The best would be to be able do this in one SQL request.

Categories