一个投球手不能在板球比赛中连续两次投球

One Bowler can not bowl two consecutive over in cricket

我正在从事板球项目。我有一个 table OverDetails。我想在这个 table.

中插入数据
ID  OverNumber  BowlerID  InningsID
1       1          150          1
2       4          160          1
3       3          165          1
4       2          150          1

Row_1Row_2Row_3 是合法的。 Row_4 是不合法的,因为一个保龄球手不能在一局中连续两次投球。不必在数据库中连续添加。

我在 SQL 服务器中添加了一个约束。

#Constraint_1

ALTER TABLE OverDetails ADD CONSTRAINT UniqueOverInInning 
UNIQUE(OverNumber, BowlerID, IninngsID);

这个约束非常有效。

我需要这样的支票:

#Constraint_2

ALTER TABLE OverDetails ADD CONSTRAINT UniqueConsecutiveBowlerInOneInning 
CHECK (OverNumber + 1 != OverNumber and BowlerID + 1 != BowlerID 
         and IninngID + 1 != IninngID)

您需要一个函数,它 returns 来自给定 InningID 的最后一个 BowlerID:

    CREATE FUNCTION dbo.GetBowlerID
        ( @InningId INT, @OverNumber INT, @BowlerID INT)
        RETURNS INT
        AS
        BEGIN
        RETURN (SELECT top 1 CASE WHEN
(SELECT BowlerID
    FROM OverDetails 
    WHERE InningsId = @InningId AND OverNumber = @OverNumber - 1 ) = @BowlerID
OR
(SELECT BowlerID
    FROM OverDetails 
    WHERE InningsId = @InningId AND OverNumber = @OverNumber + 1 ) = @BowlerID
THEN 1 else 0 end)
        END

然后你可以把它放入检查约束中:

ALTER TABLE OverDetails ADD CONSTRAINT UniqueConsecutiveBowlerInOneInning 
  CHECK (dbo.GetBowlerID(InningsId, OverNumber, BowlerID)=0)

也许是这个?

create function dbo.chk_fnk (@OverNumber int,  @BowlerID int,  @InningsID int)
returns int
as
begin
return 
      case when
           exists (select * 
                   from dbo.OverDetails
                   where BowlerID = @BowlerID and abs(OverNumber - @OverNumber) = 1 and InningsID = @InningsID)
           then 1
           else 0
      end;  
end;
go

ALTER TABLE dbo.OverDetails ADD CONSTRAINT UniqueConsecutiveBowlerInOneInning 
  CHECK (dbo.chk_fnk(OverNumber,  BowlerID,  InningsID) = 0);

检查约束不能直接引用其他数据。有一些技术试图使用 UDF 来绕过这个限制,但它们往往效果不佳。特别是在这种情况下,我假设如果第 4 行的插入 also 的 bowlerID 为 165,则应该被阻止,因为这意味着 2 和 3 轮共享一个投球手。

相反,我们可以用一对视图来实现它。我通常将 DRI 放在像这样的视图名称中的某处,以表明它们存在是出于声明引用完整性的原因,而不是因为我打算让人们查询它们。

create table dbo.Bowling (
    ID int not null,
    OverNumber int not null,
    BowlerID int not null,
    InningsID int not null,
    constraint PK_Bowling PRIMARY KEY (ID),
    constraint UQ_Bowling_Overs UNIQUE (OverNumber,InningsID)
)
go
create view dbo.Bowling_DRI_SuccessiveOvers_Odd
with schemabinding
as
    select
        (OverNumber/2) as OddON,
        BowlerID
    from
        dbo.Bowling
go
create unique clustered index UQ_Bowling_DRI_SuccessiveOvers_Odd on dbo.Bowling_DRI_SuccessiveOvers_Odd (OddON,BowlerID)
go
create view dbo.Bowling_DRI_SuccessiveOvers_Even
with schemabinding
as
    select
        ((OverNumber+1)/2) as EvenON,
        BowlerID
    from
        dbo.Bowling
go
create unique clustered index UQ_Bowling_DRI_SuccessiveOvers_Even on dbo.Bowling_DRI_SuccessiveOvers_Even (EvenON,BowlerID)
go
insert into dbo.Bowling(ID,OverNumber,BowlerID,InningsID) values
(1,1,150,1),
(2,4,160,1),
(3,3,165,1)
go
insert into dbo.Bowling(ID,OverNumber,BowlerID,InningsID) values
(4,2,150,1)

最后的插入产生错误:

Msg 2601, Level 14, State 1, Line 37 Cannot insert duplicate key row in object 'dbo.Bowling_DRI_SuccessiveOvers_Even' with unique index 'UQ_Bowling_DRI_SuccessiveOvers_Even'. The duplicate key value is (1, 150). The statement has been terminated.

希望您能看到我用来让这些视图检查您想要的约束的技巧 - 它的设置是为了使行与其(逻辑上的,基于 OrderNumber)后继者或前任者配对基于使用整数数学将 OrderNumber 除以二。

然后我们对这些对应用唯一约束,包括 BowlerID。仅当同一个投球手连续两次投球时,我们才会生成具有相同 (OddON/EvenON) 和 BowlerID 值的不止一行。