I've got two databases fruit and fruit-prices (for arguement's sake).
In fruit there are two columns id | name
Fruit table
id | name
1 | Apple
2 | Banana
In fruit_prices there are three columns id | fruit_id | price where fruit_id is a FOREIGN KEY reference.
id | fruit_id | price
1 | 1 | £2.00
2 | 2 | £3.00
Now I have a PHP function that will print out a table row and cells with the information from the database but currently if I am printing two fruits out my table looks like this.
Name | Price
1 | £2.00
2 | £3.00
PHP Code:
$query = mysqli_query($conn, "SELECT * FROM fruits ");
while($row = mysqli_fetch_assoc($query)) {
$name = $row['fruit_id']; //for comma separation
$price = $row['price'];
echo "<tr>";
echo "<td>" .$name. "</td>" .
"<td>" .$price. "</td>";
echo "</tr>";
}
Is there an elegant way I can retrieve the name of the fruit (i.e. 1 = Apple, 2 = Banana). Rather than using the unique ID of each fruit.
So then my table will look like this
Name | Price
Apple | £2.00
...
I hope this makes sense? I'm new to RD concepts. This is a very simple example and does not reflect my entire project so I'm just wondering if this is achievable?
This can be done by joining both the tables.Change your sql query with below one.I think it will solve your problem.
"SELECT fruit.name,fruit_prices.price FROM fruit,fruit_prices WHERE fruit_prices.fruit_id = fruit.id";
You would want to use a join and specify the columns you would like to select.
SELECT f.name, fp.price FROM fruit as f
JOIN fruit-prices as fp ON f.id=fp.fruit_id;
It is achievable using JOIN:
SELECT * FROM fruits a JOIN fruits-prices b ON b.fruit_id = a.id
For more friendly column names you can add column aliases and use them further.
You say they are in two databases, but I think it might just be two tables. If so:
select * from fruit f
left outer join fruit-prices fp
on f.id = fp.fruit_id
The left outer join ensures that if a fruit doesn't have a price it will be returned will null as the price. If you don't want that replace it with an inner join.
Use of JOIN does what you need.
"SELECT `p`.`price`, `f`.`name` FROM `fruit_prices` `p`
JOIN `fruits` `f` ON `f`.`id` = `p`.`fruit_id`"
Be wary - use of SELECT * here will lead to an error, as both tables have an id field, and the query will break.
You need a join between the tables,
SELECT f.name, fp.price
FROM fruit f
INNER JOIN fruit_price fp ON f.id = fp.fruit_id
Well, you need to take a look to SQL Joins
query = mysqli_query($conn, "SELECT FRUIT.name,FRUIT_PRICES.price FROM fruits INNER JOIN FRUIT_PRICES ON FRUIT.id = FRUIT_PRICES.fruit.id");
while($row = mysqli_fetch_assoc($query)) {
$name = $row['name']; //for comma separation
$price = $row['price'];
echo "<tr>";
echo "<td>" .$name. "</td>" .
"<td>" .$price. "</td>";
echo "</tr>";
}
What I wrote means : "Select FRUIT.Name,FRUIT_PRICES.price in FRUIT AND FRUIT_PRICES, considering that FRUITS.id is related to FRUIT_PRICES.id_fruit"
Suggestion : You can have a single table viz fruits with 3 columns id, fruit_name, price.
for your table structure :
SELECT fruits.id, name, price
FROM fruits, fruit-prices
WHERE fruit_id=fruits.id;
Related
How can I combine 3 tables in a INNER JOIN?
The end result I am after is getting a list of CATEGORIES belonging to a PRODUCT - including the CATEGORY'S PARENT ID CATEGORY value (ie: Sneakers and Nike).
The CATEGORIES table and PRODUCTS table are joined in the PRODUCTS & CATEGORIES table. A product can belong to many categories and a category can have many products.
Here's more-or-less the setup I have in my database...
CATEGORIES TABLE:
CAT ID | PARENT ID | CATEGORY
1 | 0 | Sneakers
2 | 1 | Nike
3 | 2 | Jordan
PRODUCTS TABLE:
PROD ID
1
2
3
PRODUCTS & CATEGORIES TABLE:
CAT ID | PROD ID
1 | 0
1 | 1
2 | 3
I am running these queries and I am getting some results, but at the moment I am running 2 separate queries...
$q1 = "SELECT prodid, GROUP_CONCAT(catid SEPARATOR ' // ') as catid FROM products_categories group by prodid order by prodid";
$result1 = $conn->query($q1);
if ($result1->num_rows > 0) {
while($prods = $result1->fetch_assoc()) {
echo "Product Id:" . $prods["prodid"] . " ––> " . "Categories Id:" . $prods["catid"];
}
} else {
echo "0 results";
}
$q2 =
" SELECT `ID`.`category` as `IDName`, `LABEL`.`category` as `LabelName`, `LABEL`.`catid` as `LabelId`
FROM `categories` as ID
INNER JOIN `categories` as LABEL
ON `ID`.`catid` = `LABEL`.`parentid`";
$result2 = $conn->query($q2);
if ($result2->num_rows > 0) {
while($prods = $result2->fetch_assoc()) {
echo "ID# " . $prods["LabelId"] . " is called: ". $prods["LabelName"] . "<br>";
}
} else {
echo "0 results";
}
$conn->close();
I have tried adding another INNER JOIN with no luck in the results.
The end result I am after would be: PROD ID #0 belongs to Sneakers, Nike, Jordan.
Anyone can point me in the right direction?
Thank you so much,
Sergio
UPDATE - 10/11/16
The Query:
$q =
" SELECT PC.productid as productid, concat_WS('~',C1.category, C2.category, C3.category) as breadcrumb
FROM xcart_categories as C1
INNER JOIN xcart_products_categories as PC
ON C1.categoryid = PC.categoryid
LEFT JOIN xcart_categories as C2
ON C1.categoryid = C2.parentid
AND C1.parentid = 0
LEFT JOIN xcart_categories as C3
ON C2.categoryid = C3.parentid
WHERE C1.parentid = 0
";
The Fetch:
$result = $conn->query($q);
if ($result->num_rows > 0) {
while($prods = $result->fetch_assoc()) {
echo $prods['productid'] . ' Belongs in these categories: ' . $prods['breadcrumb'] . '<br>';
}
} else {
echo "0 results";
}
This assumes 3 levels of hierarchy no more and a separate join is needed to "put each record on the same line" so they can be combined into a single value result. I thin you were trying to use Group_concat but I can't see how that's going to work as you don't have a way to walk the hierarchy.
SELECT PC.ProductID, concat_WS('-',C1.Category, C2.Category, C3.Category) as breadcrumb
FROM categories C1
INNER JOIN ProductsCategories PC
on C1.categoryID = PC.CategoryID
LEFT JOIN categories C2
on c1.CategoryID = C2.ParentID
and C1.parentID = 0
LEFT Join Categories C3
on C2.CategoryID = C3.ParentID
WHERE C1.ParentID = 0
Working SQL Fiddle example ( this only supports 3 levels deep, but could be altered with added left joins to support a max level but not a undetermined max level..)
I see you're trying to use group concat to bring all the rows for the same product category.productID of 0 to the same line
However as 0 references catID of 1 it would only return "sneakers" on the inner join. You would need to traverse the tree (all of it) somehow, thus the above, or you have to take multiple trips to the db or use some sort of dynamic SQL or method mentioned in link in comments.
This would be fairly simple in SQL Server, Oracle or other Enterprise RDBMS systems, however without recursive queries or engine specific hierarchy queries, this is no easy feat in MySQL on a single trip.
Maybe I'm missing something so it may help to see the actual expected results for your sample data. What is the record set look like that you want back?
I have two tables:
1 - hotels[id,name,extras] ( name of hotels with column extras which I've select for each one)
2 - extras[id,name] ( here's the extras of hotel like wifi,tv,swim... )
$name = $_GET['name'];
$hotels_q = mysql_query("SELECT * FROM `hotels` WHERE `name`='$name'") or die (mysql_error());
$hotels_row = mysql_fetch_array($hotels_q);
$id = $hotels_row['id'];
$extras = explode(",", $hotels_row['extras']);
$ekstras_q = mysql_query("SELECT * FROM `extras` order by id") or die(mysql_error());
While($ekstras_row = mysql_fetch_array($ekstri_q)){
$eid = $ekstras_row['id'];
$ename = $ekstri_row ['name'];
echo '<ul><li><input type="checkbox" name="extras['.$eid.'][]" value="'.$ename.'"';
if (in_array($eid, $ekstras)) echo'checked';
echo'/>'.$ename.'</li></ul>';
Problem is here extras_q displays all entries with checked ones from table, but I want only to display only checked items!
Since you're storing your extra IDs in one column as a comma separated string, I think you should be able to do this by not exploding that value, and then using the CSV string as an IN criteria in your second query.
//...
$extras = $hotels_row['extras']; // don't explode
// Use IN with the $extras CSV here
$ekstras_q = mysql_query("SELECT * FROM `extras`
WHERE id IN ($extras) ORDER BY id") or die(mysql_error());
If you are able to modify your database, you can instead create a many-to-many relationship between hotels and extras by adding a table to join those two items together instead of using a CSV column as you currently are. This can make it easier to write queries to select the related records.
If you add a third table hotel_extras with columns hotel_id and extra_id, you can insert one row for each extra that each hotel has. For example, if the hotel with id 1 has several different extras, its entries in that table would look like this:
table: hotel_extras
_______________________
| hotel_id | extra_id |
=======================
| 1 | 1 |
| 1 | 3 |
| 1 | 4 |
-----------------------
Here is an example using PDO of how you could query data from a setup like that:
$sql = "SELECT e.id, e.name
FROM hotels h
INNER JOIN hotel_extras he ON h.id = he.hotel_id
INNER JOIN extras e ON he.extra_id = e.id
WHERE h.`name` = ?";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(1, $_GET['name']);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$eid = $row['id'];
$ename = $row['name'];
'<li><input type="checkbox" name="extras['.$eid.'][]" value="'.$ename.'" checked/>'.$ename.'</li>';
}
I've tried to find a way to select data from two tables within the same query as follows:
Suppose I have this as table1
id | item | qty
1 | 1bb1 | 12
2 | 1cc1 | 10
and as table2
id | item | qty
6 | 1bb1 | 12
7 | 1vv1 | 4
And I have an imported file which contains data item as $sheetData[$i]['A'] from an excel sheet that I need to use it to find out if BOTH tables have this item or not.
My code as follows :
$query1="SELECT * FROM table1.item,table2.item WHERE item ='".$sheetData[$i]['A']."'";
$result1= mysql_query($query1);
if(mysql_num_rows($result1)>0){
echo "This Item Found in Both Tables";
echo $sheetData[$i]['A'];
echo "<br />";
}
else{
echo "Item Could Not Be Found in both tables";
echo $sheetData[$i]['A'];
}
Its basically I want to find out if the imported item found in both tables or not. I hope this makes sense for you!
Any help would be really appreciated
Compiler can't decide which item needs to compare. item from table1 or item from table2
So write query as:
SELECT A.* , B.*
FROM table1 A, table2 B
WHERE A.item = B.item AND
A.item = '".$sheetData[$i]['A']."'
Try with -
"SELECT t1.id, t1.item, t1.qty, t2.id id_2, t2.qty qty_2 FROM table1 t1
INNER JOIN table2 t2 ON t2.item = t1.item
WHERE table1.item ='".$sheetData[$i]['A']."'"
Try to avoid using mysql, it is deprecated now. mysqli/PDO instead.
Try something like this:
SELECT COUNT(*)
FROM (
SELECT DISTINCT 1
FROM table1
WHERE item = ?
UNION ALL
SELECT DISTINCT 1
FROM table2
WHERE item = ?) AS t
This will return 2 if the item exists in both tables, 1 if it exists in only 1 table and 0 if the item doesn't exists in any of the two tables.
I need to make a list printing all the clients ordered by the gym name, but it's repeating the gym name the same number of gym's clients. If gym1 have 4 clients, the echo is printed 4 times.
The tables/columns are:
members (id, gym, name, etc...)
and
gym (gymID, gym_name, etc...).
member.gym is to know to what gym the client belongs (gym.gymID)
if ($stmt = $mysqli->prepare(" SELECT DISTINCT g.*, m.*
FROM gym g
INNER JOIN members m ON m.gym = g.gymID")) {
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_array()) {
echo 'Sport center: ' . $row['gym_name'] . '<br>';
// here print the gym's clients list
}
}
DISTINCT is not working... What is the problem??
That's the normal behavior.
Example.
Consider the following tables
Table "gym"
-----------
gym_id | gym_name
-------+----------
1 | Gym A
2 | Gym B
Table "members"
---------------
member_id | gym_id | member_name
----------+--------+------------
1 | 1 | Bob
2 | 1 | Jeff
And now, execute this query:
select g.gym_id, g.gim_name, m.member_id, m.member_name
from gym as g
inner join members as m on g.gym_id = m.gym_id;
Result:
gym_id | gym_name | member_id | member_name
-------+----------+-----------+-------------
1 | Gym A | 1 | Bob
1 | Gym B | 2 | Jeff
That happens because each row in the gym table is matched with a row in the members name. Even if you use select distinct, the result would be the same, because every row is different.
I think what you want is an output like this:
Gym A
Bob
Jeff
Although that can be done directly in SQL, it's easier to handle it directly with PHP, because doing it in SQL would be a real pain in the neck would require writing quite a complex query. I'm not quite good with PHP, but it could be something like this:
/*
You don't need "DISTINCT", but you need "ORDER BY" to make this work
*/
if ($stmt = $mysqli->prepare(" SELECT g.*, m.*
FROM gym g
INNER JOIN members m ON m.gym = g.gymID
ORDER BY g.gymID")) {
$stmt->execute();
$result = $stmt->get_result();
$gym = "";
while ($row = $result->fetch_array()) {
if($row['gym_name'] != $gym)
echo 'Sport center: ' . $row['gym_name'] . '<br>';
echo ' Member: ' . $row['member_name'] . '<br>';
$gym = $row['gym_name'];
}
}
First, drop the DISTINCT and slap in an ORDER BY:
SELECT g.*, m.*
FROM gym g
INNER JOIN members m ON m.gym = g.gymID
ORDER BY g.name;
Now, adjust your PHP code to only print the gym name if it's different from the last gym you printed.
SELECT g.*, m.*
FROM gym g
INNER JOIN members m ON m.gym = g.gymID
ORDER BY g.name,gym_clients;
I dont know the name of Gym Name column & gym Client Column So, Please Change the name if they are not correctly spelled.
I hope this will work for you
This should work:
SELECT *
FROM gym g
LEFT JOIN members m
ON g.gym_ID=m.gym_id
GROUP BY g.gym_name
I`ve a problem with grouping and displaying results from two tables in MySQL db.
I`m trying to make a shopping cart, and I have realised a shop menu which contains products categories and via jquery when category is clicked, menu expands and show products from that category.
Example of categories table:
+------------+
| ID | NAME |
+------------+
| 1 | name1 |
| 2 | name2 |
| 3 | name3 |
| 4 | name4 |
+------------+
Example of products table:
+------------------------------------------------------------------------+
| ID | PR_CODE | NAME | DIMENSIONS | COLORS | OFFER | PRICE | CATEGORY |
+------------------------------------------------------------------------+
| 1 | pr_code1 | prod1 | 40 x 40 | blue | 1 | 11.00 | 1 |
| 2 | pr_code2 | prod2 | 120 x 120 | white | 1 | 12.00 | 1 |
| 3 | pr_code3 | prod3 | 60 x 120 | yellow | 0 | 13.00 | 2 |
| 4 | pr_code4 | prod4 | 40 x 60 | orange | 0 | 14.00 | 3 |
+------------------------------------------------------------------------+
Category row in products table telling which category product belongs.
Code for menu:
<div class="shopMenu">
<ul>
<?php
$sql = "SELECT categories.*, products.id as prodId, products.name as prodName FROM `categories` LEFT JOIN `products` ON categories.id = products.category ORDER BY categories.id DESC";
$query = execute_select($sql);
foreach($query as $row) {
$id = $row['id'];
$name = $row['name'];
$prodId = $row['prodId'];
$prodName = $row['prodName'];
echo '<li>' . $name . '
<ul>
<li>' . $prodName . '</li>
</ul>
</li>'; }
?>
</ul>
</div>
This code works, but works wrong. If I put sql query as:
$sql = "SELECT categories.*, products.id as prodId, products.name as prodName FROM `categories` LEFT JOIN `products` ON categories.id = products.category ORDER BY categories.id DESC";
Result is: all categories are listed but categories which contains more products are repeated in main menu as many times as there are products in this category.
If I put sql query as:
$sql = "SELECT categories.*, products.id as prodId, products.name as prodName FROM `categories` LEFT JOIN `products` ON categories.id = products.category GROUP BY categories.id ORDER BY categories.id DESC";
Result is: all categories are listed once, but only one of products from chosen category is listed, missing other products.
Can somebody help with this query?
There is basically two ways of doing what you want, both of them have been explained in the other response and in the comments. I will try to expand a little about them in this answer.
One query
You retrieve all the data in one query and then use PHP to do some transformation in order to show them in the appropriate way.
There's two approaches to do that. You can modify the data first and then loop on them to display the menu or you can do everything in just one loop.
Two steps variant
First, we create an array containing the data in a more "usable" way for us, and then we display the content of this new array :
$sql = "SELECT categories.id as catid, categories.name as catname, products.id as prodId, products.name as prodName
FROM `categories`
INNER JOIN `products` ON categories.id = products.category
ORDER BY categories.id DESC";
$result = execute_select($sql);
$categories = array();
foreach($query as $row) {
if( ! isset($categories[$row['catid']])) {
$categories[$row['catid']] = array(
'id' => $row['catid'],
'name' => $row['catname'],
'products' => array(),
);
}
$categories[$row['catid']]['products'][] = array(
'id' => $row['prodId'],
'name' => $row['prodName'],
);
}
foreach($categories as $cat) {
echo '<li>' . $cat['name'] . '<ul>';
foreach($cat['products'] as $prod) {
echo '<li>' . $prod['name'] . '</li>';
}
echo '</ul></li>';
}
One step variant
We store the current category, and when the category changes, we close the current list and open a new one :
$sql = "SELECT categories.id as catid, categories.name as catname, products.id as prodId, products.name as prodName
FROM `categories`
INNER JOIN `products` ON categories.id = products.category
ORDER BY categories.id DESC";
$result = execute_select($sql);
$actualcategory = null;
foreach($query as $row) {
if($actualcategory != $row['catid']) {
echo '<li>' . $row['catname'] . '<ul>';
}
echo '<li>' . $row['prodName'] . '</li>';
if($actualcategory != $row['catid']) {
echo '</ul></li>';
$actualcategory = $row['catid'];
}
}
n+1 query
In this solution, we retrieve the list of categories, and then, for each one, retrieves the list of products :
$sql = "SELECT categories.id, categories.name
FROM `categories`
ORDER BY categories.id DESC";
$categories = execute_select($sql);
foreach($categories as $cat) {
echo '<li>' . $cat['name'] . '<ul>';
$sql2 = "SELECT products.id, products.name
FROM `products`
WHERE `products`.category = ".$cat['id'];
$products = execute_select($sql2);
foreach($products as $prod) {
echo '<li>' . $prod['name'] . '</li>';
}
echo '</ul></li>';
}
Dry coding warning
I dry coded the preceding piece of PHP code, I'm not even sure I didn't made some kind of silly mistakes. It is possible you will have to adapt them to your needs. If something is wrong, please point it out in the comments, I will fix it ASAP :)
Conclusion
The first two possibilities executes only one query and then parse the results to display meaningful information. The code is, in my opinion, fairly hard to understand and error prone.
The last possibility is much more clearer and, I think, easier to modify and extend.
From a performance point of view, we have only one query in the first two versions, but we retrieves much more data and a join in necessary. I think there's no easy answer about which solution is best, it will greatly depends on the number of categories and products for each of them. I think the best to do is to test each of the solution on various data set to determine the quicker one.
If I would have to develop this kind of menu, I will personally use the n+1 query approach. Even if the performance are slightly off (which I'm not sure), the solution is so much clearer that it compensates the weaknesses.
Disclaimer
Kudos to every other poster on this question, I didn't provide a "new" answer, I just put the already provided one in PHP code. Hope this will help !
You want two queries.
First get a list of categories, and loop through them. Then within each category do a second query and get the products.
(Yes, it's technically possible to get all the data in one query and check if the category was already output, but I recommend against it.)
SELECT
*, products.id as prodId, products.name as prodName
FROM
products
LEFT JOIN
categories ON categories.id = products.category
You want products table so take it FROM products not FROM categories
The SQL Grouping operator roughly works like this: You group by an attribute, and you (under the hood) make groups of rows which have the same value in that attribute. The query result will only contain the top of each those groups. You can use aggregate functions on each of those groups but that's about it.
You have two options:
(a) Either perform separate queries for each category (as previously suggested) or
(b) Using your first query, order by category and in your loop, while the current row is in the same category as the previous row then add it to your current list. When you reach a result which belongs to another category than the previous one then close the current list (echo </ul>;) and start a new one