2017-09-20 3 views
2

Je travaille sur Cricket Project. J'ai une table OverDetails. Je veux insérer des données dans ce tableau.Un joueur de bowling ne peut pas jouer au cricket deux fois de suite

ID OverNumber BowlerID InningsID 
1  1   150   1 
2  4   160   1 
3  3   165   1 
4  2   150   1 

Row_1, Row_2 et Row_3 sont légales. Row_4 n'est pas légal, car un quilleur ne peut pas à travers deux overs consécutifs en une manches. Il n'est pas nécessaire que les overs soient ajoutés consécutivement dans la base de données.

J'ai ajouté une contrainte dans SQL Server.

# Constraint_1

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

Cette contrainte fonctionne parfaitement.

je besoin d'un chèque comme ceci:

# Constraint_2

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

Vous devez le mettre dans une fonction - la fonction doit renvoyer le dernier identifiant melon de votre table et dans la contrainte vous venez de vérifier s'il est différent de l'identifiant melon que vous voulez insérer – PacoDePaco

+0

qui fonctionnent? Pouvez-vous s'il vous plaît expliquer un peu. Parce que je suis nouveau dans Sql et je ne sais pas beaucoup –

+0

S'il vous plaît lire ma table à nouveau. Il n'est pas nécessaire que les Overs soient ajoutés consécutivement dans la base de données. Dans la deuxième rangée OverNumber est 4 –

Répondre

1

Vous avez besoin d'une fonction qui retourne une dernière BowlerID d'une donnée InningID:

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 

Ensuite, vous pouvez le mettre dans une contrainte de vérification:

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

Le problème est que les lignes sont ajoutées dans le désordre. Comme le dit le PO, dans leur exemple, les rangées 1-3 sont ajoutées en premier, puis la rangée 4 doit être empêchée d'être insérée. Mais cela doit se rapporter aux lignes 1 (et 3, que l'OP n'a pas encore mis en évidence) mais votre fonction serait de sélectionner la ligne 2. –

+0

Oui, je l'ai codé avant de modifier la question et maintenant je dois participer à d'autres affaires – PacoDePaco

+0

@IshtiaqAhmed - est-ce un souci que cela permettrait '(4,2,165,1)' d'être inséré, ce qui signifie que les overs 2 et 3 ont été joués par le même melon? –

0

Peut-être que celui-ci?

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); 
1

Vérifiez les contraintes ne peuvent pas référencer directement d'autres lignes données. Certaines techniques tentent d'utiliser les fonctions définies par l'utilisateur pour contourner cette limitation, mais elles ont tendance à ne pas fonctionner correctement. Surtout dans ce cas où je présume que l'insertion de la rangée 4 devrait également être bloquée si elle avait un bowlerID de 165 puisque cela signifierait que 2 & overs partageait un melon. Au lieu de cela, nous pouvons implémenter ceci avec une paire de vues. Je place habituellement DRI quelque part au nom de vues comme ceci pour indiquer qu'elles sont là pour des raisons d'intégrité référentielle déclarative, pas parce que j'ai l'intention de les interroger.

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) 

Cet insert final génère l'erreur:

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.

Si tout va bien, vous pouvez voir l'astuce j'employer pour faire ces vues vérifier votre contrainte souhaitée - il est mis en place afin que les lignes sont jumelés avec soit leur successeur (logique, basé sur OrderNumber) ou son prédécesseur en divisant le OrderNumber par deux en utilisant des maths entiers. Nous appliquons ensuite des contraintes uniques sur ces paires et notamment BowlerID. Ce n'est que si le même bouliste bols deux overs successifs que nous générons plus d'une ligne avec les mêmes valeurs (OddON/EvenON) et BowlerID.