简体   繁体   English

如何在表中存储互斥值

[英]how to store a mutually exclusive value in a table

Based on social networking design, I need to store whether a person has Liked or Disliked something. 基于社交网络设计,我需要存储一个人LikedDisliked东西。 There are other actions they can take such as Share as well. 他们还可以执行其他操作,例如Share

What I need to do is make sure that when a person Like s something, its value is stored as true . 我需要做的是确保当一个人Like某物时,其值存储为true But if they then change their mind and Dislike the same thing, that the Like 'd value is set to NULL and the Dislike value is set to true . 但是,如果他们随后改变了主意并且对同一件事Dislike Like ,则将Dislike值设置为NULL并将Dislike值设置为true

Initial approach would be a table like this: 初始方法将是这样的表:

UserID (int) | ItemID (int) | Like (bit) | Dislike (bit) | Share (bit) | ...
1              1              1            NULL            NULL
1              2              NULL         1               NULL
1              3              1            NULL            1

The problem here is that if more actions can be taken on an item eg 'Favourited' then I have to add these columns to the table. 这里的问题是,如果可以对某个项目(例如“收藏夹”)采取更多措施,那么我必须将这些列添加到表格中。 This is breaking normalisation rules but it could work. 这违反了规范化规则,但可能有效。 The important business rule is that someone cannot Like and Dislike the same Item at the same time. 重要的业务规则是某人不能同时LikeDislike同一Item Its one or the other. 它一个或另一个。 I guess I would have to do this logical processing on the application end rather than DB end but if there's a better way please do let me know! 我想我将不得不在应用程序端而不是数据库端进行此逻辑处理,但是如果有更好的方法,请告诉我!

The other approach could be to have a table that stores user actions like this: 另一种方法可能是使用一个表来存储用户操作,如下所示:

ActionID | ActionName
1          Like
2          Dislike
3          Share

And then have a linking table like this: 然后有一个这样的链接表:

UserID | ItemID | ActionID
1        1        1
1        1        2
1        1        3

The problem with this second approach is that I think it will be hard to make the Actions mutually exclusive. 第二种方法的问题在于,我认为很难使这些行动相互排斥。 The user has Liked an item, and then Disliked it, and then Shared it. 用户喜欢一个项目,然后不喜欢它,然后共享它。 So in my application I would have to work out which ActionID relates to a Like or Dislike and then depending on which one is chosen, delete the other. 因此,在我的应用程序中,我必须确定哪个ActionID与“喜欢”或“不喜欢”相关,然后根据选择的哪个来删除另一个。 So here I would have to delete the row with an ActionID value of '1' because it is overwritten by the Dislike action with value of '2' 所以在这里,我必须删除ActionID值为'1'的行,因为它被值'2'的Dislike操作覆盖了

Could anyone please advise on what the best way to do this might be? 谁能建议最好的方法是什么? Its the mutual exclusivity between certain actions that is causing me the most bother. 某些行为之间的相互排他性使我最困扰。

Alternatively, you could re-implement it as an integer column and allow (-1, 0, 1) to represent (dislike, neutral, like), which in turn may simplify ranking an item's popularity. 或者,您可以将其重新实现为整数列,并允许(-1、0、1)表示(不喜欢,中立,喜欢),这反过来又可以简化对商品受欢迎程度的排名。 For example, to list the top 10 most liked items: 例如,要列出最喜欢的10个项目:

  select top (10)
         ItemID, sum(ToLikeOrNotLike)
    from Items
group by ItemID
order by sum(ToLikeOrNotLike) desc;

This takes cares of the mutual exclucivity as well. 这也照顾到相互排斥。

Alternative 替代

On a suggestion from Spevy (see comments), the 0 (for no like or dislike) could be replaced with null , so that it's easier to determine overall activity on an item. 根据Spevy的建议(请参阅评论),可以将null (不喜欢或不喜欢) 0替换为null ,以便更轻松地确定项目的总体活动。 For example: 例如:

  select top (10)
         ItemID, count(ToLikeOrNotLike)
    from Items
group by ItemID
order by count(ToLikeOrNotLike) desc;

Would return how many likes or dislikes an item has received. 将返回一个项目已收到多少个喜欢不喜欢的东西。 This can be useful to distinguish between an item with 2 likes and 1 dislikes, and an item with 10,000 likes and 9,999 dislikes, both of which would be otherwise indistinguishable when summed. 这对于区分具有2个喜欢和1个不喜欢的项目与具有10,000个喜欢和9,999个不喜欢的项目很有用,如果将它们加起来,这两者将很难区分。

This is based on your first idea of a table having Boolean columns for separate actions that the user has taken regarding the item. 这是基于您的表的第一个想法,该表具有布尔列,用于用户对项目执行的单独操作。

Use a CHECK constraint on the table (change the table name to whatever your table is really named): 在表上使用CHECK约束(将表名更改为表的实际名称):

ALTER TABLE UserAction 
ADD CONSTRAINT CK_LikeOrDisLike
CHECK (
    (Like is null AND Dislike is null)
    OR (Like = 1 AND Dislike is null)
    OR (Like is null AND Dislike = 1)
)

Or perhaps: 也许:

ALTER TABLE UserAction 
ADD CONSTRAINT CK_LikeOrDisLike
CHECK (
    (ISNULL(Like, 0) = 0 AND ISNULL(Dislike, 0) = 0)
    OR (Like = 1 AND ISNULL(Dislike, 0) = 0)
    OR (ISNULL(Like, 0) = 0 AND Dislike = 1)
)

if you want to allow 0 = false in addition to null = false . 如果除了null = false之外,还希望允许0 = false null = false

This could then further be changed to: 然后可以将其进一步更改为:

ALTER TABLE UserAction 
ADD CONSTRAINT CK_LikeOrDisLike
CHECK (
    ISNULL(Like, 0) = 0 OR ISNULL(Dislike, 0) = 0
)

This last one means that at least one of Like and Dislike must be either false or null. 这最后一个意味着LikeDislike中的至少一个必须为false或null。

This will of course not help you to make consistent updates from your program, you must still handle that separately. 当然,这不会帮助您从程序中进行一致的更新,您仍然必须单独进行处理。 But IF your program tries to make an invalid insert or update, the database will reject it with an error message. 但是, 如果您的程序尝试进​​行无效的插入或更新,则数据库将拒绝它并显示一条错误消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM