0

我有下表存储系统中用户的偏好

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

虽然它按预期工作,但 [and + (or)] 组合让我认为这不是正确的方法。我也相当肯定,一旦数据集增加,查询将不会执行良好。

存储和检索此类数据的最有效方法是什么?是否有任何 no-sql 类型的方法可以用来提高效率?

更新

经过一番谷歌搜索后,我认为我所采用的方法可能是最安全的选择。我仍然对这种方法感到矛盾的一个因素是,添加另一个“可搜索”属性将意味着添加一个新列。

这个关于EAV 反模式的博客提供了一些关于这种方案的很好的阅读材料。另请参阅friend-feed 如何使用 MySQL将变量属性存储在表中。

4

3 回答 3

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 语法的查询。如果在您的数据库ifnull中有检查空值的功能,请替换nvl()ifnull()

@ Pompom6784 您必须将 ifnull 应用于 <用户提供的值> 而不是列值..

于 2011-07-03T10:39:00.243 回答
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>
于 2011-07-02T02:42:51.677 回答
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 作为他们的城市的人,你可以将这两组联合起来:

             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)。

于 2011-07-03T13:08:01.570 回答