我有一个下表结构。
USERS
PROPERTY_VALUE
PROPERTY_NAME
USER_PROPERTY_MAP
我正在尝试从users
表中检索property_value
表中具有匹配属性的用户。
单个用户可以拥有多个属性。这里的示例数据有2个用户'1'的属性,但可以有2个以上。我想在WHERE
子句中使用所有这些用户属性。
如果用户具有单个属性但是对于多个属性失败,则此查询有效:
SELECT * FROM users u
INNER JOIN user_property_map upm ON u.id = upm.user_id
INNER JOIN property_value pv ON upm.property_value_id = pv.id
INNER JOIN property_name pn ON pv.property_name_id = pn.id
WHERE (pn.id = 1 AND pv.id IN (SELECT id FROM property_value WHERE value like '101')
AND pn.id = 2 AND pv.id IN (SELECT id FROM property_value WHERE value like '102')) and u.user_name = 'user1' and u.city = 'city1'
我理解,因为查询有pn.id = 1 AND pn.id = 2
,所以它总是会失败,因为pn.id
可以是1或2,但不能同时是两者。那么如何重新编写它以使其适用于n个属性?
在上面的示例数据中,只有一个id = 1
用户具有WHERE
子句中使用的匹配属性。查询应返回包含USERS
表的所有列的单个记录。
我正在开发一个应用程序,该应用程序在UI上有一个用户列表页面,列出了系统中的所有用户。此列表包含用户ID,用户名,城市等信息 - USERS
表中的所有列。用户可以拥有上述数据库模型中详述的属性。
用户列表页面还提供了基于这些属性搜索用户的功能。搜索具有2个属性'property1'和'property2'的用户时,该页面应该只获取并显示匹配的行。根据上面的测试数据,只有用户'1'符合账单。
具有4个属性的用户包括'property1'和'property2'符合条件。但是由于缺少'property2',将只排除只有一个属性'property1'的用户。
答案 0 :(得分:6)
SELECT *
FROM users u
WHERE u.id IN(
select m.user_id
from property_value v
join USER_PROPERTY_MAP m
on v.id=m.property_value_id
where (v.property_name_id, v.value) in( (1, '101'), (2, '102') )
group by m.user_id
having count(*)=2
)
OR
SELECT u.id
FROM users u
INNER JOIN user_property_map upm ON u.id = upm.user_id
INNER JOIN property_value pv ON upm.property_value_id = pv.id
WHERE (pv.property_name_id=1 and pv.value='101')
OR (pv.property_name_id=2 and pv.value='102')
GROUP BY u.id
HAVING count(*)=2
如果propery_name_id已知,则查询中不需要property_name
个表。
答案 1 :(得分:5)
如果您只想过滤:
SELECT users.*
FROM users
where (
select count(*)
from user_property_map
left join property_value on user_property_map.property_value_id = property_value.id
left join property_name on property_value.property_name_id = property_name.id
where user_property_map.user_id = users.id -- join with users table
and (property_name.name, property_value.value) in (
values ('property1', '101'), ('property2', '102') -- filter properties by name and value
)
) = 2 -- number of properties you filter by
或者,如果您需要根据匹配数量下降的用户,您可以这样做:
select * from (
SELECT users.*, (
select count(*) as property_matches
from user_property_map
left join property_value on user_property_map.property_value_id = property_value.id
left join property_name on property_value.property_name_id = property_name.id
where user_property_map.user_id = users.id -- join with users table
and (property_name.name, property_value.value) in (
values ('property1', '101'), ('property2', '102') -- filter properties by name and value
)
)
FROM users
) t
order by property_matches desc
答案 2 :(得分:2)
您在两个AND
和pn.id=1
之间使用pn.id=2
运算符。然后你如何得到答案:
(SELECT id FROM property_value WHERE value like '101') and
(SELECT id FROM property_value WHERE value like '102')
与上述评论一样,请使用or
运算符。
更新1:
SELECT * FROM users u
INNER JOIN user_property_map upm ON u.id = upm.user_id
INNER JOIN property_value pv ON upm.property_value_id = pv.id
INNER JOIN property_name pn ON pv.property_name_id = pn.id
WHERE pn.id in (1,2) AND pv.id IN (SELECT id FROM property_value WHERE value like '101' or value like '102');
答案 3 :(得分:2)
SELECT * FROM users u
INNER JOIN user_property_map upm ON u.id = upm.user_id
INNER JOIN property_value pv ON upm.property_value_id = pv.id
INNER JOIN property_name pn ON pv.property_name_id = pn.id
WHERE (pn.id = 1 AND pv.id IN (SELECT id FROM property_value WHERE value
like '101') )
OR ( pn.id = 2 AND pv.id IN (SELECT id FROM property_value WHERE value like
'102'))
OR (...)
OR (...)
你不能做AND因为没有这样的情况,其中id为1和2为SAME ROW,你指定每行的where条件!
如果你运行一个简单的测试,比如
SELECT * FROM users where id=1 and id=2
你会得到0分的结果。实现这一目标
id in (1,2)
或
id=1 or id=2
该查询可以进行更多优化,但我希望这是一个良好的开端。
答案 4 :(得分:2)
如果你只想要U中的不同列,那就是:
SELECT DISTINCT u.*
FROM Users u INNER JOIN USER_PROPERTY_MAP upm ON u.id = upm.[user_id]
INNER JOIN PROPERTY_VALUE pv ON upm.property_value_id = pv.id
INNER JOIN PROPERTY_NAME pn ON pv.property_name_id = pn.id
WHERE (pn.id = 1 AND pv.[value] = '101')
OR (pn.id = 2 AND pv.[value] = '102')
注意我使用pv.[value] =
而不是子查询重新获取id ...这是简化。