I have 4 tables:
我有4张桌子:
items
+----+------+---------+-----+
| id | name | city_id | ... |
+----+------+---------+-----+
attributes
+----+------+-----+
| id | name | ... |
+----+------+-----+
item_attribute
+----+---------+--------------+
| id | item_id | attribute_id |
+----+---------+--------------+
city
+----+------+-----+
| id | name | ... |
+----+------+-----+
Items and attributes have relations many-to-many.
项目和属性具有多对多的关系。
Item is located only in one city one-to-many
物品仅位于一对多的城市中
Question:
I'm using php (Laravel). How can I get Items list (with LIMIT) for one Item with similar attributes in one city? Attribute list is never equals for 2 items.
我正在使用php(Laravel)。如何在一个城市中为一个具有相似属性的项目获取项目列表(带LIMIT)?属性列表永远不等于2个项目。
Is it possible to do with MySQL query?
是否可以使用MySQL查询?
Example:
| ItemName | Attributes | City |
+----------+-----------------------+------+
| Alpha | one, two, three, four | NY |
| Beta | five, six, seven | NY |
| Gamma | one, three, seven | NY |
| Delta | one, six, eight | CA |
| Epsilon | two, three, four | NY |
| Zeta | ten, nine | NY |
I want to choose similar items for Alpha
, they will be: Gamma
, Epsilon
because they have similar attributes.
我想为Alpha选择类似的项目,它们将是:Gamma,Epsilon,因为它们具有相似的属性。
Delta
won't be chosen, because it's located in another city.
Delta将不会被选中,因为它位于另一个城市。
2 个解决方案
#1
1
If you have both the item_id and the city_id to pass in:
如果您同时传入item_id和city_id:
SELECT i.name,
GROUP_CONCAT(a.name) attributes,
c.name
FROM items i
JOIN city c
ON c.id = i.city_id
JOIN item_attribute ia
ON ia.item_id = i.id
AND EXISTS (
SELECT 1
FROM item_attribute ia1
JOIN item_attribute ia2
ON ia2.attribute_id = ia1.attribute_id
AND ia2.item_id = ia.item_id
WHERE ia1.item_id = :item_id /* Pass in item id variable */
)
JOIN attributes a
ON a.id = ia.attribute_id
WHERE i.city_id = :city_id /* Pass in city id variable */
GROUP BY i.name, c.name
If you just want to pass the example item id: (A little bit sloppy, but should work)
如果你只是想传递示例项id :(有点草率,但应该工作)
SELECT i.name,
GROUP_CONCAT(a.name) attributes,
c.name
FROM items base
JOIN items i
ON i.city_id = base.city_id
JOIN city c
ON c.id = i.city_id
JOIN item_attribute ia
ON ia.item_id = i.id
AND EXISTS (
SELECT 1
FROM item_attribute ia1
JOIN item_attribute ia2
ON ia2.attribute_id = ia1.attribute_id
AND ia2.item_id = ia.item_id
WHERE ia1.item_id = base.id
)
JOIN attributes a
ON a.id = ia.attribute_id
WHERE base.id = :item_id /* Pass in item id variable */
GROUP BY i.name, c.name
** UPDATE **
**更新**
Ordering:
...
JOIN (
SELECT ia2.item_id, COUNT(*) count
FROM item_attribute ia1
JOIN item_attribute ia2
ON ia2.attribute_id = ia1.attribute_id
AND ia2.item_id = ia1.item_id
/* AND ia2.id != ia1.id /* If you don't want the original item */
WHERE ia1.item_id = base.id
GROUP BY ia2.item_id
) similar
ON similar.id = ia.item_id
...
ORDER BY similar.count DESC
#2
0
You can perform INNER JOINS
in all
您可以执行所有INNER JOINS
SELECT I.name,I_A.name,city.name FROM attributes as A
INNER JOIN item_attribute as I_A ON I_A.attribute_id = A.id
INNER JOIN city ON I_A.id = city.id
INNER JOIN items as I ON I.id = I_A.item_id
WHERE <Your condition>
To get comma separated values you can refer here Let me know if I am not getting your point.
要获得逗号分隔值,您可以参考这里。如果我没有明白您的观点,请告诉我。
#1
1
If you have both the item_id and the city_id to pass in:
如果您同时传入item_id和city_id:
SELECT i.name,
GROUP_CONCAT(a.name) attributes,
c.name
FROM items i
JOIN city c
ON c.id = i.city_id
JOIN item_attribute ia
ON ia.item_id = i.id
AND EXISTS (
SELECT 1
FROM item_attribute ia1
JOIN item_attribute ia2
ON ia2.attribute_id = ia1.attribute_id
AND ia2.item_id = ia.item_id
WHERE ia1.item_id = :item_id /* Pass in item id variable */
)
JOIN attributes a
ON a.id = ia.attribute_id
WHERE i.city_id = :city_id /* Pass in city id variable */
GROUP BY i.name, c.name
If you just want to pass the example item id: (A little bit sloppy, but should work)
如果你只是想传递示例项id :(有点草率,但应该工作)
SELECT i.name,
GROUP_CONCAT(a.name) attributes,
c.name
FROM items base
JOIN items i
ON i.city_id = base.city_id
JOIN city c
ON c.id = i.city_id
JOIN item_attribute ia
ON ia.item_id = i.id
AND EXISTS (
SELECT 1
FROM item_attribute ia1
JOIN item_attribute ia2
ON ia2.attribute_id = ia1.attribute_id
AND ia2.item_id = ia.item_id
WHERE ia1.item_id = base.id
)
JOIN attributes a
ON a.id = ia.attribute_id
WHERE base.id = :item_id /* Pass in item id variable */
GROUP BY i.name, c.name
** UPDATE **
**更新**
Ordering:
...
JOIN (
SELECT ia2.item_id, COUNT(*) count
FROM item_attribute ia1
JOIN item_attribute ia2
ON ia2.attribute_id = ia1.attribute_id
AND ia2.item_id = ia1.item_id
/* AND ia2.id != ia1.id /* If you don't want the original item */
WHERE ia1.item_id = base.id
GROUP BY ia2.item_id
) similar
ON similar.id = ia.item_id
...
ORDER BY similar.count DESC
#2
0
You can perform INNER JOINS
in all
您可以执行所有INNER JOINS
SELECT I.name,I_A.name,city.name FROM attributes as A
INNER JOIN item_attribute as I_A ON I_A.attribute_id = A.id
INNER JOIN city ON I_A.id = city.id
INNER JOIN items as I ON I.id = I_A.item_id
WHERE <Your condition>
To get comma separated values you can refer here Let me know if I am not getting your point.
要获得逗号分隔值,您可以参考这里。如果我没有明白您的观点,请告诉我。