php


mysql select where limit, join where


I have following two MySQL tables
products (product_id, name, category)
products_sizes (product_id, size)
every product can have multiple sizes
I need to make a query that
selects a product based on category and size (if size is set) - e.g. category = 'shoes' and size = '10'
it must still return all sizes for the product, but only if the product has the specific size as on of its sizes
it must at the same time limit the results of products to a certain number with an offset
What I have now the query below. I works but doesn't constrain by category and only returns the one size specified (here '10') - I need all sizes, but only for the products that have '10' among its sizes...
SELECT products.*
, products_sizes.*
FROM (
SELECT *
FROM products
LIMIT $limit OFFSET $offset
) AS products
LEFT JOIN products_sizes
ON products.products_id = products_sizes.products_id
WHERE products_sizes.size = 10
... and if I add WHERE category = 'something' query returns nothing...
SELECT products.*
, products_sizes.*
FROM (
SELECT *
FROM products
WHERE category = 'shoes'
LIMIT $limit OFFSET $offset
) AS products
LEFT JOIN products_sizes
ON products.products_id = products_sizes.products_id
WHERE products_sizes.size = 10
??
UPDATE: getting closer...
After reading the answers I now have this:
SELECT *
FROM products AS p
LEFT JOIN products_sizes AS s
ON p.product_id = s.product_id
WHERE s.product_id
IN (SELECT product_id FROM s WHERE size = 10)
AND p.category = 'shoes'
It satisfies my initial question's first two requirements:
Returns results constrained by category and size
Returns all sizes for each product if one of its sizes equals the specified size
... BUT I still need to limit the results to a certain number of products. If I put a LIMIT $limit at the very end of the query, it will limit the number of sizes returned and not the number of products... Thanks for the input.
The WHERE clause in your main query is defeating the purpose of your LEFT JOIN, making it the same as an INNER JOIN. It's very possible that there are not any rows selected by your derived table that match (shoes of size 10).
Unless there is something about your data not shown, you can try this:
SELECT products.*
, products_sizes.*
FROM products
JOIN products_sizes
ON products.products_id = products_sizes.products_id
WHERE products.category = 'shoes'
AND products_sizes.size = 10
LIMIT $limit OFFSET $offset
Your final query was absolutely correct. Just use the limit inside the subquery, that'll bind the number of products.
There are at least three result formats that you might want:
One row per size but limited to 10 distinct products
10 rows - one per product with a column containing comma separated sizes
Two result sets, which will be combined in PHP:
10 products
related sizes
For every format you need somehow to return 10 distinct products matching your conditions.
The most expressive way is to use an EXISTS statement:
select p.*
from products p
where p.category = 'shoes'
and exists (
select *
from products_sizes ps
where ps.product_id = p.product_id
and ps.size = 10
)
order by p.product_id
limit $limit offset $offset
Another way is to use a JOIN:
select p.*
from products p
join products_sizes ps
on ps.product_id = p.product_id
where p.category = 'shoes'
and ps.size = 10
order by p.product_id
limit $limit offset $offset
I will farther use the second one because of its compact code. But you can always replace it with the EXISTS statement.
1.
select p.*, ps.size
from (
select p.*
from products p
join products_sizes ps
on ps.product_id = p.product_id
where p.category = 'shoes'
and ps.size = 10
order by p.product_id
limit $limit offset $offset
) p
join products_sizes ps
on ps.product_id = p.product_id
order by p.product_id, ps.size
2.
select p.*, group_concat(ps.size order by ps.size) as sizes
from products p
join products_sizes ps1
on ps1.product_id = p.product_id
join products_sizes ps
on ps.product_id = p.product_id
where p.category = 'shoes'
and ps1.size = 10
group by p.product_id
order by p.product_id
limit $limit offset $offset
You can use explode() to convert the string to an array in PHP:
$product->sizes = explode(',' $product->sizes);
3.
select p.*
from products p
join products_sizes ps
on ps.product_id = p.product_id
where p.category = 'shoes'
and ps.size = 10
limit $limit offset $offset
Store the result in an array indexed by product id. E.g. in the fetchAssoc-loop:
$row->sizes = array();
$products[$row->product_id] = $row;
Extract the product IDs from the result:
$productIds = (',', array_keys($products));
Fetch the related sizes with;
select product_id, size
from products_sizes
where product_id in ($productIds)
order by product_id, size
Link the sizes in a loop
$products[$row->product_id]->sizes[] = $row->size;
Given the following sample data
| product_id | name | category | sizes |
|------------|--------|----------|-------|
| 1 | shoes1 | shoes | 8,9 |
| 2 | shirt1 | shirts | 10,11 |
| 3 | shoes2 | shoes | 9,10 |
| 4 | shoes3 | shoes | 10,11 |
| 5 | shoes4 | shoes | 10,12 |
and using LIMIT 2 OFFSET 0, the results will be:
1.
| product_id | name | category | size |
|------------|--------|----------|------|
| 3 | shoes2 | shoes | 9 |
| 3 | shoes2 | shoes | 10 |
| 4 | shoes3 | shoes | 10 |
| 4 | shoes3 | shoes | 11 |
2.
| product_id | name | category | sizes |
|------------|--------|----------|-------|
| 3 | shoes2 | shoes | 9,10 |
| 4 | shoes3 | shoes | 10,11 |
3.
| product_id | name | category |
|------------|--------|----------|
| 3 | shoes2 | shoes |
| 4 | shoes3 | shoes |
| product_id | size |
|------------|------|
| 3 | 9 |
| 3 | 10 |
| 4 | 10 |
| 4 | 11 |
Demos:
http://sqlfiddle.com/#!9/903c1/6
http://rextester.com/RZW84326
SELECT *
FROM products AS p
LEFT JOIN products_sizes AS s ON p.product_id = s.product_id
WHERE p.product_id IN (SELECT product_id FROM products_sizes WHERE size = 10)
LIMIT 15
EDIT (explanation):
I was thinking about it and realized you might want to know the reasoning too :p
You are interested in the products that meet a certain criteria, so that's your primary table to select from.
You'd like to know the sizes available for that product, join sizes to products.
You are only interested in the products that have a certain size. Run a sub-query to find which products have that size. Display only those products.

Related Links

Replace non-ASCII characters on image upload Wordpress
Nette Framework - Disable Latte macros
How do I trigger both of these?
htmlentities() expects parameter 1 to be string, array given when submitting the for
How to get the exact value from function shuffle in codeigniter?
Wordpress plugins: Can I implement locational search from one plugin with filtering from another?
Integrating parse server data into wordpress
methodnotallowedhttpexception in routecollection.php line 218
Retrieve data from mysql based upon a priority [duplicate]
PHP: file_put_contents Parse Error: syntax error, unexpected '‌​' (T_STRING) [duplicate]
Regular Expression to match version number pattern
How to : Populate Content of Page to another page in WordPress
Display Users' Notifications PHP
Need Unique clients with maixmum count first according to high priority
Authorize.net PHP Fatal error: Call to a member function getSubscriptionDetailType() on array
Filter Traffic Before Hitting Server Environment

Categories

HOME
elasticsearch
python-2.7
plesk
class
lambda
apple-push-notifications
activex
antd
odata
tabs
twitter-fabric
google-webmaster-tools
cypher
greasemonkey
bittorrent
sharepoint-online
port
reportviewer
alljoyn
jodatime
mailgun
async-await
tfsbuild
nullreferenceexception
android-custom-view
error-logging
acl
sybase-ase
tracing
copy-protection
monitor
vcenter
spring-rabbitmq
django-crispy-forms
uivisualeffectview
linq.js
task-parallel-library
swfupload
section508
webalizer
ol3-google-maps
nonlinear-functions
head.js
sonatype
deedle
dblink
emacs25
mpmovieplayercontroller
annotatorjs
cocoa-bindings
mifos
scheduledexecutorservice
openquery
maven-release-plugin
dojo-build
gnucash
sharepoint-apps
mercurial-extension
gravatar
flipclock
odesk
phpquery
largenumber
openshift-cartridge
astropy
fanotify
auto-generate
darwin
shoes
findersync
vs-unit-testing-framework
xhprof
webmethod
lumia-imaging-sdk
stripe.net
forio-contour
refit
bittorrent-sync
boolean-algebra
pre
jms-serializer
assetic
particle-swarm
jmenubar
saga
jquery-transit
node.js-stream
apportable
spiral
gprof
audiotoolbox
pageheap
monocross
firebird1.5
zend-server-ce
datacontracts
vows
firefly-mv
qt-mobility
fork-join
rtd
printqueue
bass
solandra
ninject-interception
uninstaller
rootkit
webclient.uploaddata

Resources

Encrypt Message