I have two tables: Stores and Items. The relationship is: Stores 1---* Items
In PHP/MySQL what would be the best (fastest/simplest) way to check if a particular item belongs to a particular store.
In other words given for example:
$store_id = 1;
$item_id = 12;
I want to check if item 12 belongs to store 1 (and not some other store).
I usually do a select on Items matching both the store_id and item_id and limit the results to 1. Then check how many rows (0 or 1) were returned with mysql_num_rows. Is there a better way?
Update:
Both tables have an "id" column. The Items table has a "store_id" column.
SELECT COUNT(*) AS count
FROM stores JOIN items USING(store_id)
WHERE item_id = 12
AND store_id = 1
Then you'd get the results, and check of count > 0 or not. However, if I'm getting your DB design right, then you have a very messed up database.
From what you describe, an item can only exist in one store. So my guess of the general layout here would be like this:
STORE ITEM
----- ----
store_id ---| item_id
store_name |--- store_id
... item_name
...
Is this correct? An item can never exist except in the one store? So if it's a screwdriver, every store would need a different item_id to hold it?
A better design would be:
STORE STORE_ITEM ITEM
----- ---------- ----
store_id ------- store_id |------ item_id
store_name item_id ---| item_name
... ...
With a query of
SELECT COUNT(*)
FROM store JOIN store_item USING(store_id)
JOIN item USING(item_id)
WHERE store_id = 1
AND item_id = 12
Both tables have an id, Items has a store_id
SELECT COUNT(*) FROM Items WHERE store_id = $store_id AND id = $item_id
$r = mysql_query("select NULL from Item where storeID = '$store_id' and ItemID = '$item_id'");
if (mysql_fetch_row($r))
{
it belongs...
}
For fun, I'll throw in a one-liner check:
// if item belongs to store
if (current(mysql_fetch_array(mysql_query("SELECT COUNT(*) FROM Items WHERE store_id = $store_id AND id = $item_id"), MYSQL_NUM)))) {
// it belongs!
}
Related
I have 2 tables - products and productimages.
product has unique id and title.
productimages has productid and imageurl. these are examples of my tables:
products:
|id|title |
_____________
|1 |Laptop |
|2 |Speakers |
productimages:
|productid|imageurl|
___________________
| 1 |lap1.png|
| 1 |lap2.png|
| 1 |lap3.png|
| 2 |spe1.png|
Right now I have a nested loop in PHP.
loop through all rows of -> select * from products
and for every product inside the loop -> select * from productimages where productid = id which is basically another loop inside the first loop.
and then I take all productimages into array and decode to JSON [title,photos].
Now imagine you have 2 million rows in productimages, the query times are too high, is there any way to make it more efficient?
$query = "SELECT * FROM products ORDER BY id LIMIT 10;
$result = mysqli_query($con,$query);
if(mysqli_num_rows($result)>0)
{
$response = array();
while($row = mysqli_fetch_assoc($result)) {
$photos = array();
$id = $row["id"];
$title = $row["title"];
$queryp = "select imageurl from productimages where productid= '".$id."';";
$resultp = mysqli_query($con,$queryp);
if(mysqli_num_rows($resultp)>0)
{
while($row2 = mysqli_fetch_assoc($resultp)) {
$photourl = $row2["imageurl"];
array_push($photos,$photourl);
}
}
}
}
Some betterment for you could be:
1) Don't use select *. Use column names instead. e.g. select products.id, products.title, productimages.imageurl
2) Use JOIN instead of nested loop
So, you can try querying data like:
select products.id, products.title, productimages.imageurl
from products
join productimages on products.id = productimages.productid
ORDER BY products.id LIMIT 10
This case is not uncommon - you have two tables in a one to many relationship.
You should never nest an SQL call in a loop if you can possibly avoid it but there is a decision to be made about one SQL call or two.
A single SQL call could be:
SELECT id, title, imageURL
FROM products LEFT JOIN productImages ON id=productid
The disadvantage of this is that you are extracting the title several times for each product and this is wasteful.
Using two SQL statements you can download the titles once for each product:
SELECT id, title FROM products
The results of this query can be stored in an associative array - so that you can look up the title for each id.
The second query is:
SELECT productid, imageURL FROM productImages ORDER BY productid, imageURL
You can loop through the results of this query, spitting out the title as you go.
To save the images with product you can add a column imageurl in the products table.collect the image names with , and insert that image name string to the products table.
your table looks like below.
+--------------+--------------+---------------------------+
| id | title | imageurl |
+--------------+--------------+---------------------------+
| 1 | Laptop | lap1.png,lap2.png,lap3.png|
+--------------+--------------+---------------------------+
| 2 | Speakers | spe1.png |
Hope you understood what i explain.
I am using MySQL and have a table called sales. Its primary key is sales_id.
-------------------------------------
sales_id | invoice_id |
-------------------------------------
1 | 147
2 | 148
3 | 150
For sales_id 3 the invoice_id is supposed to be 149. I want to know which numbers are missing from invoice_id. I start invoice_id at 147 and end invoice_id at 4497. The invoice_id had no relation with sales_id.
Is it possible to know which numbers are missing from invoice_id, using a query?
I presume that you have a table of invoice - INVOICES. You may try:
SELECT invoice_id FROM INVOICES invoice
WHERE NOT EXISTS (SELECT * FROM SALES s WHERE invoice.invoice_id = s.invoice_id)
EDIT: If you don't have the INVOICES table, you may need to take all the invoices out before checking if there's any gap.
SELECT DISTINCT invoice_id FROM SALES ORDER BY invoice_id ASC
SELECT MAX(invoice_id) FROM SALES
then, by php:
for ($i = 1; $i < $max_invoice_id; $i++)
{
if (!in_array($i, $all_invoice_id))
{
$gapId[] = $i;
}
}
If you're just trying to find numbers out of the sequence in the example you've provided you could use something like this:
SELECT *
FROM `sales`
WHERE (
`invoice_id` - 147 - `sales_id`
) = 0
If you can provide a bigger sample set we might be able to tool a better answer for you.
set #suggest_invoice:=147;
select
sales_id,
invoice_id,
#suggest_invoice:=#suggest_invoice+1,
if(invoice_id=#suggest_invoice, 0, 1) as missing_invoice
from sales
order by sales_id;
I guess you almost getting all the records except the first two with missing_invoice=1
As you are searching for invoice_id then make sure you have an index on that column. otherwise queries will be slow.
You can try the following code
$inv_ids=range(147,4497);
$str_inv_ids=implode(",",$inv_ids);
$query="SELECT DISTINCT invoice_id FROM sales WHERE invoice_id IN ($str_inv_ids)";
$result=mysql_query($query);
while ($row = mysql_fetch_assoc($result)) {
$inv_ids_db[]=$row['invoice_id'];
}
// It gives invoice Ids that are in $inv_ids but not in $inv_ids_db
$missing= array_diff($inv_ids,$inv_ids_db);
print_r($missing);
You can find gaps in a MySQL sequence using this query:
SELECT invoice_id+1
FROM sales s
WHERE NOT EXISTS (
SELECT NULL
FROM sales t
WHERE s.invoice_id = t.invoice_id+1
)
HAVING `invoice_id+1` < (SELECT MAX(invoice_id) FROM sales)
ORDER BY invoice_id
This will return all invoice_id missing from the sequence, regardless of sales_id.
I have a field in my database that is an array ie: id_ingredients = "1,8,3,9,5,2,7,4"
I want to compare a variable that is also an array to give a result if any of the variable ids exist in the field ids.
I am trying to check to see if a product's ingredients contain any of the ingredients in the variable. If someone is allergic to nuts for example i want to selet all products that contain nuts of any kind. So i query my ingredients to get the id of any ingredient that has the word "nut" in its name. Then i need to get the products with any of the ingredient ids.
This is what I have...
$alg = $_POST['alg'];
mysql_select_db($database, $Products);
$query_availIngredients = "SELECT * FROM ingredients WHERE ingredient LIKE '%$alg%' ";
$availIngredients = mysql_query($query_availIngredients, $Products) or die(mysql_error());
$row_availIngredients = mysql_fetch_assoc($availIngredients);
$ingarray = array();
do{
$ingarray[] = $row_availIngredients['id'];
} while ($row_availIngredients = mysql_fetch_assoc($availIngredients));
$alg = implode (',', $ingarray);
mysql_select_db($database, $Products);
$query_Products = "SELECT *FROM products WHERE
id_ingredients LIKE '%$alg%' " ;
$Products = mysql_query($query_Products, $Products) or die(mysql_error());
$row_Products = mysql_fetch_assoc($Products);
Thank you in advance for your help.
Placing an array of IDs in a single database field isn't really a good idea and you lose some of the power a relational database gives you by designing your database this way.
Rather than storing an array of ingredient IDs in your product's table I would create a third table.
An example table schema would be like this:
Products
id
productName
productDescription
Ingredients
id
ingredientName
ProductIngredients
id
id_Products
id_Ingredients
Some sample data might look like:
Products
id productName productDescription
1 Peanutbutter And Jelly Sandwich Best sandwich ever
Ingredients
id ingredientName
1 Peanutbutter
2 Jelly
3 Special sauce
4 Bread
ProductIngredients
id id_Products id_Ingredients
1 1 1
2 1 2
3 1 4
You could then get a list of IDs of ingredients containing the word 'nut' like this:
SELECT id FROM Ingredients WHERE ingredientName LIKE '%nut%'
And a list of products containing ingredients which contain the word 'nuts' like this:
SELECT
Products.productName
FROM
Products
LEFT JOIN ProductIngredients ON ProductIngredients.id_Products = Products.id
LEFT JOIN Ingredients ON Ingredients.id = ProductIngredients.id_Ingredients
WHERE
Ingredients.ingredientName LIKE '%nut%'
You could get a list of ingredients for a product like this:
SELECT
Ingredients.ingredientName
FROM
Ingredients
LEFT JOIN ProductIngredients ON ProductIngredients.id_Ingredients = Ingredients.id
WHERE
ProductIngredients.id_Products = 1
This would give you a list such as this:
Peanutbutter
Jelly
Bread
Edit
This is is called a many-to-many relationship.
I have a table that looks like this
id | itemID | catID | Title
----------------------------------------------------------------------------
0 3 4 Hello
1 3 6 Hello
2 4 4 Yo
3 4 8 Yo
4 5 2 Hi
5 1 3 What
I want to do a MySQL PHP Select that only gets one occurrence of the itemID. As you can see they are the same item, just in different categories.
This is what I tried
SELECT * FROM Table GROUP BY itemID
That didn't seem to work, it still just shows duplicates.
Is this what you are looking for? http://www.sqlfiddle.com/#!2/5ba87/1
select itemID, Title from test group by itemID;
As far as MySQL is concerned, the data is all unique, since you want all of the columns. You have to be more specific.
Do you just want the itemID (or other column)? Then say so:
select [column] from Table GROUP BY itemID
Do you want the last entry of a particular item ID? Then say that:
select * from Table where itemID = 1 ORDER BY id DESC
Or the first one?
select * from Table where itemID = 1 ORDER BY id
If none of these are what you want, then you probably need to restructure your tables. It looks like you want different categories for your items. If so, then you'll want to split them out into a new join table, because you have a many-to-many relationship between Items and Categories. I recommend reading up on database normalization, so you're not duplicating data (such as you are with the titles).
If you want everything for the distinct itemIDs, you could certainly take a long route by doing one selection of all of the distinct itemIDs, then doing a series of selections based on the first query's results.
select distinct(`itemID`) from Table
Then in your PHP code, do something like this:
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
$itemID = $row['itemID'];
$sql2 ="SELECT * FROM Table WHERE 1 and `itemID`=\"$itemID\" limit 1";
$result2 = #mysql_query($sql2, $connection);
while ($row2 = mysql_fetch_array($result2))
{
$id = $row2['id'];
$itemID = $row2['itemID'];
$catID = $row2['catID'];
$Title = $row2['Title'];
}
}
This is what my customers_basket table looks like:
customers_id | products_id | basket_quantity
3 | 56:3121fefbe6043d6fc12e3b3de2c8fc38 | 3
3 | 56:fb4c9278fcfe6225b58c06711a7e62ef | 1
3 | 56:8e334fce09556108f5416e27154b6c27 | 1
3 | 52:f3b9f38e4ddd18035bc04cd264b0f052 | 1
This is the query I'm using:
$products_in_cart_query = "SELECT products_id FROM customers_basket WHERE customers_id = " . $_SESSION['customer_id'] ."";
$products_in_cart = $db->Execute($products_in_cart_query);
$products_in_cart_model = $products_in_cart->fields['products_id'];
$products_in_cart_model = substr($products_in_cart_model, 0, strpos($products_in_cart_model, ":"));
The end result I get is 56,56,56,52
First of all, how do I use the first line's quantity field? I'd need to list that products_id 3 times since quantity is 3. Therefore, the end result needs to be: 56,56,56,56,56,52
or, for easier understanding (56,56,56),56,56,52
And second, how do I count how many same values I have? In this case, I have 5x56 and 1x52. I need to use those counts in my further calculation.
EDIT: further calculations explained
I need to know how many of each product_id I have and then run something like this:
foreach(product_id) {
$shipping_cost += FIXED_VALUE * basket_qty;
}
To get the basket quantity, you have to select it. It would be best if the first portion of the product ID was stored in a separate column, rather than having to do messy operations like substringing.
Query 1: 2-character codes and corresponding quantities
SELECT SUBSTR(products_id, 1, 2) AS product_code, basket_quantity
FROM Customers_Basket
WHERE customers_id = 3;
Query 2: 2-character codes and summed quantities
SELECT product_code, SUM(basket_quantity) AS total_quantity
FROM (SELECT SUBSTR(products_id, 1, 2) AS product_code, basket_quantity
FROM Customers_Basket
WHERE customers_id = 3
)
GROUP BY product_code;
If you really, really, really desperately want 3 rows of data for the product ID 56:3121fefbe6043d6fc12e3b3de2c8fc38, then you have to know ways to generate rows. They're truly painful in the absence of convenient SQL support (so much so, that you'd do better to select a row in PHP with the quantity and then generate the appropriate number of rows in your array in the client-side (PHP) code). I'm going to assume that some variation on these queries will get you the information you want.