I have a table items
and a table parameters
. A join table of item_parameters
stores the value for each possible parameter for an item, instead of having a separate column for each parameter.
For example (simplified):
parameters: items:
id: 1, name: color id: 1, name: bike
id: 2, name: size id: 2, name: phone
id: 3, name: weight id: 3, name: shoe
item_parameters:
id: 1, item_id: 1, parameter_id: 1, value: "blue"
id: 2, item_id: 1, parameter_id: 2, value: "large"
id: 3, item_id: 1, parameter_id: 3, value: "heavy"
id: 4, item_id: 2, parameter_id: 1, value: "black"
id: 5, item_id: 2, parameter_id: 2, value: "medium"
id: 6, item_id: 2, parameter_id: 3, value: "medium"
id: 7, item_id: 3, parameter_id: 1, value: "white"
id: 8, item_id: 3, parameter_id: 2, value: "small"
id: 9, item_id: 3, parameter_id: 3, value: "light"
How can I search for items (applying a filter for specific parameters) and order the results based on the value
of a particular parameter
for the items
?
I know how to apply the filter part, using a where clause with item_parameters.parameter_id = ? AND item_parameters.value = ?
item_parameters.parameter_id = ? AND item_parameters.value = ?
But for the ordering part, simply adding ORDER BY item_parameters.value desc
doesn't seem to be enough to order by only those item_parameters.value
where item_parameters.parameter_id = ?
.
In my results of items, I want all item_parameters
for that item
including the parameters
that weren't used in the order by clause.
This query is still a work in progress because I don't yet have it returning all item_parameters
for each item
:
SELECT DISTINCT
`items`.name,
`parameters`.name,
`item_parameters`.value
FROM `items`
LEFT OUTER JOIN `item_parameters` ON `item_parameters`.`item_id` = `items`.`id`
LEFT OUTER JOIN `parameters` ON `item_parameters`.`parameter_id` = `parameters`.`id`
WHERE (item_parameters.parameter_id = 3 AND item_parameters.value = 'light')
ORDER BY item_parameters.value LIMIT 10000;
In addition currently not returning all item_parameters, the relevant missing piece above for this post is that the order logic (pseudocode) needs to be ORDER BY items_parameters.value where item_parameters.parameter_id = 1
Here is an example of desired results, assumes from a larger example data set than the provided example above:
item name color size weight
cup brown small light
shirt green medium light
candy pink large light
chair tan medium light
paper white large light
Notice that the results are all filtered on parameter 3 (weight) = light and ordered on parameter 1 (color).
Thanks for any guidance on this.
I'm not sure it's best for performance but here's how I would logically construct the query.
First SELECT all the items and their parameters:
SELECT i.name, p.name, ip.value
FROM items i
JOIN item_parameters ip
ON ip.item_id = i.id
JOIN parameters p
ON p.id = ip.parameter_id
Then make sure you only have items that have the correct value for a particular param:
JOIN item_parameters ip3
ON ip3.parameter_id = 3
AND ip3.item_id = i.id
AND ip3.value = 'light'
Then include the param that you are ordering by:
JOIN item_parameters ip1
ON ip1.parameter_id = 1
AND ip1.item_id = i.id
Then add the ORDER BY:
ORDER BY ip1.value DESC, i.id, p.id
If you are ordering by a parameter that may not be present, you'll have to LEFT JOIN to that one and choose where to put the resultant NULL values.
This also will NOT pivot the table as shown in your example results, but will keep the items grouped together nicely.
If you wish to have the pivoted table, you'll probably have to join all the parameters separately, similar to 1 and 3 above. You can either do this manually or by dynamically building the query from a list of expected/required parameters.
UPDATE
For the pivoted results shown, with a bit of hard coding:
SELECT i.name, color.value color, size.value size, weight.value weight
FROM items i
JOIN item_parameters color
ON color.parameter_id = 1
AND color.item_id = i.id
JOIN item_parameters size
ON size.parameter_id = 2
AND size.item_id = i.id
JOIN item_parameters weight
ON weight.parameter_id = 3
AND weight.item_id = i.id
WHERE weight.value = 'light'
ORDER BY color.value DESC
You could join on the parameters table to get the names too just in case they change, but this gives you an outline.
The downside of this approach is that the query will have to be updated every time you add a new parameter.
Personally, I prefer the group style method, the pivot table can be generated using application code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.