Здесь есть два случая, в зависимости от того, сколько изменений вы можете / можете внести в существующую схему.
Если вы можете изменить схему, самое простое решение здесь состоит в том, чтобы иметь только одно поле и использовать поле 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;
Надеюсь, одна из этих идей поможет!