ORA-00907 :parenthèse droite manquante
Il s'agit de l'un des nombreux messages d'erreur génériques indiquant que notre code contient une ou plusieurs erreurs de syntaxe. Parfois, cela peut signifier que nous avons littéralement omis une parenthèse droite; c'est assez facile à vérifier si nous utilisons un éditeur qui a un crochet de correspondance capacité (la plupart des éditeurs de texte destinés aux codeurs le font). Mais cela signifie souvent que le compilateur a rencontré un mot-clé hors contexte. Ou peut-être s'agit-il d'un mot mal orthographié, d'un espace au lieu d'un trait de soulignement ou d'une virgule manquante.
Malheureusement, les raisons possibles pour lesquelles notre code ne se compile pas sont pratiquement infinies et le compilateur n'est tout simplement pas assez intelligent pour les distinguer. Donc, il lance un message générique, légèrement crypté, comme ORA-00907: missing right parenthesis
et nous laisse le soin de repérer la floraison réelle.
Le script publié comporte plusieurs erreurs de syntaxe. Je vais d'abord discuter de l'erreur qui déclenche cet ORA-0097, mais vous devrez tous les corriger.
Les contraintes de clé étrangère peuvent être déclarées en ligne avec la colonne de référence ou au niveau de la table après que toutes les colonnes ont été déclarées. Ceux-ci ont des syntaxes différentes; vos scripts mélangent les deux et c'est pourquoi vous obtenez l'ORA-00907.
La déclaration en ligne n'a pas de virgule et n'inclut pas le nom de la colonne de référence.
CREATE TABLE historys_T (
history_record VARCHAR2 (8),
customer_id VARCHAR2 (8)
CONSTRAINT historys_T_FK FOREIGN KEY REFERENCES T_customers ON DELETE CASCADE,
order_id VARCHAR2 (10) NOT NULL,
CONSTRAINT fk_order_id_orders REFERENCES orders ON DELETE CASCADE)
Les contraintes au niveau de la table sont un composant distinct. Elles comportent donc une virgule et mentionnent la colonne de référence.
CREATE TABLE historys_T (
history_record VARCHAR2 (8),
customer_id VARCHAR2 (8),
order_id VARCHAR2 (10) NOT NULL,
CONSTRAINT historys_T_FK FOREIGN KEY (customer_id) REFERENCES T_customers ON DELETE CASCADE,
CONSTRAINT fk_order_id_orders FOREIGN KEY (order_id) REFERENCES orders ON DELETE CASCADE)
Voici une liste des autres erreurs de syntaxe :
- La table référencée (et la clé primaire référencée ou la contrainte unique) doivent déjà exister avant que nous puissions créer une clé étrangère contre elles. Vous ne pouvez donc pas créer de clé étrangère pour
HISTORYS_T
avant d'avoir créé lesORDERS
référencés tableau. - Vous avez mal orthographié les noms des tables référencées dans certaines des clauses de clé étrangère (
LIBRARY_T
etFORMAT_T
). - Vous devez fournir une expression dans la clause DEFAULT. Pour les colonnes DATE qui correspondent généralement à la date actuelle,
DATE DEFAULT sysdate
.
Regarder notre propre code avec un œil cool est une compétence que nous devons tous acquérir pour réussir en tant que développeurs. Il est vraiment utile de se familiariser avec la documentation d'Oracle. Une comparaison côte à côte de votre code et des exemples de la référence SQL vous aurait aidé à résoudre ces erreurs de syntaxe en moins de deux jours. Trouvez-le ici (11g) et ici (12c).
En plus des erreurs de syntaxe, vos scripts contiennent des erreurs de conception. Ce ne sont pas des échecs, mais des mauvaises pratiques qui ne doivent pas devenir des habitudes.
- Vous n'avez pas nommé la plupart de vos contraintes. Oracle leur donnera un nom par défaut, mais ce sera horrible et rendra le dictionnaire de données plus difficile à comprendre. Nommer explicitement chaque contrainte nous aide à naviguer dans la base de données physique. Cela conduit également à des messages d'erreur plus compréhensibles lorsque notre SQL déclenche une violation de contrainte.
- Nommez vos contraintes de manière cohérente.
HISTORY_T
a des contraintes appeléeshistorys_T_FK
etfk_order_id_orders
, dont aucun n'est utile. Une convention utile est<child_table>_<parent_table>_fk
. Donchistory_customer_fk
ethistory_order_fk
respectivement. - Il peut être utile de créer les contraintes avec des instructions séparées. Créer des tables puis des clés primaires puis des clés étrangères évitera les problèmes d'ordre des dépendances identifiés ci-dessus.
- Vous essayez de créer des clés étrangères cycliques entre
LIBRARY_T
etFORMATS
. Vous pouvez le faire en créant les contraintes dans une instruction séparée, mais ne le faites pas :vous aurez des problèmes lors de l'insertion de lignes et des problèmes encore pires avec les suppressions. Vous devez reconsidérer votre modèle de données et trouver un moyen de modéliser la relation entre les deux tables afin que l'une soit le parent et l'autre l'enfant. Ou peut-être avez-vous besoin d'un autre type de relation, comme une table d'intersection. - Évitez les lignes vides dans vos scripts. Certains outils les géreront, mais d'autres non. Nous pouvons configurer SQL*Plus pour les gérer, mais il vaut mieux éviter d'en avoir besoin.
- La convention de dénomination de
LIBRARY_T
est laid. Essayez de trouver un nom plus expressif qui ne nécessite pas de suffixe inutile pour éviter un conflit de mots clés. T_CUSTOMERS
est encore plus laid, étant à la fois incohérent avec vos autres tables et complètement inutile, en tant quecustomers
n'est pas un mot-clé.
Nommer les choses est difficile. Vous ne croiriez pas les querelles que j'ai eues à propos des noms de table au fil des ans. La chose la plus importante est la cohérence. Si je regarde un dictionnaire de données et que je vois des tables appelées T_CUSTOMERS
et LIBRARY_T
ma première réponse serait confusion. Pourquoi ces tables sont-elles nommées avec des conventions différentes ? Quelle différence conceptuelle cela exprime-t-il ? Alors, s'il vous plaît, décidez d'une convention de nommage et respectez-la. Faites en sorte que vos noms de table soient tous au singulier ou au pluriel. Évitez autant que possible les préfixes et les suffixes ; nous savons déjà que c'est une table, nous n'avons pas besoin d'un T_
ou un _TAB
.