表上的多维搜索

发布于 2024-11-18 12:41:40 字数 1466 浏览 4 评论 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>)

我 按预期工作,[和+(或)]组合让我认为这不是正确的方法。我也相当确定,一旦数据集增加,查询将无法很好地执行。

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

更新

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

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

I have the following table that stores the preferences of the users in the system

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 |

I would like to search this based on user provided search values. So if one searches for

City: NYC, Brand: Tide

the output should be:

    A    | Soap      | Tide      | NYC       |
    B    | Dont-Care | Tide      | Dont-care |

where as if they search for

Brand: Tide, Product: Soap

the result should be:

    A    | Soap      | Tide      | NYC       |

The current solution I have, is the following query (where null represents 'don't care') going against a MySQL table:

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

Though it works as expected, the [and + (or)] combination makes me think this is not the right way to do this. I am also fairly certain that once the dataset increases, the query will not perform well.

What would be most efficient way of storing and retrieving such data? Are there any no-sql type approaches that can be used to make this efficient?

Update

After some googling around I figured the approach I have may be the safest bet. One factor I still am ambivalent about with this approach is that adding another 'searchable' attribute would mean adding a new column.

This blog about the EAV anti-pattern provides some good reading material on such a scheme. Also see how friend-feed uses MySQL for another take on storing variable attributes in a table.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寂寞美少年 2024-11-25 12:41:40

您可以使用 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>

You could use the IFNULL() function.

It would be something like this:

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>
辞慾 2024-11-25 12:41:40

基于@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 是检查 null 值的函数,请将 nvl() 替换为 ifnull()

@Pompom6784 您必须应用 ifnull上<用户提供的价值>不在列值上..

based on @Pompom6784's answer -

but logically it has very different
conditions-

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)

I am a oracle pl sql developer so please check above query having syntex of oracle sql..
if in your database ifnull is the function to check for null values please replace nvl() with ifnull()

@Pompom6784 you had to apply ifnull on < user provided value > not on column values ..

娇俏 2024-11-25 12:41:40

既然您问如何存储此类数据,那么我可能会这样做:

            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 的用户他们的肥皂和第二组是那些更喜欢纽约市作为其城市的人,您可以将这两个组联合起来:

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

但当然,这种结构也允许不使用联合的查询。

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

Since you ask how to store such data, here's what I'd probably do:

            USERS
            userid  PK
            name
            etc


            PREFTYPES
            preftypeid  PK
            prefname



           PREFTYPEVALUES
           preftypeid  foreign key references PREFTYPES(preftypeid)
           value

           composite primary key (preftypeid, value)

PREFTYPEVALUES table above lets you constrain the possible value-entries in the USERPREFS table:

            USERPREFS
            userid      foreign key references USERS(userid)
            preftypeid  
            value

           => composite  foreign key(preftypeid, value) references PREFTYPEVALUES(preftypeid, value)

To combine the two sets of users, the first set being those who prefer Tide for their soap and the second set being those who prefer NYC as their city, you could UNION the two sets:

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

but this structure would also permit queries that do not use UNION, of course.

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

I bet your next question would be: how to get a single row for each user, with the user's preferences side-by-side?

              user-A, Tide, NYC

That denormalization is better left to the presentation layer, although it can be done in SQL using a variety of inelegant approaches. The SQL key here is composite (user,preftype).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文