IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MS SQL Server Discussion :

clé primaire nvarchar(50) par concatenation


Sujet :

MS SQL Server

  1. #1
    Membre régulier
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    270
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 270
    Points : 123
    Points
    123
    Par défaut clé primaire nvarchar(50) par concatenation
    Bonsoir!
    Je souhaiterais fabriquer des clé primaire à partir de la concatenation de deux champs de la même table (PANIER).

    Cette table est composé de trois collone :
    1 - ID
    2 - PANIER_NOM
    3 - USER_ID (qui est le résultat de la commande USER_NAME(USER_ID))

    Le fait d'avoir comme clé primaire la concaténation du nom de mon panier + l'indentifiant utilisateur me permettrais qu'il n'existe pas deux panier avec le meme nom.

    Pour cela j'ai créer un trigger :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    ALTER TRIGGER [testconctat] 
    ON [dbo].[PANIER]
     
    FOR INSERT, UPDATE
    AS 
    DECLARE @panierId nvarchar(50),@nomPanier nvarchar(50), @userId nvarchar(50);
     
    select @userId = user_ID from INSERTED;
    select @nomPanier = PANIER_NOM from INSERTED;
    select @panierId = @userId + @nomPanier;
     
    BEGIN 
    UPDATE dbo.PANIER  set PANIER_ID=@panierId 
    where PANIER_NOM in (select PANIER_NOM from inserted)
    END
    dès lors que je veux créer une nouvelle entrée SQL SERVER m'envoie gentillement boulé en me disant qu'une clé primaire ne peu avoir de valeur nulle.

    Or si je fait ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    insert into PANIER(PANIER_ID,PANIER_NOM) values ('uncaratere','monpanier')
    select * from PANIER
    Ca marche
    Peut pourriez vous me dire quelle est mon erreur?
    Merci d'avance

  2. #2
    Membre régulier
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    270
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 270
    Points : 123
    Points
    123
    Par défaut
    J'ai trouvé j'ai rajouté la contrainte que voici
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ALTER TABLE dbo.PANIER
    ADD CONSTRAINT CONCAT_INDEX DEFAULT ('uncaractere') FOR PANIER_ID
    En espérant que ca serve à quelqu'un

  3. #3
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Bonjour,

    Je souhaiterais fabriquer des clé primaire à partir de la concatenation de deux champs de la même table (PANIER).
    C'est une des pires erreurs : toute valeur dans une base de données doit être atomique.
    En ce sens toute valeur ne peut être composée de "sous-valeurs", d'une quelconque façon que ce soit.
    De la même façon toute valeur ne peut dépendre de la valeur de clé primaire d'une table.

    De plus je vous ai montré dans ce sujet que la façon dont vous écrivez votre trigger est fausse parce qu'elle n'est pas ensembliste.
    Sous SQL Server, en aucun cas dans un trigger vous ne devez déclarer des variables qui reçoivent des valeurs des tables virtuelles INSERTED ou DELETED, ni de la table à laquelle est attachée le trigger.
    Je montre ici pourquoi cela est faux au sens SQL et au sens du traitement, et les erreurs auxquelles cela conduit

    Pourquoi avez-vous choisi le type nvarchar ?
    Allez-vous stocker des caractères non-latins ?

    dès lors que je veux créer une nouvelle entrée SQL SERVER m'envoie gentillement boulé en me disant qu'une clé primaire ne peu avoir de valeur nulle.
    Une première chose : NULL n'est pas une valeur.
    C'est un marqueur qui signifie l'absence de valeur.
    Faites le test suivant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    IF NULL = NULL
    	PRINT 'OK'
    ELSE
    	PRINT 'KO'
    NULL n'est pas égal à lui même, ce qui prouve que ce n'est pas une valeur (au moins au sens SQL ).
    Si vous autorisez une clé primaire à ne pas avoir de valeur, comment voulez-vous identifier une ligne dans votre table ?
    Cela conduit en plus à la possibilité de doublons, ce qui ne doit jamais se produire dans une base de données relationnelle SQL.


    Je pense que vous concevez mal votre base de données, et que vous n'avez pas au moins fait le dessin des entités qui participent au modèle conceptuel de celle-ci.
    La clé primaire de votre table panier doit être identifiante d'un panier, comme pour celle d'un utilisateur.
    Vous devriez avoir une table de sessions utilisateurs qui associe un utilisateur avec une date et un statut (ouvert ou fermé).
    Votre application devrait alors vérifier que tout utilisateur a bien une session ouverte.
    Dans votre table panier, vous ne devriez pas référencer l'utilisateur, mais la session.
    Cela vous permettrait de plus d'avoir un historique puissant de qui s'est exactement passé sur votre site.


    N'utilisez jamais de clés primaires de type chaîne de caractère.

    En effet, sous SQL Server, pour toute clé primaire, un index cluster est créé, de façon à garantir l'intégrité des données, mais aussi à accélérer les jointures.
    La valeur de l'index cluster est "copiée" dans les index non-cluster de la table, qui vous permettent principalement d'accélérer les recherches sur cette table à partir des filtres de la clause WHERE de vos requêtes.

    En utilisant un clé primaire de type chaîne de caractère, vous favorisez la fragmentation de tous les index, puisque les valeurs prises par la clé primaire ne sont pas consécutives, décélérant donc les recherches puisque plus de pages doivent être parcourues pour obtenir la même réponse.

    Ensuite, tout caractère utilise au moins un octet.
    Le type INT permet une plage de 4.294.967.295 valeurs sur seulement 4 octets.
    Si cela n'est pas suffisant, vous avez le type BIGINT (8 octets), qui lui autorise une plage de 18.446.744.073.709.551.615 valeurs, ce qui devrait être suffisant.
    Vous vous rendez donc compte des avantages des types entiers.

    Enfin, lorsque vous effectuez des jointures sur une valeur de type chaîne de caractère, cela oblige le moteur de base de données à comparer des chaînes, ce qui est bien plus long que de comparer des entiers, surtout si vous utilisez une collation qui n'est pas binaire ou qui est insensible aux accents et/ou à la casse.

    J'ai trouvé j'ai rajouté la contrainte que voici

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ALTER TABLE dbo.PANIER
    ADD CONSTRAINT CONCAT_INDEX DEFAULT ('uncaractere') FOR PANIER_ID
    En espérant que ca serve à quelqu'un
    J'espère que non !

    Voici donc ce que je vous propose :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    CREATE TABLE utilisateur
    (
    	utilisateur_id int NOT NULL IDENTITY CONSTRAINT PK_Utilisateur PRIMARY KEY, 
    	, utilisateur_autreCaracteristiques autresTypes
    )
     
    CREATE TABLE utilisateur_session
    (
    	utilisateur_session_id int NOT NULL IDENTITY CONSTRAINT PK_utilisateur_session  PRIMARY KEY,
    	utilisateur_id int NOT NULL CONSTRAINT FK_utilisateur_session__utilisateur_id FOREIGN KEY (utilisateur_id) REFERENCES dbo.utilisateur,
    	time_stamp datetime NOT NULL CONSTRAINT DF_utilisateur_session__date_session DEFAULT (GETDATE()),
    	statut_session bit NOT NULL, -- 0 fermée, 1 ouverte, par exemple
    )
     
    CREATE TABLE Panier
    (
    	panier_id int NOT NULL IDENTITY CONSTRAINT PK_Panier PRIMARY KEY,
    	utilisateur_session_id int NOT NULL CONSTRAINT FK_Panier__utilisateur_session_id FOREIGN KEY (utilisateur_session_id) REFERENCES utilisateur_session,
    	commande_id int NOT NULL IDENTITY CONSTRAINT FK_Panier__commande_id FOREIGN KEY(commande_id) REFERENCES commande,
    	...
    )
    Il manque les index non-cluster, je vous laisse le soin de les rajouter

    @++

  4. #4
    Membre régulier
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    270
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 270
    Points : 123
    Points
    123
    Par défaut
    Je vous remercie de me répondre toujours aussi rapidement.
    Je vous avoue que je suis novice en SQL (étudiant) et que tout ce dont j'ai appris cette année ne suffit clairement pas. Disons que nous avons fait en classe tout un semestre sur l'algebre relationnel sans même parler de language sql et que les règles que vous m'avez cité non malheureusement pas été abordées(c'est pas faute d'avori suivi).

    A vraix dire la base de données que je suis en train de mettre au point est dans le cadre d'un mini-projet pour mes études. Je vous crois sur parole sur les risques de fragmentation. Mais malheureusement mon prof qui en à décidé ainsi.

    Le sujet de ce projet consiste en la synchronisation de deux version d'une même base (version production et développement).

    la base de production contient trois table de plus qui sont :
    PANIER, PANIER_DUPLIQUES, SERIES_DUPLIQUEES

    Pour ce qui est de la table panier les consignes sont :

    La table PANIER contient l’identifiant Windows de la personne à qui appartient le panier (utile pour la confidentialité). La table contient aussi le nom du panier. L’identifiant est généré automatiquement à la création d’un panier : c’est la concaténation de l’identifiant Windows et du nom de panier donné par l’utilisateur. Cette méthode assure l’unicité de l’identifiant du panier tant que un utilisateur n’essaie pas de créer un panier portant le même nom qu’un de ses panier déjà existant. Ceci lui est de toute façon refusé.
    Voila donc le pourquoi de mes requettes.
    Je vous remerci encore

  5. #5
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Je vous remercie de me répondre toujours aussi rapidement.
    Avec plaisir

    Je vous avoue que je suis novice en SQL (étudiant) et que tout ce dont j'ai appris cette année ne suffit clairement pas. Disons que nous avons fait en classe tout un semestre sur l'algebre relationnel sans même parler de language sql et que les règles que vous m'avez cité non malheureusement pas été abordées(c'est pas faute d'avori suivi ).
    L'algèbre relationnelle est très importante.
    En revanche je vous avoue qu'en sortant de l'IUT j'étais également peu formé aux problèmes de performances.
    Cela dit nombre d'entre eux viennent du modèle de données.
    Si vous avez un modèle de données bien pensé, les problèmes de performances viennent principalement de l'indexation, parce que vos requêtes s'expriment simplement, pour vous comme pour le moteur de bases de données.

    L’identifiant est généré automatiquement à la création d’un panier : c’est la concaténation de l’identifiant Windows et du nom de panier donné par l’utilisateur
    Quelle horreur ! et dire qu'on vous enseigne cela !
    Je ne vous encourage pas à sécher, mais si c'est pour entendre pareilles sottises ...

    Cette méthode assure l’unicité de l’identifiant du panier tant que un utilisateur n’essaie pas de créer un panier portant le même nom qu’un de ses panier déjà existant
    Une phrase perturbante pour l'étudiant; drôle pour quelqu'un ayant un peu d'expérience

    Voila donc le pourquoi de mes requettes.
    Je vous remerci encore
    Je comprends mieux maintenant. A bientôt sur le forum !

    @++

Discussions similaires

  1. Clés primaires mal gérées par RoR
    Par dancingmad dans le forum Ruby on Rails
    Réponses: 2
    Dernier message: 10/08/2009, 10h00
  2. création de variable par concatenation
    Par donnie62 dans le forum ActionScript 3
    Réponses: 3
    Dernier message: 22/05/2008, 17h00
  3. Réponses: 3
    Dernier message: 19/04/2007, 21h55
  4. Import data d'Excel ds 2 table lié par clé primaire
    Par lord_paco dans le forum MS SQL Server
    Réponses: 11
    Dernier message: 10/05/2005, 09h31
  5. Retirer une clé primaire par code
    Par Arrown dans le forum Bases de données
    Réponses: 3
    Dernier message: 28/07/2004, 15h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo