SELECT from MYSQL with INNER JOIN on multiples of the same ID - php

So im just wondering if the next is possible and if so how to approach this.
I created an INNER JOIN query to SELECT multiple ID's from on a table where it is equal to the ID value from another table.
Product table
product_id | cults_id1 | cults_id2 | cults_id3
-----------------------------------------------------
1 | 5 | 4 | 2
2 | 3 | 0 | 0
Cultivar table
cults_id | cults_name |
---------------------------
1 | berries |
2 | fruit |
3 | choc |
4 | wood |
5 | mysql! |
So i created an join where it will fetch all the cults_name based on the product tables cults_id1, cults_id2, cults_id3
Result:
Product_id(1) = mysql! , wood , fruit
Now the problem comes with the next one how can i display the one value that product_id(2) contains.
So it would result in looking like this:
Product_id(1) = mysql! , wood , fruit
Product_id(2) = choc
At this moment product_id(2) wont display in my listing because it has no resemble to the Cultivar table after the first ID, (using this query).
I know normalisation should be considered.
Query
SELECT p.product_image_path, p.product_id, p.brand_name, p.product_name, b.botttle_size, v.vintage,
t.wine_type_blend, p.price, p.quantity, p.time_created, p.reference_number, p.shipping_cost,
c1.cultivar_type as cultivar_type1, c2.cultivar_type as cultivar_type2,
c3.cultivar_type as cultivar_type3, c4.cultivar_type as cultivar_type4
FROM product p
INNER JOIN wine_bottle b ON b.bottle_id = p.bottle_id
INNER JOIN wine_vintage v ON v.vintage_id = p.vintage_id
INNER JOIN wine_type t ON t.type_id = p.type_id
INNER JOIN wine_cultivar c1 ON c1.cultivar_id = p.cultivar_1_id
INNER JOIN wine_cultivar c2 ON c2.cultivar_id = p.cultivar_2_id
INNER JOIN wine_cultivar c3 ON c3.cultivar_id = p.cultivar_3_id
INNER JOIN wine_cultivar c4 ON c4.cultivar_id = p.cultivar_4_id
Now my product listing page has this to display it in listing but i want to display even if cults_id1, cults_id2, cults_id3 has an value of 0.
Product-listing.php
<?php
if($result = mysqli_query($conn, $query)){
if(mysqli_num_rows($result) > 0){
$i = 0;
while($row = mysqli_fetch_array($result)){
$i++;
echo "
<p>Cultivars: <span>" .$row["cultivar_type1"]. "</span>, <span>" .$row["cultivar_type2"]. "</span>, <span>" .$row["cultivar_type3"]. "</span>, <span>" .$row["cultivar_type4"]. "</span></p> ";
}
mysqli_free_result($result);
}
}
Output:
Product_id(1) = mysql! , wood , fruit
Expected:
Product_id(1) = mysql! , wood , fruit
Product_id(2) = choc

So the only thing that i needed to to was to create an LEFT JOIN. Because an LEFT JOIN can accept 0 or an value. And my query worked.
Yes this my mysql DB is not the normalized as would be expected.
Solution:
SELECT p.product_image_path, p.product_id, p.brand_name, p.product_name, b.botttle_size, v.vintage,
t.wine_type_blend, p.price, p.quantity, p.time_created,
p.reference_number, p.shipping_cost,
c1.cultivar_type as cultivar_type1, c2.cultivar_type as cultivar_type2,
c3.cultivar_type as cultivar_type3, c4.cultivar_type as cultivar_type4
FROM product p
INNER JOIN wine_bottle b ON b.bottle_id = p.bottle_id
INNER JOIN wine_vintage v ON v.vintage_id = p.vintage_id
INNER JOIN wine_type t ON t.type_id = p.type_id
LEFT JOIN wine_cultivar c1 ON c1.cultivar_id = p.cultivar_1_id
LEFT JOIN wine_cultivar c2 ON c2.cultivar_id = p.cultivar_2_id
LEFT JOIN wine_cultivar c3 ON c3.cultivar_id = p.cultivar_3_id
LEFT JOIN wine_cultivar c4 ON c4.cultivar_id = p.cultivar_4_id

Related

INNER JOIN mysql from one table to another where its based on multiples of same id

I have an table called product which lets say looks like this:
product
product_id | cults_id1 | cults_id2 | cults_id3
-----------------------------------------------------
1 | 5 | 4 | 2
And the also a table thats based on this called cultivar:
cultivar
cults_id | cults_name |
-------------------------
1 | berries |
2 | fruit |
3 | choc |
4 | wood |
5 | mysql! |
How would i create an JOIN query to get each name from cultivar table where the product id in product table is the same as cults_id in the cultivar table?
OUTPUT
My Product Cults :
berries, Mysql!, wood, fruit
Dont think an INNER JOIN is the way to go but i would have tried something like this:
$query = "SELECT cultivars.cults_name
FROM product
INNER JOIN wine_cultivar ON wine_cultivar.cults_id = product.cultivar_1_id
INNER JOIN wine_cultivar ON wine_cultivar.cults_id = product.cultivar_2_id
INNER JOIN wine_cultivar ON wine_cultivar.cults_id = product.cultivar_3_id
INNER JOIN wine_cultivar ON wine_cultivar.cults_id = product.cultivar_4_id
";
i tried a inner join multiple times targeting all the ids but dont think this is the way to go. Also this is just a part of my sql query.
Simply assign table aliases to each self join and then reference corresponding fields in SELECT.
Right now you join to same table but do not provide aliases to distinguish between the four which MySQL should have raised its Error #1066 for this attempt.
SELECT p.product_image_path, p.product_id, p.brand_name, p.product_name, b.botttle_size, v.vintage,
t.wine_type_blend, p.price, p.quantity, p.time_created, p.reference_number, p.shipping_cost,
c1.cultivar_type as cultivar_type1, c2.cultivar_type as cultivar_type2,
c3.cultivar_type as cultivar_type3, c4.cultivar_type as cultivar_type4
FROM product p
INNER JOIN wine_bottle b ON b.bottle_id = p.bottle_id
INNER JOIN wine_vintage v ON v.vintage_id = p.vintage_id
INNER JOIN wine_type t ON t.type_id = p.type_id
INNER JOIN wine_cultivar c1 ON c1.cultivar_id = p.cultivar_1_id
INNER JOIN wine_cultivar c2 ON c2.cultivar_id = p.cultivar_2_id
INNER JOIN wine_cultivar c3 ON c3.cultivar_id = p.cultivar_3_id
INNER JOIN wine_cultivar c4 ON c4.cultivar_id = p.cultivar_4_id

MYSQL joining three tables

I have a simple multiple school management system and I am trying to get total number of teachers, and total number of students for a specific school. My table structures are as follows:
teachers
--------------------------
id | schoolid | Name | etc...
--------------------------
1 | 1 | Bob |
2 | 1 | Sarah|
3 | 2 | John |
students
--------------------------
id | schoolid | Name | etc...
--------------------------
1 | 1 | Jack |
2 | 1 | David|
3 | 2 | Adam |
schools
--------------------------
id | Name | etc...
---------------------------
1 | River Park High |
2 | Stirling High |
I can count just all teachers with the following query:
SELECT COUNT(a.id) AS `totalteachers`
FROM teachers a
LEFT JOIN schools b ON a.schoolid = b.id WHERE b.id = '1'
and similarly I can count the number of teachers with the following query:
SELECT COUNT(a.id) AS `totalstudents`
FROM students a
LEFT JOIN schools b ON a.schoolid = b.id WHERE b.id = '1'
I am however struggling with trying to combine these two queries to get a simple result like this:
totalstudents | totalteachers
--------------------------------
2 | 2
I have tried the following:
SELECT COUNT(a.id) as `totalteachers`, COUNT(c.id) as `totalstudents`
FROM teachers a
LEFT JOIN schools b ON a.schoolid = b.id
LEFT JOIN students c ON c.schoolid=b.id WHERE b.id = '5'
You can do something like this
SELECT
id, name, s.total AS totalstudents, t.total AS totalteachers
FROM schools
JOIN (SELECT schoolid, COUNT(id) AS total FROM teachers GROUP BY schoolid)
AS t ON t.schoolid = id
JOIN (SELECT schoolid, COUNT(id) AS total FROM students GROUP BY schoolid)
AS s ON s.schoolid = id
then you can add where id = 2 or whatever to limit the school.
The problem with the multiple left joins is it generates additional records for each teacher to each student; artifically inflating your counts
There's four ways to solve this: (best imo is what Andrew bone did)
Simply select inline without the joins so the counts are not inflated. (most desirable in my mind as it's easy to maintain)
SELECT (SELECT COUNT(a.id) AS `totalteachers`
FROM teachers a
WHERE A.SchoolID = '1') as TotalTeachers
, (SELECT COUNT(a.id) AS `totalstudents`
FROM students a
WHERE a.SchoolID = '1') as TotalStudents
Use subqueries to get the counts first before the joins, then join. Since count will always be 1 a cross join works.
SELECT totalTeachers, totalStudents
FROM (SELECT COUNT(a.id) AS `totalteachers`
FROM teachers a
LEFT JOIN schools b
ON a.schoolid = b.id
WHERE b.id = '1')
CROSS JOIN (SELECT COUNT(a.id) AS `totalstudents`
FROM students a
LEFT JOIN schools b ON a.schoolid = b.id
WHERE b.id = '1')
Use key word distinct within the count so as not to replicate the counts and negate the artificial inflation (least desirable in my mind as this hides the artifical count increase)
SELECT COUNT(distinct a.id) as `totalteachers`, COUNT(distinct c.id) as `totalstudents`
FROM teachers a
LEFT JOIN schools b ON a.schoolid = b.id
LEFT JOIN students c ON c.schoolid=b.id WHERE b.id = '5'
Another way would be to use a window functions, however these are not available in mySQL.
SELECT COUNT(t.id) AS TotalTeachers, COUNT(st.id) AS TotalStudents
FROM schools s
INNER JOIN teachers t
ON s.id = t.schoolid
INNER JOIN students st
ON s.id = st.schoolid
Try this SQL. I havn't try it but it should work.

Join Three tables in mysql with weird requirement

I have three tables in my db.
Table A has the fields
KEYID | KeyName
27 | Income
28 | Account Number
Table B has the fields
UserID | Email | Name | Phone
481 | test#gmail.com | test | 99999999
Table C has the fields
ID | KEYID | UserID | Value
1 | 27 | 481 | 10,000
I need to display the table fields headers are:
UserID | Email | Name | Phone | Income
and the table values should be like this:
481 | test#gmail.com | test | 99999999 | 10,000
I can get the KeyIDs which should be displayed in the table. In this example the KeyIDs string is '27' . I tried with joining and i can fetch & display the value in the table. but i dont know how i can show the key name as table header.
Any Idea.?
You can use a pair of inner join
select b.UserID, b.Email , b.Name, c.value as income
from tableB as b inner join tableC as C on b.userID = c.userId
inner join tableA as a on a.keyID = c.keyID
and a.keyname = 'Income';
and the query you provided in comment
select
b.UserID
, b.Email
, b.Name
, Group_Concat(Distinct Concat(c.keyID,’^:^’,c.value)
Order By c.id Separator ‘;’) As Keyvalues
from tableB as b
inner join tableC as C on b.userID = c.userId
inner join tableA as a on a.keyID = c.keyID;
and with CASE should be
select
b.UserID
, b.Email
, b.Name
, Group_Concat(Distinct CASE
WHEN c.keyID IN ('1,23,10') THEN Concat(c.keyID,’^:^’,c.value) END
Order By c.id Separator ‘;’) As Keyvalues
from tableB as b
inner join tableC as C on b.userID = c.userId
inner join tableA as a on a.keyID = c.keyID;
This query should help to get your desire result.
select b.UserID, b.Email, b.Name, b.Phone, c.Value as Income
from table_b as b
JOIN table_c as c ON (b.UserID = c.UserID)
where c.KEYID = 27
Try this:
SELECT b.userid, b.email, b.name, b.phone, c.value as income
FROM a
LEFT JOIN c on c.keyid = a.keyid
LEFT JOIN b ob b.userid = c.userid

LEFT JOIN with multiple row result

I have 3 tables products,colors,assign with this structure:
products:
product_id | default_color
1 | 1
colors
color_id | color_name
1 | Black
2 | Green
3 | Yellow
assign
product_id | color_id
1 | 1
1 | 2
1 | 3
My query returns only first row from "assign" table, I need to have ALL colors assigned for current product.
Here is a query I use:
SELECT * FROM products p
LEFT JOIN assign a ON p.product_id = '1'
LEFT JOIN colors c ON a.color_id = c.color_id
WHERE p.product_id = 1
Try this:
SELECT * FROM products p
LEFT JOIN assign a ON a.product_id = p.product_id
LEFT JOIN colors c ON c.color_id = a.color_id
WHERE p.product_id = 1
The join condition should be made on column names, not on values.
For filtering results, use where.
See here a working sqlFiddle.
For more info on join, see the official docs here.
Instead of p.product_id = '1' use a.product_id
SELECT * FROM products p
LEFT JOIN assign a ON p.product_id = a.product_id
LEFT JOIN colors c ON a.color_id = c.color_id
WHERE p.product_id = 1`
Your SQL statement seems to list all three rows from assign table.
I executed your query:
SELECT * FROM products p
LEFT JOIN assign a ON p.product_id = '1'
LEFT JOIN colors c ON a.color_id = c.color_id
WHERE p.product_id = 1
And I am getting the three rows of assign table.
Here is my SQLFiddle: http://sqlfiddle.com/#!9/50f8bd/1/0
Try this query. Everything is the same as yours except I'm using GROUP_CONCAT() function to concatinate ALL colors for a given product into one field.
SELECT
p.product_id,
GROUP_CONCAT(c.color_name ORDER BY c.color_name ASC SEPARATOR ', ') AS colors
FROM products p
LEFT JOIN assign a ON a.product_id = p.product_id
LEFT JOIN colors c ON c.color_id = a.color_id
WHERE p.product_id = 1
RESULT:
product_id | colors
-----------|-------------
1 | Black, Green, Yellow
DEMO:
http://sqlfiddle.com/#!9/50f8bd/6

Select table with subquery

i try to list out all products with product images, but not sure how to use subquery in this situation. Below is my database structure
products
products_id + product_name +
1 | Apple |
2 | Banana |
products_screenshot
products_id + images +
1 | Apple-1.jpg |
1 | Apple-2.jpg |
1 | Apple-3.jpg |
2 | Banana-1.jpg |
2 | Banana-2.jpg |
2 | Banana-3.jpg |
this is my query:
$sql = "SELECT p.* FROM `products` p ORDER BY p.products_id ASC ";
//LEFT JOIN (SELECT ps.* FROM `products_screenshot` ps WHERE ps.products_id=p.products_id) AS pss ON(p.products_id=pss.products_id)
$query = $db->query($sql);
while ($row = $query->fetch_object()) {
// result
echo $row->products_name.'</br>';
// list all product screenshot related with this
//$row->images
}
With your requirement you can do as below. Then execute the query and loop through.
The
$row->images will be comma seperated and you can split them display them for a product.
$sql = "SELECT p.products_id,p.product_name,group_concat(pi.images) as `images`
FROM `products` p
left join products_screenshot pi on pi.products_id = p.products_id
group by p.products_id
ORDER BY p.products_id ";
If you dont care about products being repeated multiple times in the loop then just use below where for each loop you will get a new row with the product and the related images
$sql = "SELECT p.products_id,p.product_name,pi.images
FROM `products` p
left join products_screenshot pi on pi.products_id = p.products_id
ORDER BY p.products_id ";
What wrong with a simple query like this:
select
p.products_id,
p.product_name,
ps.images
from
products p
join products_screenshot ps
on p.products_id=ps.products_id
where
whateveryouline
order by
1,2
It will get you all the items you need?
Try this query:
select products.product_name, products_screenshot.images from products,products_screenshot where products.products_id = products_screenshot.products_id
SELECT * from products_screenshot as ps where products_id IN (SELECT p.products_id from products as p WHERE p.products_id = ps.products_id )

Categories