mardi 14 décembre 2010

Heritage de tables

En statistique nous sommes souvent confronté à trois grands types de variables:
- Binaire
- Catégorielle (qualitative)
- Quantitative (continue ou discrète).

Lorsque l'on doit stocker ce type de variable dans une base de donnée, il serait tentant d'utiliser trois tables différentes et de stocker le type de la variable dans une table de définition des variables:
-- Définition de la variable (métadonnée)
tblVariable
VarID int;
type int; (1-Binaire, 2-Categorielle, 3-Quantitative)
Code varchar(10)

-- valeur de la variable binaire
tblBinaire
ID int;
VarID int;
Valeur BIT;

-- valeur de la variable catégorielle
tblCategorielle
ID int;
VarID int;
Valeur varchar(10);

-- valeur de la variable quantitative
tblQuantitative
ID int;
VarID int;
Valeur DECIMAL 10.4;

Le problème de cette approche est qu'il est difficile de créer une intégrité référencielle entre la table Variable et les autres tables puisque le type de variable définira avec quelle table on doit faire le lien et donc les ID entre les différentes tables pourront se recouvrir. Il est donc difficile de définir une FOREIGN key entre 3 tables pouvant avoir des ID Identique et une table source...

Une approche plus simple pourrait considérer la table variable comme une table de base dont hérite les autres tables.

CREATE TABLE tblVariable
(
varid SERIAL PRIMARY KEY,
Code varchar(10);
)

CREATE TABLE tblVariableInst
(
id SERIAL PRIMARY KEY, -- idéalement autonumber
varid INT
FOREIGN KEY (varid) REFERENCES tblVariable(varid)
)

CREATE TABLE tblBinaire
(
id INT UNSIGNED PRIMARY KEY NOT NULL,
Valeur BIT,
FOREIGN KEY (id) REFERENCES tblVariableInst(varid)
)

CREATE TABLE tblCategorielle
(
id INT UNSIGNED PRIMARY KEY NOT NULL,
Valeur Varchar(10),
FOREIGN KEY (id) REFERENCES tblVariableInst(varid)
)

CREATE TABLE tblQuantitative
(
id INT UNSIGNED PRIMARY KEY NOT NULL,
Valeur NUMERIC 10.4;
FOREIGN KEY (id) REFERENCES tblVariableInst(varid)
)

Pour créer une nouvelle variable liée à une variable modèle 1234 par exemple.
@var_id=INSERT INTO tblVariableInst (1234) RETURN ID
INSERT INTO tblQuantitative (@var_id, 9.25)

Ces deux lignes devront être placée dans une transaction, pour éviter d'avoir des ID de VarInstance perdu en cas de problème.

L'avantage de cette approche est que l'intégrité référentielle est parfaitement maintenue entre la table de définition tblVariable (métadonnée) et les tables filles.

Rmk: En sql server on utilisera @@IDENTITY_SCOPE pour obtenir l'ID crée dans la table de base. Par contre en PostgreSQL il est possible de demander au INSERT de retourner le dernier ID crée. L'ID crée pour toutes les tables filles est stocké dans la table tblVariableInst (Variable instance) qui contient une clé étrangère sur la table de définition.

vendredi 10 décembre 2010

Comprendre la nullité

La valeur NULL (pour SQL) ne signifie pas 0, FALSE ou chaine vide. Il s'agit d'une erreur classique dans le développement.
NULL signifie indéterminé ou inconnu. Beaucoup de développeurs ont cette incompréhension de l'inconnu.

Exemple:

date
13/10/2010
NULL
13/12/2010

SELECT COUNT(DATE) where DATE<'13/12/2010' retournera 1 et non pas 2.
Car NULL représente une date inconnue et pas une date nulle (par ex 31/12/1899), comme la date est inconnue il est impossible de savoir si elle est plus petite ou plus grande que le 13/12/2010. Un autre exemple, si je dit que Jacques à 32 ans et que Pierre à un age à NULL. Dans ce cas de figure, cela signifie que l'age de Pierre n'a pas été entré dans le système. Si je demande si Jacques est plus vieuw que Pierre la réponse sera je ne sais pas.
=> Comparer un numérique avec un NULL donne un résultat indéterminé.
Si maintenant je ne connais pas l'age d'Alain. Comme savoir si Alain est plus vieux que Pierre, après tout ils ont peut-être le même age.
=> Comparer un NULL avec un NULL donne un résultat indéterminé.

Si j'ajoute l'age d'Alain à celui de Jacques le résultat peut aussi être n'importe quoi et ne sera certainement pas32
NULL{+,-,*,/}Nombre donne un NULL.
Même chose avec les concaténation de chaine de caractères. Concaténer un NULL avec une autre chaîne donne une chaîne indéterminée.

Cas particuliers dans les opérations booléennes:
NULL true=true
NULL & false=false

Toutes les autres opérations incluants des NULL donnent des NULL.

mardi 7 décembre 2010

Eclipse et Tomcat sous Debian lenny

Il y a quelques temps j'ai commencé quelques développements en Java, Tomcat et Postgre SQL sous Debian Lenny. Tout semblait fonctionner pafaitement, je pouvais lancer et arrêter le démon Tomcat à partir d'Eclipse et effectuer du debugging sans problèmes. Toutefois, quelques mise à jour de Lenny plus tard, à chaque tentative de démarrage du démon, je me retrouvais avec le message suivant:

SEVERE: Class loader creation threw exception
java.lang.InternalError: One of the management beans is not compliant.
at java.lang.management.ManagementFactory.getPlatformMBeanServer(libgcj.so.90)
at org.apache.catalina.startup.Bootstrap.createClassLoader(Bootstrap.java:183)
at org.apache.catalina.startup.Bootstrap.initClassLoaders(Bootstrap.java:92)
at org.apache.catalina.startup.Bootstrap.init(Bootstrap.java:207)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:391)
Caused by: javax.management.NotCompliantMBeanException: MBean is not compliant
at mx4j.server.MX4JMBeanServer.registerImpl(MX4JMBeanServer.java:818)
at mx4j.server.MX4JMBeanServer.registerMBeanImpl(MX4JMBeanServer.java:769)
at mx4j.server.MX4JMBeanServer.registerMBean(MX4JMBeanServer.java:753)
at java.lang.management.ManagementFactory.getPlatformMBeanServer(libgcj.so.90)
...4 more


ce qui est assez ennuyeux vous en conviendrez...
Le problème est lié au fait que l'installation du jre effectuée est indépendante de la distribution Debian Lenny. Donc lorsque certaines mise à jour sont effectuées, le jre quant à lui n'est pas remis à jour ce qui peut poser rapidement des problèmes de compatibilités.

Le plus simple est donc d'installer un jre plus récent et plus ... standard.
Le jre par défaut sur Lenny est le gcj (du gnu) qui a l'avantage d'être complètement libre de license, mais qui n'est pas le plus efficient.

Le plus simple est donc d'installer le jre de java.
J'ai opté pour la version: jre-6u22-linux-i586.bin
Le plus simple est de la télécharger dans le répertoire utilisateur.
Ensuite en mode utilisateur:
$chmod a+x jre-6u22-linux-i586.bin
Puis en mode root
#mkdir /usr/java
#cd /usr/java
#/home//jre-6u22-linux-i586.bin
Le fichier va s'extraire tout seul.
Une fois le nouveau JRE installé il faut le faire reconnaître par Eclipse.
Window/Preference/Java/Installed JREs
Cliquer sur ajouter. Donnez le nom jre-6u22-linux-i586 et indiqué le path d'origine /usr/java/jrel-6.0_22
Déselectionnez le JRE gcj et sélectionnez le nouveau.

Aller dans
Window/Preference/Tomcat/JVM setting
dans la combo box, choisir le nouveau JRE jre-6u22-linux-i586
Ajouter un nouveau ClassPath
/usr/java/jrel-6.0_22
Et supprimer l'ancien

Voilà maintenant le démon Tomcat devrait pouvoir être à nouveau piloté par Eclipse et le debugging à nouveau rendu possible...