Précédent   Forum des professionnels en informatique > Bases de données > MS SQL-Server > Développement
Développement Forum d'entraide sur le Transact-SQL, le CLR, les procédures stockées, les triggers, les requêtes SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 22/11/2010, 02h31   #1
Invité régulier
 
Inscription : janvier 2009
Messages : 16
Détails du profil
Informations forums :
Inscription : janvier 2009
Messages : 16
Points : 6
Points : 6
Par défaut Problème de contrainte

Bonsoir à tous,

voici mon souci : Je cherche à empêcher qu'un numéro de facture soit utilisé plus d'une fois pour une même année.

Mon code est donc composé d'une fonction et d'une contrainte check:

FONCTION :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
CREATE FUNCTION checkFNumber(@fnumber varchar(8000), @date datetime) RETURNS INT
AS
BEGIN
	DECLARE @dp int
	SET @dp = DATEPART(year, @date)
	RETURN
	CASE
		WHEN @fnumber NOT IN (SELECT DISTINCT numero FROM Facture WHERE DATEPART(Year, date_facture) = @dp)
		THEN 1
		ELSE 0
	END
END
CONTRAINTE:
Code :
ALTER TABLE Facture ADD CONSTRAINT UniqueFNumberConstraint CHECK (dbo.checkFNumber(numero, date_facture) = 1)
Je tente d'insérer une facture :

Code :
1
2
 
INSERT INTO Facture(numero, date_facture) VALUES('2', GETDATE());
Erreur de SQL Server :
Citation:
Msg*547, Niveau*16, État*0, Ligne*1
L'instruction INSERT est en conflit avec la contrainte CHECK "UniqueFNumberConstraint". Le conflit s'est produit dans la base de données "automobile", table "dbo.Facture".
L'instruction a été arrêtée.
Il n'y a pourtant aucune données dans la table Facture au moment de l'insertion... comment résoudre ce problème de contrainte?

Merci d'avance
MagicTux est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2010, 14h13   #2
Modérateur

 
Avatar de elsuket
 
Homme Nicolas Souquet
Administrateur de base de données
Inscription : janvier 2005
Messages : 4 658
Détails du profil
Informations personnelles :
Nom : Homme Nicolas Souquet
Âge : 30
Localisation : Thaïlande

Informations professionnelles :
Activité : Administrateur de base de données
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : janvier 2005
Messages : 4 658
Points : 8 687
Points : 8 687
Bonjour,

Il aurait fallu remplacer par < 2, mais le mieux reste de mettre une contrainte d'unicité, qui est faite exactement pour cela.
Vous aurez donc besoin d'une colonne calculée qui vous retourne l'année :

Code :
1
2
ALTER TABLE dbo.Facture 
ADD annee_facture AS (YEAR(date_facture))
Et la contrainte d'unicité devient alors :

Code :
1
2
ALTER TABLE dbo.Facture 
ADD CONSTRAINT UQ_Facture__annee_facture__numero UNIQUE (annee_facture, numero)
Ce sera en outre bien moins coûteux que d'appeler la fonction

@++
__________________
En bases de données relationnelles SQL, il n'y a ni tableaux, ni enregistrements, ni champs: il y a des tables, des lignes et des colonnes.
Blog | Profil| Consulter ou télécharger les fichiers d'aide de SQL Server, des versions 2000 à 2012
elsuket est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 22/11/2010, 21h13   #3
Invité régulier
 
Inscription : janvier 2009
Messages : 16
Détails du profil
Informations forums :
Inscription : janvier 2009
Messages : 16
Points : 6
Points : 6
Citation:
Il aurait fallu remplacer par < 2
Que veux tu dire par ça?

En tout cas merci, cette autre solution fonctionne à merveille.
MagicTux est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2010, 00h42   #4
Modérateur

 
Avatar de elsuket
 
Homme Nicolas Souquet
Administrateur de base de données
Inscription : janvier 2005
Messages : 4 658
Détails du profil
Informations personnelles :
Nom : Homme Nicolas Souquet
Âge : 30
Localisation : Thaïlande

Informations professionnelles :
Activité : Administrateur de base de données
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : janvier 2005
Messages : 4 658
Points : 8 687
Points : 8 687
En fait, < 2 ne fonctionnera pas non plus.
Donc en supposant que les contraintes d'unicité n'existent pas, il aurait mieux valu écrire :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CREATE FUNCTION checkFNumber
	(
		@fnumber varchar(8000)
		, @date datetime
	) 
RETURNS bit
AS
BEGIN
	DECLARE @result bit
	SET @result = 1
 
	IF EXISTS
	(
		SELECT	*
		FROM	dbo.Facture
		WHERE	date_facture BETWEEN CAST(YEAR(@date) + '0101' AS datetime) AND CAST(YEAR(@date) + '1231' AS datetime)
		AND	numero = @fnumber
	)
	SET @result = 0
 
	RETURN @result
END
Et votre contrainte aurait alors été :

Code :
1
2
3
ALTER TABLE dbo.Facture
ADD CONSTRAINT UniqueFNumberConstraint
CHECK (dbo.checkFNumber(numero, date_facture) = 1)
C'est à dire inchangée, mais le comportement correct

@++
__________________
En bases de données relationnelles SQL, il n'y a ni tableaux, ni enregistrements, ni champs: il y a des tables, des lignes et des colonnes.
Blog | Profil| Consulter ou télécharger les fichiers d'aide de SQL Server, des versions 2000 à 2012
elsuket est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 03h22.


 
 
 
 
Partenaires

Hébergement Web