[SQL] Comportement jointure sur clé de type varchar

Comportement jointure sur clé de type varchar [SQL] - SQL/NoSQL - Programmation

Marsh Posté le 26-03-2009 à 19:14:19    

Bonjour,
 
Les jointures sur des clés VARCHAR ont-elles des particularités par rapport à celle sur des INT?
 
http://en.wikipedia.org/wiki/Join_(SQL)
 
Dans l'exemple décrit ci-dessus, tout marche nikel sur des clés de type INT.
Si on passe DepartmentID en type VARCHAR(20) dans les deux cas, j'obtiens un comportement assez bizarre:
si dans une des 2 tables, une des clé finie par un espace et est donc par conséquent différente de son homologue dans l'autre table, une requête avec jointure me renverra quand même la ligne comme si les deux valeurs étaient toujours identiques!
 
Par exemple, si on change dans la table Employee le "31" en "31 " (ou même "31    ", peu importe le nombre d'espace), j'obtiens quand même les mêmes valeurs qu'avant la modif de donnée.
 
Quelqu'un pourrait me détailler ce qu'il se passe exactement (je suppose que ce comportement est normal, j'ai vérifié sur MSSQL 2000/2005 et MYSQL)?
Je sais que c'est pas génial d'utiliser des clés VARCHAR, mais je pensais que c'était uniquement dû aux pertes de perfos?
 
Merci!


---------------
XBL : ESN3S | GGPO (3rd strike) : ESN | PSN : Huitxilopochti
Reply

Marsh Posté le 26-03-2009 à 19:14:19   

Reply

Marsh Posté le 26-03-2009 à 20:10:50    

Bonjour,
 
Faire des jointures sur un varchar n'est pas du tout un problème si :
 - Soit tu as un SGBD qui te permet de définir les FK et que tu respectes FK subset PK
 - Soit tu as manuellement fixé un index sur le champ cible (et, dépendant du SGBD, sur le champ source, comme en Mysql par ex).
 
Dans ces deux situations, tu auras les mêmes performances que s'il s'agissait d'un int.
 
 
Pour répondre à ta question de comparaison de chaines, voici un extrait de la doc mysql 5 :  
"Les valeurs contenues dans les colonnes de type VARCHAR sont de tailles variables. Vous pouvez déclarer une colonne VARCHAR pour que sa taille soit comprise entre 1 et 255, exactement comme pour les colonnes CHAR. Par contre, contrairement à CHAR, les valeurs de VARCHAR sont stockées en utilisant autant de caractères que nécessaire, plus un octet pour mémoriser la longueur. Les valeurs ne sont pas complétées. Au contraire, les espaces finaux sont supprimés avant stockage"

Reply

Marsh Posté le 27-03-2009 à 17:44:16    

Merci!
 
Ça explique effectivement ce comportement. Par contre, je trouve ça vraiment étrange, le SDGB zappant volontairement les espaces en fin de mot si ils sont stockés en VARCHAR. D'autant plus que ces espaces sont quand même présents en base, juste qu'ils ne sont pas interprétés lors des opérations sur ces champs (fonction LEN, une simple clause where <champ> = 'valeur '). On ne peut donc pas faire, simplement, de vraie (stricte) comparaison de chaîne directement avec le SDGB (sous entendu avec ce type VARCHAR)?
 
Pour ça j'ai été obligé de faire une magouille du genre
WHERE <champ> = <champ > AND REVERSE(<champ> ) = REVERSE(<champ > )
 
Un peu trop bidouille à mon gout...


Message édité par En_Sabah_Nur le 27-03-2009 à 17:55:30

---------------
XBL : ESN3S | GGPO (3rd strike) : ESN | PSN : Huitxilopochti
Reply

Marsh Posté le 27-03-2009 à 18:20:28    

Si la chaine contient un retour à la ligne ou un caractère 0 binaire, alors elle sera tronquée jusqu'à ce caractère. C'est pour cela que les mots de passes cryptés sont stockés dans des champs de type char() au lieu de varchar(), car les champs de type char() conservent leur contenu intact, même s'il y a des espaces au bout ou du code non imprimable.

Reply

Marsh Posté le 27-03-2009 à 20:30:41    

Le problème avec char, c'est que c'est un type paramétré (en longueur), et que tout ce qui est stocké dedans est automatiquement complété par des espaces pour occuper la longueur fournie en paramètre initialement.  
 
Sinon, effectivement, le fait d'ignorer les espaces ne respecte pas la norme ANSI.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed