Мне кажется, я знаю тип создаваемой вами установки.В этих обстоятельствах я обычно определяю свои структуры данных как:
CREATE TABLE DataItems (
DataItemID int IDENTITY(1,1) not null,
Name varchar(10) not null,
TypeRequired varchar(6) not null,
constraint PK_DataItems PRIMARY KEY (DataItemID),
constraint CK_TypeRequired CHECK (TypeRequired in ('STRING','FLOAT','BIT','INT'),
constraint UQ_DataItems_TypeCheck UNIQUE (DataItemID,TypeRequired)
)
Обратите внимание, что я сделал DataItemID,TypeRequired
суперключем, поэтому я могу ссылаться на него в ограничении внешнего ключа.
Теперь в таблице, которая собирает данные:
CREATE TABLE Answers (
AnswerID int IDENTITY(1,1) not null,
/* Other columns to FK to e.g. Client, Users, Session, whatever */
DataItemID int not null,
Type varchar(6) not null,
StringValue varchar(max) null,
FloatValue float null,
BitValue bit null,
IntValue int null,
constraint PK_Answers PRIMARY KEY (AnswerID),
constraint FK_Answers_DataItems FOREIGN KEY (DataItemID) references DataItems (DataItemID),
constraint FK_Answers_DataItems_TypeCheck FOREIGN KEY (DataItemID,Type) references DataItems (DataItemID,TypeRequired),
constraint CK_Answers_TypeCheck CHECK (
(FloatValue is null or TypeRequired = 'FLOAT') and
(StringValue is null or TypeRequired = 'STRING') and
(BitValue is null or TypeRequired = 'BIT') and
(IntValue is null or TypeRequired = 'INT')),
constraint CK_Answers_NotNUll CHECK (
FloatValue is not null or StringValue is not null or BitValue is not null or IntValue is not null)
)
Второе ограничение внешнего ключа гарантирует, что столбец типа соответствует определенному типу для элемента данных, а пара проверочных ограничений гарантирует, что ровно один столбец (иправый столбец) не равен нулю.
Если вам нужно скрыть столбец Тип от пользователей, я бы предложил переименовать приведенную выше таблицу (например, _Answers
), создав представление с триггером вставки:
CREATE VIEW Answers
WITH SCHEMABINDING
AS
SELECT
AnswerID,
DataItemID,
StringValue,
FloatValue,
BitValue,
IntValue
FROM
dbo._Answers
CREATE TRIGGER T_Answers_I
ON Answers
INSTEAD OF INSERT
AS
INSERT INTO _Answers (DataItemID,Type,StringValue,FloatValue,BitValue,IntValue)
SELECT i.DataItemID,di.Type,i.StringValue,i.FloatValue,i.BitValue,i.IntValue
FROM inserted i inner join DataItems di on i.DataItemID = di.DataItemID