ИМХО, это в принципе проблема нормализации. Столбец с именем «id» не уникально адресует строку, поэтому он никогда не может быть PK. Необходим как минимум новый (суррогатный) ключ (элемент). Само ограничение не может быть выражено как выражение «в строке», поэтому оно должно быть выражено в терминах FK.
Итак, он разбит на две таблицы:
Один с PK = id и FK, ссылающийся на two.sid
Два с PK = суррогатный ключ и FK id ССЫЛКА one.id
Оригинальная полезная нагрузка "value" также находится здесь.
«Однобитовая переменная» исчезает, потому что она может быть выражена в терминах EXISTS. (фактически таблица 1 указывает на строку, содержащую токен)
[Я ожидаю, что система правил Postgres может использоваться для использования вышеупомянутой модели двух таблиц для эмуляции предполагаемого поведения OP. Но это был бы уродливый взлом ...]
EDIT / UPDATE:
Postgres поддерживает частичные / условные индексы. (не знаю о ms-sql)
DROP TABLE tmp.one;
CREATE TABLE tmp.one
( sid INTEGER NOT NULL PRIMARY KEY -- surrogate key
, id INTEGER NOT NULL
, status INTEGER NOT NULL DEFAULT '0'
/* ... payload */
);
INSERT INTO tmp.one(sid,id,status) VALUES
(1,1,0) , (2,1,1) , (3,1,0)
, (4,2,0) , (5,2,0) , (6,2,1)
, (7,3,0) , (8,3,0) , (9,3,1)
;
CREATE UNIQUE INDEX only_one_non_zero ON tmp.one (id)
WHERE status > 0 -- "partial index"
;
\echo this should succeed
BEGIN ;
UPDATE tmp.one SET status = 0 WHERE sid=2;
UPDATE tmp.one SET status = 1 WHERE sid=1;
COMMIT;
\echo this should fail
BEGIN ;
UPDATE tmp.one SET status = 1 WHERE sid=4;
UPDATE tmp.one SET status = 0 WHERE sid=9;
COMMIT;
SELECT * FROM tmp.one ORDER BY sid;