【问题标题】:How to create a column null or not-null dependent on the value of another column?如何根据另一列的值创建空列或非空列?
【发布时间】:2019-09-06 01:53:05
【问题描述】:

我正在使用 EF 核心的数据库优先方法,并试图找出解决以下问题的干净解决方案 -

考虑下面的学生出勤表(不相关的列已删除),该表存储上课日期并允许学生输入他的班级评分 -

create table Student (
    Id int Identity(1, 1) not null,
    ClassDate smalldatetime not null,
    ClassRatingByStudent varchar(250) not null
) 

这是一个网络应用程序,学校出勤系统会在 EOD 时自动填充上表,然后要求学生(比如说几天后)添加班级评分。当表由学校出勤系统填充时,ClassRatingByStudent 列中没有任何内容。那么当学生登录时,他必须添加评分。

如您所见,当学校出勤系统填充表时,ClassRatingByStudent 必须为空,而当学生保存他的更改时,ClassRatingByStudent 必须为非空。一个明显的解决方案是让 ClassRatingByStudent 列可空广告在代码中处理它,但我想知道是否存在更简洁的数据库(或者可能是 EF)级别的解决方案,或者针对此类场景的某种模式/架构指南?

【问题讨论】:

  • 我会用代码来做。
  • 我会将ClassRatingByStudent 定义为NULL 并编程系统以将该列中的NULL 值解释为学生尚未填写评分的指示符。这里NULL值带有特定的含义。

标签: sql-server db-first


【解决方案1】:

我不知道,但也许 CHECK 约束可以帮助你:

CREATE TABLE TestTable(
  ID int NOT NULL IDENTITY,
  RatingAllowed bit NOT NULL DEFAULT 0, -- switcher
  RatingValue varchar(250),
CONSTRAINT PK_TestTable PRIMARY KEY(ID),
CONSTRAINT CK_TestTable_RatingValue CHECK( -- constraint
                    CASE
                      WHEN RatingAllowed=0 AND RatingValue IS NULL THEN 1
                      WHEN RatingAllowed=1 AND RatingValue IS NOT NULL THEN 1
                      ELSE 0
                    END=1
                 )
)

INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,NULL)
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,'AAA')

-- The INSERT statement conflicted with the CHECK constraint "CK_TestTable_RatingValue"
INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,'AAA')
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,NULL)

【讨论】:

    【解决方案2】:

    我发现了一个变体,如何使用另一个表作为切换器进行检查

    CREATE TABLE TableA(
      ID int NOT NULL IDENTITY PRIMARY KEY,
      StudentID int NOT NULL,
      Grade int
    )
    
    CREATE TABLE TableB(
      StudentID int NOT NULL PRIMARY KEY
    )
    GO
    
    -- auxiliary function
    CREATE FUNCTION GradeIsAllowed(@StudentID int)
    RETURNS bit
    BEGIN
      DECLARE @Result bit=CASE WHEN EXISTS(SELECT * FROM TableB WHERE StudentID=@StudentID) THEN 1 ELSE 0 END
      RETURN @Result
    END
    GO
    
    -- constraint to check
    ALTER TABLE TableA ADD CONSTRAINT CK_TableA_Grade CHECK(
                    CASE dbo.GradeIsAllowed(StudentID) -- then we can use the function here
                      WHEN 1 THEN CASE WHEN Grade IS NOT NULL THEN 1 ELSE 0 END
                      WHEN 0 THEN CASE WHEN Grade IS NULL THEN 1 ELSE 0 END
                    END=1)
    GO
    
    -- Tests
    INSERT TableB(StudentID)VALUES(2) -- allowed student
    
    INSERT TableA(StudentID,Grade)VALUES(1,NULL) -- OK
    INSERT TableA(StudentID,Grade)VALUES(2,5) -- OK
    
    INSERT TableA(StudentID,Grade)VALUES(1,4) -- Error
    INSERT TableA(StudentID,Grade)VALUES(2,NULL) -- Error
    
    INSERT TableB(StudentID)VALUES(1) -- add 1
    
    UPDATE TableA SET Grade=4 WHERE StudentID=1 -- OK
    UPDATE TableA SET Grade=NULL WHERE StudentID=1 -- Error
    

    【讨论】:

      猜你喜欢
      • 2019-11-21
      • 2021-12-02
      • 1970-01-01
      • 2021-03-30
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 2023-02-23
      • 2015-12-20
      相关资源
      最近更新 更多