SQL where子句和分隔的IN表达式来实现CNF



我需要根据动态添加的属性(转置表)来查询用户

我有4张桌子

  • 用户-针对用户
  • propertyGroup-对于属性组,可以将组动态添加到数据库中
  • propertyValue-查找propertyGroup的可能值
  • 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 |

所以一个混合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

我想通过一组propertyValueId查询数据,并获取与该组的属性集相匹配的所有用户,因此用户需要至少拥有每个组中的一个属性-换句话说,一个与通用CNF子句相匹配的where calause,如下所示:(pvId是propertyValueId的缩写)

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运算器(IN模拟或部分析取)连接到这里(查询上面的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)),而是一个都没有。

我理解为什么结果集是空的,但我不理解如何实现right 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中有解决方案,那也很棒。但如果没有,我会翻译。。。感谢

根据我对您的注释的理解,您希望查询与两个属性值ID相关联的所有用户(因此{1,5}转到爱好:科技,喜欢食物:蔬菜的属性值ID)

一旦你这样表述它,很简单,首先得到一个列表,然后得到另一个列表并在两者中找到元素,如下所示:

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或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

---

从小提琴

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

我认为当您更改和通过或在where子句中时会有所帮助

其中(pv.propertiesGroupId=1 AND pv.id IN(1,2))

相关内容

  • 没有找到相关文章

最新更新