我有下表存储用户在系统中的首选项
UserId | Product | Brand | City |
-------------------------------------------
A | Soap | Tide | NYC |
A | Cereal | Dont-care | NYC |
B | Dont-Care | Tide | Dont-care |
C | Shampoo | Dont-care | Dont-Care |
我想根据用户提供的搜索值进行搜索。所以,如果一个人搜索
City: NYC, Brand: Tide
输出应为:
A | Soap | Tide | NYC |
B | Dont-Care | Tide | Dont-care |
就好像他们搜索
一样Brand: Tide, Product: Soap
结果应该是:
A | Soap | Tide | NYC |
我当前的解决方案是针对MySQL表的以下查询(其中null表示'不关心'):
select *
from user_preferences
where (product is null or product = <user provided value>)
and (brand is null or brand = <user provided value>)
and (city is null or city = <user provided value>)
虽然它按预期工作,但[和+(或)]组合让我觉得这不是正确的方法。我也相当确定,一旦数据集增加,查询将无法正常运行。
存储和检索此类数据的最有效方法是什么?是否有任何no-sql类型的方法可用于提高效率?
更新
经过一些谷歌搜索后,我认为我的方法可能是最安全的选择。我仍然对这种方法感到矛盾的一个因素是添加另一个“可搜索”属性意味着添加一个新列。
关于EAV anti-pattern的博客提供了一些关于此类计划的优秀阅读材料。另请参阅friend-feed uses MySQL如何在表中存储变量属性。
答案 0 :(得分:0)
您可以使用IFNULL()函数。
这将是这样的:
select *
from user_preferences
where ifnull(product, <user provided value>) = <user provided value>
and ifnull(brand, <user provided value>) = <user provided value>
and ifnull(city, <user provided value>) = <user provided value>
答案 1 :(得分:0)
基于@ Pompom6784的回答 -
但从逻辑上讲它有很大的不同 条件 -
select * from user_preferences
where product = nvl(<user provided value> , product)
and brand = nvl(<user provided value> ,brand)
and city = nvl(<user provided value> ,city)
我是oracle pl sql开发人员所以请检查以上查询有oracle sql的syntex ..
如果您的数据库中ifnull
是检查空值的函数,请将nvl()
替换为ifnull
()
@ Pompom6784你必须在&lt;上使用ifnull用户提供的值&gt;不是列值..
答案 2 :(得分:0)
既然你问如何存储这些数据,这就是我可能会做的事情:
USERS
userid PK
name
etc
PREFTYPES
preftypeid PK
prefname
PREFTYPEVALUES
preftypeid foreign key references PREFTYPES(preftypeid)
value
composite primary key (preftypeid, value)
上面的PREFTYPEVALUES表允许您约束USERPREFS表中可能的值条目:
USERPREFS
userid foreign key references USERS(userid)
preftypeid
value
=> composite foreign key(preftypeid, value) references PREFTYPEVALUES(preftypeid, value)
要合并两组用户,第一组是那些喜欢Tide为他们的肥皂而第二组是那些喜欢NYC作为他们的城市的用户,你可以UNION两套用户:
select U.userid, U.name, UP.value
from USERS U
inner join USERPREFS UP on U.userid = UP.userid
where
(UP.preftypeid = 'soap' and UP.value = 'Tide' )
UNION
select U.userid, U.name, UP.value
from USERS U
inner join USERPREFS UP on U.userid = UP.userid
where
(UP.preftypeid = 'city' and UP.value = 'NYC')
但是这个结构当然也允许不使用UNION的查询。
select U.userid, U.name, UP.value
from USERS U
inner join USERPREFS UP on U.userid = UP.userid
where
(UP.preftypeid = 'soap' and UP.value = 'Tide' )
OR
(UP.preftypeid = 'city' and UP.value = 'NYC')
我打赌你的下一个问题是:如何为每个用户获得一行,用户的偏好并排?
user-A, Tide, NYC
这种非规范化最好留给表示层,尽管可以使用各种不优雅的方法在SQL中完成。这里的SQL键是复合的(user,preftype)。