уникальная проверка ограничений на основе параметра в родительской таблице - PullRequest
0 голосов
/ 15 декабря 2009

Стол Пользователь имеет (userId, scoreType, ...)

@Table(name = "User", uniqueConstraints =
   @UniqueConstraint(columnNames = userId))

- ScoreType может быть либо в баллах, либо в процентах

Таблица UserScore (id, userId, points, percentage)

Я хотел бы предоставить гибкость для хранения либо точек, либо процентов в зависимости от user.scoreType. Поэтому, если ScoreType для пользователя помечен как баллы, мы можем предположить, что в таблице UserScore будут заполнены только баллы, и наоборот.

а. Я предполагаю, что из-за вышеуказанного требования я не смогу добавить проверку nullable = false на UserScore.points или UserScore.percentage.

б. Как мне определить проверку @UniqueConstraint для таблицы UserScore. Должно ли это быть

@Table(name = "UserScore", uniqueConstraints = { 
   @UniqueConstraint(columnNames = userId, points), 
   @UniqueConstraint(columnNames = userId, percentage))

Буду признателен за любые другие точки зрения по этому вопросу

Ответы [ 5 ]

1 голос
/ 15 декабря 2009

а. Я предполагаю, что из-за вышеуказанного требования я не смогу добавить проверку nullable = false на UserScore.points или UserScore.percentage.

Корректное

б. Как определить проверку @UniqueConstraint для таблицы UserScore. Если это будет @Table (name = "UserScore", uniqueConstraints = {@UniqueConstraint (columnNames = userId, points), @UniqueConstraint (columnNames = userId, процент))

Ни то, ни другое не будет работать для бизнес-правил, о которых вы говорили. @UniqueConstraint(columnNames = userId, points) разрешает только уникальные комбинации идентификаторов пользователя и точек; @UniqueConstraint(columnNames = userId, percentage) допускает только уникальные комбинации идентификатора пользователя и процента.

0 голосов
/ 28 декабря 2009

Может быть, вы можете попытаться установить процентное значение по умолчанию для некоторого абсурдного значения, когда типом баллов являются баллы и сделайте то же самое для очков, когда ScoreType - это процент. Сценарий 1: пользователь = Боб, ScoreType = очки

       User= Bob, Points=2.5,Percentage -100000 (Default value for percentage) 

И тогда вы можете определить составной первичный ключ

@ Table (name = "UserScore", uniqueConstraints = { @UniqueConstraint (columnNames = userId, точки, проценты)}

0 голосов
/ 24 декабря 2009

Здесь есть два случая, в зависимости от того, сколько изменений вы можете / можете внести в существующую схему.

Если вы можете изменить схему, самое простое решение здесь состоит в том, чтобы иметь только одно поле и использовать поле 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 (БД, с которой я больше всего знаком), синтаксис для функции триггера будет выглядеть примерно так (для ясности, поля 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;

Надеюсь, одна из этих идей поможет!

0 голосов
/ 23 декабря 2009

Что я читаю из вашего описания, так это то, что у пользователя может быть только одна запись в userScore, и эта запись может содержать только точки или проценты, но не обе. Если это так, таблицы user и userScore должны представлять собой одну таблицу со столбцами userId, points, процент. 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;
0 голосов
/ 22 декабря 2009

Вы можете использовать тот же столбец для пунктов и процентов, как 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...