SQL where 子句带有分离的 IN 表达式以实现 CNF
SQL where clause with seperataed IN expression to implement CNF
我需要根据动态添加的属性查询用户(转置table)
我有 4 table
- 用户 - 对于用户
- 属性Group - 对于属性组,可以将组动态添加到 db
- 属性Value - 属性Group
的可能值
- usersPropertyValues - 将用户连接到他的相关属性
它看起来像这样:
users:
------
| id | name | details |
|----|------|---------|
| 1 | Joe | foo |
| 2 | Dan | bar |
propertyGroup:
--------------
| id | name |
|----|----------------|
| 1 | Hobbies |
| 2 | LikeFood |
| 3 | VisitedCountry |
propertyValue:
--------------
| id | propertyGroupId | name |
|----|-----------------|--------------|
| 1 | 1 | Technologies |
| 2 | 1 | Surfing |
| 3 | 2 | Rice |
| 4 | 2 | Meat |
| 5 | 2 | Veg |
| 6 | 3 | USA |
| 7 | 3 | FRANCE |
| 8 | 3 | ISRAEL |
| 9 | 3 | CANADA |
usersPropertyValues:
--------------------
| userId | propertyValueId |
|--------|-----------------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 5 |
| 1 | 6 |
| 1 | 7 |
| 1 | 8 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
| 2 | 5 |
| 2 | 8 |
| 2 | 9 |
| 2 | 7 |
所以 mix-em-all 查询将如下所示:
select *
from users as u
join usersPropertyValues as upv on upv.userId = u.id
join propertyValues as pv on pv.id = upv.propertyValueId
join propertyGroup as pg on pg.id = pv.propertyGroupId
| id | name | details | userId | propertyValueId | id | propertyGroupId | name | id | name |
|----|------|---------|--------|-----------------|----|-----------------|--------------|----|----------------|
| 1 | Joe | foo | 1 | 1 | 1 | 1 | Technologies | 1 | Hobbies |
| 1 | Joe | foo | 1 | 2 | 2 | 1 | Surfing | 1 | Hobbies |
| 1 | Joe | foo | 1 | 3 | 3 | 2 | Rice | 2 | LikeFood |
| 1 | Joe | foo | 1 | 5 | 5 | 2 | Veg | 2 | LikeFood |
| 1 | Joe | foo | 1 | 6 | 6 | 3 | USA | 3 | VisitedCountry |
| 1 | Joe | foo | 1 | 7 | 7 | 3 | FRANCE | 3 | VisitedCountry |
| 1 | Joe | foo | 1 | 8 | 8 | 3 | ISRAEL | 3 | VisitedCountry |
| 2 | Dan | bar | 2 | 2 | 2 | 1 | Surfing | 1 | Hobbies |
| 2 | Dan | bar | 2 | 3 | 3 | 2 | Rice | 2 | LikeFood |
| 2 | Dan | bar | 2 | 4 | 4 | 2 | Meat | 2 | LikeFood |
| 2 | Dan | bar | 2 | 5 | 5 | 2 | Veg | 2 | LikeFood |
| 2 | Dan | bar | 2 | 8 | 8 | 3 | ISRAEL | 3 | VisitedCountry |
| 2 | Dan | bar | 2 | 9 | 9 | 3 | CANADA | 3 | VisitedCountry |
| 2 | Dan | bar | 2 | 7 | 7 | 3 | FRANCE | 3 | VisitedCountry |
全部在这里:http://sqlfiddle.com/#!3/49329/1
我想通过一组 属性ValueId 查询数据,并获取与该组属性匹配的所有用户,以便与该组相关用户需要至少有来自每个组的 属性 - 换句话说,一个与一般 CNF 子句匹配的 where 子句,如下所示:
(pvId 是 属性ValueId 的缩写)
Property group A Property group B Property group C
(pvId_x or pvId_y) and (pvId_w or pvId_z) and... and (pvId_m or pvId_k)
上例中pvId_x&pvId_y属于A组,pvId_w&pvId_z属于B组等
我没有工作,
我尝试连接 IN 运算符的 AND oparators(模拟 or 部分 - 析取),如此处所示(查询上述 sql fiddle):
select distinct u.name, u.id
from users as u
join usersPropertyValues as upv on upv.userId = u.id
join propertyValues as pv on pv.id = upv.propertyValueId
join propertyGroup as pg on pg.id = pv.propertyGroupId
where (pv.propertyGroupId = 1 AND pv.id IN(1,2)) and (pv.propertyGroupId = 2 AND pv.id IN(5,6))
而不是让两个用户(都有(1 或 2)和(5 或 6))- 我得到 none。
我明白为什么结果集是空的,但我不明白如何实现正确的 where 子句。 - 如何做到?
我的问题:
如何在上述 SQL 结构中实现 CNF 逻辑?
编辑:异常结果示例:(关于 sqlfiddle 示例:
input --> output
{1,5} --> Joe (user with hobby:tech, likefood:veg)
{2,8} --> Joe,Dan (user with hobby:surfing, VisitedCountry:Israel)
{2,8,9} --> Dan (user with hobby:surfing, VisitedCountry:Israel,Canada)
顺便说一句,我最终需要在 JPA 中实现它,所以如果 JPA 中有解决方案,那也很好。但如果没有 - 我会翻译它......
谢谢
我认为当您更改 and by 或在 where 子句中时它会有所帮助
where (pv.propertyGroupId = 1 AND pv.id IN(1,2)) or (pv.propertyGroupId = 2 和 pv.id IN(5,6))
据我了解,您想要查询与两个 属性valueid 关联的所有用户(因此 {1,5} 转到 属性 hobby:tech 的值 id , likefood:veg)
一旦你这样表达它就很简单了,首先得到一个列表,然后得到另一个列表,然后在两者中找到元素,就像这样:
select *
from users
where id in (
select userid from userPropertyValues where propertyvalueid = 1
intersect
select userid from userPropertyValues where propertyvalueid = 5
) sub
请注意,我可以使用内部联接而不是相交运算符,但相交更性感。如果您的平台不支持它,请使用连接。
作为连接:
select *
from users
join (select userid from userPropertyValues where propertyvalueid=1) a on a.userid = users.id
join (select userid from userPropertyValues where propertyvalueid=5) b on b.userid = users.id
或更简单地表述为(这是 AND 条件 - 1 和 5)
select *
from users
join userPropertyValues a on a.userid = users.id and a.propertyvalueid=1
join userPropertyValues b on b.userid = users.id and b.propertyvalueid=5
(这是 OR 条件 - 1 OR 5)
select *
from users
left join userPropertyValues a on a.userid = users.id and a.propertyvalueid=1
left join userPropertyValues b on b.userid = users.id and b.propertyvalueid=5
where coalesce(a.userid, b.userid) is not null
你也可以说
where a.userid is not null or b.userid is not null
---
来自 fiddle
select *
from users
where id in (
select userid from usersPropertyValues where propertyvalueid = 1
intersect
(
select userid from usersPropertyValues where propertyvalueid = 3
UNION ALL
select userid from usersPropertyValues where propertyvalueid = 4
)
);
让我们看看相交之前的部分
select *
from users
join userPropertyValues a on a.userid = users.id and a.propertyvalueid=1
之后的部分是
select *
from users
left join userPropertyValues b on b.userid = users.id and b.propertyvalueid=1
left join userPropertyValues c on c.userid = users.id and c.propertyvalueid=5
where coalesce(b.userid, c.userid) is not null
所以把它们放在一起(两者都适用于相交,因为它与 AND 相同):
select *
from users
join userPropertyValues a on a.userid = users.id and a.propertyvalueid=1
left join userPropertyValues b on b.userid = users.id and b.propertyvalueid=1
left join userPropertyValues c on c.userid = users.id and c.propertyvalueid=5
where coalesce(b.userid, c.userid) is not null
我需要根据动态添加的属性查询用户(转置table)
我有 4 table
- 用户 - 对于用户
- 属性Group - 对于属性组,可以将组动态添加到 db
- 属性Value - 属性Group 的可能值
- usersPropertyValues - 将用户连接到他的相关属性
它看起来像这样:
users:
------
| id | name | details |
|----|------|---------|
| 1 | Joe | foo |
| 2 | Dan | bar |
propertyGroup:
--------------
| id | name |
|----|----------------|
| 1 | Hobbies |
| 2 | LikeFood |
| 3 | VisitedCountry |
propertyValue:
--------------
| id | propertyGroupId | name |
|----|-----------------|--------------|
| 1 | 1 | Technologies |
| 2 | 1 | Surfing |
| 3 | 2 | Rice |
| 4 | 2 | Meat |
| 5 | 2 | Veg |
| 6 | 3 | USA |
| 7 | 3 | FRANCE |
| 8 | 3 | ISRAEL |
| 9 | 3 | CANADA |
usersPropertyValues:
--------------------
| userId | propertyValueId |
|--------|-----------------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 5 |
| 1 | 6 |
| 1 | 7 |
| 1 | 8 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
| 2 | 5 |
| 2 | 8 |
| 2 | 9 |
| 2 | 7 |
所以 mix-em-all 查询将如下所示:
select *
from users as u
join usersPropertyValues as upv on upv.userId = u.id
join propertyValues as pv on pv.id = upv.propertyValueId
join propertyGroup as pg on pg.id = pv.propertyGroupId
| id | name | details | userId | propertyValueId | id | propertyGroupId | name | id | name |
|----|------|---------|--------|-----------------|----|-----------------|--------------|----|----------------|
| 1 | Joe | foo | 1 | 1 | 1 | 1 | Technologies | 1 | Hobbies |
| 1 | Joe | foo | 1 | 2 | 2 | 1 | Surfing | 1 | Hobbies |
| 1 | Joe | foo | 1 | 3 | 3 | 2 | Rice | 2 | LikeFood |
| 1 | Joe | foo | 1 | 5 | 5 | 2 | Veg | 2 | LikeFood |
| 1 | Joe | foo | 1 | 6 | 6 | 3 | USA | 3 | VisitedCountry |
| 1 | Joe | foo | 1 | 7 | 7 | 3 | FRANCE | 3 | VisitedCountry |
| 1 | Joe | foo | 1 | 8 | 8 | 3 | ISRAEL | 3 | VisitedCountry |
| 2 | Dan | bar | 2 | 2 | 2 | 1 | Surfing | 1 | Hobbies |
| 2 | Dan | bar | 2 | 3 | 3 | 2 | Rice | 2 | LikeFood |
| 2 | Dan | bar | 2 | 4 | 4 | 2 | Meat | 2 | LikeFood |
| 2 | Dan | bar | 2 | 5 | 5 | 2 | Veg | 2 | LikeFood |
| 2 | Dan | bar | 2 | 8 | 8 | 3 | ISRAEL | 3 | VisitedCountry |
| 2 | Dan | bar | 2 | 9 | 9 | 3 | CANADA | 3 | VisitedCountry |
| 2 | Dan | bar | 2 | 7 | 7 | 3 | FRANCE | 3 | VisitedCountry |
全部在这里:http://sqlfiddle.com/#!3/49329/1
我想通过一组 属性ValueId 查询数据,并获取与该组属性匹配的所有用户,以便与该组相关用户需要至少有来自每个组的 属性 - 换句话说,一个与一般 CNF 子句匹配的 where 子句,如下所示: (pvId 是 属性ValueId 的缩写)
Property group A Property group B Property group C
(pvId_x or pvId_y) and (pvId_w or pvId_z) and... and (pvId_m or pvId_k)
上例中pvId_x&pvId_y属于A组,pvId_w&pvId_z属于B组等
我没有工作, 我尝试连接 IN 运算符的 AND oparators(模拟 or 部分 - 析取),如此处所示(查询上述 sql fiddle):
select distinct u.name, u.id
from users as u
join usersPropertyValues as upv on upv.userId = u.id
join propertyValues as pv on pv.id = upv.propertyValueId
join propertyGroup as pg on pg.id = pv.propertyGroupId
where (pv.propertyGroupId = 1 AND pv.id IN(1,2)) and (pv.propertyGroupId = 2 AND pv.id IN(5,6))
而不是让两个用户(都有(1 或 2)和(5 或 6))- 我得到 none。
我明白为什么结果集是空的,但我不明白如何实现正确的 where 子句。 - 如何做到?
我的问题: 如何在上述 SQL 结构中实现 CNF 逻辑?
编辑:异常结果示例:(关于 sqlfiddle 示例:
input --> output
{1,5} --> Joe (user with hobby:tech, likefood:veg)
{2,8} --> Joe,Dan (user with hobby:surfing, VisitedCountry:Israel)
{2,8,9} --> Dan (user with hobby:surfing, VisitedCountry:Israel,Canada)
顺便说一句,我最终需要在 JPA 中实现它,所以如果 JPA 中有解决方案,那也很好。但如果没有 - 我会翻译它...... 谢谢
我认为当您更改 and by 或在 where 子句中时它会有所帮助
where (pv.propertyGroupId = 1 AND pv.id IN(1,2)) or (pv.propertyGroupId = 2 和 pv.id IN(5,6))
据我了解,您想要查询与两个 属性valueid 关联的所有用户(因此 {1,5} 转到 属性 hobby:tech 的值 id , likefood:veg)
一旦你这样表达它就很简单了,首先得到一个列表,然后得到另一个列表,然后在两者中找到元素,就像这样:
select *
from users
where id in (
select userid from userPropertyValues where propertyvalueid = 1
intersect
select userid from userPropertyValues where propertyvalueid = 5
) sub
请注意,我可以使用内部联接而不是相交运算符,但相交更性感。如果您的平台不支持它,请使用连接。
作为连接:
select *
from users
join (select userid from userPropertyValues where propertyvalueid=1) a on a.userid = users.id
join (select userid from userPropertyValues where propertyvalueid=5) b on b.userid = users.id
或更简单地表述为(这是 AND 条件 - 1 和 5)
select *
from users
join userPropertyValues a on a.userid = users.id and a.propertyvalueid=1
join userPropertyValues b on b.userid = users.id and b.propertyvalueid=5
(这是 OR 条件 - 1 OR 5)
select *
from users
left join userPropertyValues a on a.userid = users.id and a.propertyvalueid=1
left join userPropertyValues b on b.userid = users.id and b.propertyvalueid=5
where coalesce(a.userid, b.userid) is not null
你也可以说
where a.userid is not null or b.userid is not null
---
来自 fiddle
select *
from users
where id in (
select userid from usersPropertyValues where propertyvalueid = 1
intersect
(
select userid from usersPropertyValues where propertyvalueid = 3
UNION ALL
select userid from usersPropertyValues where propertyvalueid = 4
)
);
让我们看看相交之前的部分
select *
from users
join userPropertyValues a on a.userid = users.id and a.propertyvalueid=1
之后的部分是
select *
from users
left join userPropertyValues b on b.userid = users.id and b.propertyvalueid=1
left join userPropertyValues c on c.userid = users.id and c.propertyvalueid=5
where coalesce(b.userid, c.userid) is not null
所以把它们放在一起(两者都适用于相交,因为它与 AND 相同):
select *
from users
join userPropertyValues a on a.userid = users.id and a.propertyvalueid=1
left join userPropertyValues b on b.userid = users.id and b.propertyvalueid=1
left join userPropertyValues c on c.userid = users.id and c.propertyvalueid=5
where coalesce(b.userid, c.userid) is not null