表用户有(userId, scoreType, ...)
@Table(name = "User", uniqueConstraints =
@UniqueConstraint(columnNames = userId))
- scoreType可以是积分或百分比
表UserScore (id, userId, points, percentage)
我想提供基于user.scoreType存储点数或百分比的灵活性。因此,如果用户的scoreType被标记为点,我们可以假设UserScore表只填充了点,反之亦然。
一个。我假设由于上述要求,我将无法在UserScore.points或UserScore.percentage上添加nullable = false检查。
湾我应该如何定义@UniqueConstraint
表的UserScore
检查。应该是
@Table(name = "UserScore", uniqueConstraints = {
@UniqueConstraint(columnNames = userId, points),
@UniqueConstraint(columnNames = userId, percentage))
对此问题上的任何其他观点表示赞赏
答案 0 :(得分:1)
一个。我假设由于上述要求,我将无法在UserScore.points或UserScore.percentage上添加nullable = false检查。
正确
湾我应该如何定义UserScore表的@UniqueConstraint检查。应该是@Table(name =“UserScore”,uniqueConstraints = {@UniqueConstraint(columnNames = userId,points),@ UniqueConstraint(columnNames = userId,percentage))
两者都不适用于您所谈论的业务规则。 @UniqueConstraint(columnNames = userId, points)
只允许用户ID和点的唯一组合; @UniqueConstraint(columnNames = userId, percentage)
只允许用户ID和百分比的唯一组合。
答案 1 :(得分:0)
您可以对点和百分比使用相同的列,例如score int
。然后用“假设小数点”存储百分比,比如25.7%score = 257
。有了这个,就不需要约束了。
你也可以将scoreType
移到UserScore
表中,以便为每个用户提供混合评分 - 毕竟,它确实描述了得分。
CREATE TABLE UserScore (
id int
,[userID] int
,scoreType varchar(3)
,score int
)
查询表(SQL服务器)时:
SELECT
id
,[userId]
,CASE scoreType WHEN 'pts' THEN score ELSE 0 END AS points
,CASE scoreType WHEN 'pts' THEN 0.0 ELSE (cast(score AS decimal(4,1)) /10.0) END AS percentage
FROM UserScore
答案 2 :(得分:0)
我从您的描述中读到的是,用户在userScore中只能有一个条目,并且该条目只能包含点数或百分比,但不能同时包含两者。如果是这样,用户和userScore表应该只是一个表,其中包含userId,points,percentage列。 scoreType已经隐式,可以省略。然后使用检查约束来确保只填充一个点和百分比。所以像
CREATE TABLE User (
userId int PRIMARY KEY,
points int,
percentage numeric,
CHECK (points IS NULL OR percentage IS NULL),
CHECK (points IS NOT NULL OR percentage IS NOT NULL) -- if desired
);
如果您真的需要scoreType列,请创建一个视图:
CREATE VIEW UserView AS
SELECT userId,
CASE WHEN points IS NOT NULL THEN 'points'
ELSE 'percentage' END AS scoreType
...
FROM User;
答案 3 :(得分:0)
此处有两种情况,基于您能够/允许在现有架构中引入多少更改。
如果您可以更改架构,这里最简单的解决方案是只有一个字段并使用用户记录中的scoreType字段来确定如何解释数据。如果您的百分比总是小数点后两位,那么您可以像这样创建表格:
CREATE TABLE userScore (
id INT,
userID INT,
scoreValue INT
);
并像这样查询:
SELECT id,
CASE WHEN scoreType = 'points' THEN scoreValue ELSE NULL END as points,
CASE WHEN scoreType = 'percentage' THEN scoreValue / 100.0 ELSE NULL END as percentage
WHERE userID = ?
现在不需要任何类型的约束。
如果用户的scoreType字段可以更改且使用的字段(点数或百分比)将取决于存储分数时scoreType的值 ,则必须将scoreType添加到我的userScore版本中为了保持用每条记录解释数据的规则,因为你不能依赖父记录的一致性(但它确实不需要连接)。
如果您无法更改架构,则可以使用ON INSERT / UPDATE触发器来获取scoreType字段以验证结果记录在正确的字段中是否只有值。在PostgreSQL(我最熟悉的DB)中,触发器函数的语法就是这样的(为清楚起见,v_ *字段是变量/参数):
-- for trigger ON INSERT/UPDATE to userScore
SELECT INTO v_scoreType scoreType FROM user WHERE userID = v_userID;
IF (v_scoreType = 'points' AND NEW.points IS NOT NULL AND NEW.percentage IS NULL)
OR (v_scoreType = 'percentage' AND NEW.points IS NULL AND NEW.percentage IS NOT NULL) THEN
RETURN NEW; -- this record is OK
ELSE
RAISE EXCEPTION 'User Score type is %, tried to set points = % and percentage = %', v_scoreType, NEW.points, NEW.percentage;
END IF;
希望其中一个想法有所帮助!
答案 4 :(得分:0)
当分数类型为分数时,也许您可以尝试将百分比默认为某个荒谬值 当scoreType为百分比时,对点进行相同的操作。 场景1:用户= Bob,ScoreType = Points
User= Bob, Points=2.5,Percentage -100000 (Default value for percentage)
然后您可以定义复合主键
@Table(name =“UserScore”,uniqueConstraints = { @UniqueConstraint(columnNames = userId,points,percentage)}