SQL Select multiple matching rows - php

I have a SQL database of products from different suppliers, so the same product could appear multiple times with different prices.
Is it possible to select all of the products that have more than 4 prices, so bascially all of the rows which have more than 4 rows with the same ID?

You could add COUNT(*) AS number_of_products to SELECT, GROUP BY product_id, then use HAVING number_of_products > 4.
Note that HAVING is applied on the results (it basically goes through all the results, one by one, and applies the conditions), so it will be slower than WHERE. If you have hundreds of thousands of rows and you need performance, consider pre-counting the products, storing the indexed count value somewhere, then using a simple WHERE instead.

Yes, GROUP on the identificator for your item, and specify the number of prices to count in a HAVING clause, something like this :
SELECT ItemID, COUNT(Price) FROM itemTBL GROUP BY ItemID HAVING COUNT(Price) >= 4
You can then use this to later filter and get more information:
SELECT Item.*, Category.Name, Filter.NumPrices from itemTBL AS Item
INNER JOIN categoryTBL as Category ON Item.CategoryID = Category.CategoryID
INNER JOIN (SELECT ItemID, COUNT(Price) AS NumPrices FROM itemTBL GROUP BY ItemID HAVING COUNT(Price) >= 4) AS Filter on Item.ItemID = Filter.ItemID

This is the perfect thing for a group by:
SELECT ProductID, COUNT(*) AS PriceCount
FROM Product GROUP BY
Product,Price HAVING COUNT(Product) > 4

Related

How do you control which match is chosen when running a `SELECT INNER JOIN WHERE t1.column=t2.column` and there are multiple matches?

I have two MySQL tables:
Products
title id hidden categories
Thing 10 N 12,14,
Stuff 23 N 12,
Object 41 Y 13,14
Images
filename id productid
aca8t.jpg 1 10
ev7ha.jpg 2 10
mscpk.jpg 3 10
asges.jpg 4 23
fcuhg.jpg 5 23
scvfe.jpg 6 41
vf6kl.jpg 7 41
fgszy.jpg 8 41
I build a list of product titles and images using a SELECT statement like this:
SELECT t1.title,
t1.id,
t1.hidden,
t1.categories,
t2.image
FROM products AS t1
INNER JOIN pimage AS t2
WHERE t1.categories LIKE '%$categoryId%'
AND t1.id=t2.productid
AND NOT t1.hidden='Y'
GROUP BY id
ORDER BY id ASC
After running this query, I have a list of non-hidden products in a given category, as well as their IDs and one image. However, the selection of an image appears to be random. Sometimes it's alphabetical, sometimes it's the lowest ID, and sometimes it's neither. However, it's always the same when the filenames for a given productid stay the same.
This is in use on a small website where product managers upload photos of a product and its accessories. The first photo should be used as a thumbnail and visible on the category page. However, a photo of a random accessory is sometimes selected as the thumbnail image, and the product managers have to re-upload the images until the right one gets selected. This process is onerous.
How can I modify the SQL statement so that the first photo (the filename with the lowest images.id) is selected?
Try using a correlated subquery instead of a join/group by:
SELECT p.*,
(SELECT i.image
FROM pimage i
WHERE p.id = i.productid
ORDER BY i.image ASC
LIMIT 1
) as image
FROM products p
WHERE p.categories LIKE '%$categoryId%' AND
p.hidden <> 'Y'
ORDER BY p.id ASC
If this statement were executed on another relational database (other than MySQL/MariaDB), it would throw an error with a message along the lines of "non-aggregates in SELECT list not included in GROUP BY".
But A MySQL specific extension to GROUP BY allows this query to execute in MySQL, but as you've noticed, the values returned for the non-aggregates in the SELECT list are indeterminate, MySQL will return a value from some row.
The normal pattern is to use a MAX() or MIN() aggregate function to "control" which value is returned.
In your case, that would work to return the minimum id value, but getting the other values on that same row is more problematic. If you only need to return a few columns, you can use a correlated subqueries in the SELECT list.
Another approach is to use an inline view and a join operation.
SELECT t1.title
, t1.id
, t1.hidden
, t1.categories
, t2.image
FROM products t1
JOIN ( SELECT n.productid
, MIN(n.id) AS min_id
FROM pimage n
GROUP BY n.productid
) m
ON m.productid = t1.id
JOIN pimage t2
ON t2.id = m.min_id
WHERE t1.categories LIKE '%$categoryId%'
AND t1.hidden='Y'
GROUP BY t1.id
ORDER BY t1.id ASC
This approach is useful when you need to return a additional columns from the row with the "minimum" id. For example, you also needed to include in the SELECT list:
, t2.fee
, t2.fi
, t2.fo
, t2.fum

Mysql query with count on another table

I have two tables, one that has transaction information such as id, status, price and date. I have another table that stores the number of items in that order as individual rows. So, say transaction 2 has 10 items, there will be 10 rows in the second table of different items. What im trying to do is run a query that lists transactions and the number of items sold in that transaction. I imagine this would require a count on the second table, but im not entirely sure of how to do it. This is the basic layout of the database
transaction id, date, price, discount, status
items: id, transaction_id, item_name, email, date_ordered, hash
Thanks in advance for all the help.
Group by the columns in the transaction table you want to select. Then add a count of the items
select t.id, count(i.id) as item_count
from transaction t
left join items i on i.transaction_id = t.id
group by t.id
You can do a left join on both tables like below
select t.*, tab.total_order
from transaction t
left join
(
select transaction_id, count(*) as total_order
from items
group by transaction_id
) tab on t.id = tab.transaction_id

Separate a mysql array into a query

I've a problem with MySQL query. I'm trying select products info over the order products list, but it are selecting only the first record, being that the products list is a array.
Example: being orders.itens = "10,11,12,13", the "IN" selects only the first ID, "10". How I do to select all ID's, something that sounds like implode function in PHP?
SELECT
orders.id,
products.name,
products.price
FROM
orders,
products
WHERE
products.id IN (orders.itens)
Thank you
You want to do a join:
SELECT o.id, p.name, p.price
FROM orders o join
products p
on find_in_set(p.id, o.items) > 0;
Unfortunately, there is no way to optimize this query. You should created an association/junction table, probably called OrderProducts that contains one row for each product in an order.
I guess you need something like this
select CONCAT('"',CONCAT(Replace("10,11,12,13", ',', '","'),'"')) as str
And use this as the value for in clause

mysql searching row's based on AND

Hi guy's I've been trying to figure this out for hours, but I can't seem to wrap my head around it..
Take a look at this sql table..
I'm trying to search for a product_id that exists in all filter_cat_id's, so in this example it would be product_id 30, because it exists with filter_cat_id 1 2 and 3.. Product_id 30 exists in the same filter_cat_id twice, otherwise I'd just count the product id's, then the distinct cat id's and make sure the count's match.
Any ideas? Is this possible in mysql? another option would be to use PHP.
Thanks!
I'm trying to search for a product_id that exists in all filter_cat_id's, so in this example it would be product_id 30, because it exists with filter_cat_id 1 2 and 3.
In general, this can be done by grouping by product_id and using HAVING COUNT(product_id) >= x – where x is the number of categories,
SELECT product_id FROM table GROUP BY product_id HAVING COUNT(product_id) >= 3
If you don’t know the number of categories upfront (so that you can insert the actual number into the query), you can get that value with a subquery,
SELECT product_id FROM table GROUP BY product_id
HAVING COUNT(product_id) >= (SELECT COUNT(DISTINCT category_id) FROM table)
Edit: OK, so apparently the category_ids to search for come from some kind of search form/filter mechanism.
In that case, the filtering of items has to be added – and the number to compare to must be embedded implicitly, but that should be no problem.
SELECT product_id FROM table
WHERE category_id IN(1,2,3)
GROUP BY product_id
HAVING COUNT(product_id) >= 3
SELECT
product_id, count(i.product_id) as t
FROM
(SELECT
*
FROM
tablename
GROUP BY product_id , filter_cat_id) as i
GROUP BY product_id
HAVING t = 3
This should be smart enough to determine the number of distinct categories, and select a product_id that has that number of distinct categories.
SELECT product_id
FROM
(SELECT DISTINCT product_id, filter_cat_id
FROM test.play) a
GROUP BY product_id
HAVING count(product_id) = (SELECT count(DISTINCT filter_cat_id) FROM test.play)
;
Test Data:
Query Result:
30
40

Counting distinct items within a category on SQL

I need to compose a SQL statement as follows:
I have a table with many items, each item having a category. In total there are 3 categories.
I need to select the DISTINCT categories and then order them by number of items within each category.
Would this be a good way? Or too slow?
SELECT DISTINCT category, count(*) AS counter
FROM item_descr
GROUP BY category
ORDER BY counter DESC
The DISTINCT is not needed since you are using GROUP BY category:
SELECT category, count(*) AS counter
FROM item_descr
GROUP BY category
ORDER BY counter DESC
The GROUP BY is doing what you want. DISTINCT is redundant.
It is very important to have an index on category if you want good performance especially on larger tables.

Categories