ORA-00907:höger parentes saknas
Detta är ett av flera allmänna felmeddelanden som indikerar att vår kod innehåller ett eller flera syntaxfel. Ibland kan det betyda att vi bokstavligen har utelämnat en höger parentes; det är lätt nog att verifiera om vi använder en redigerare som har en matchningsparentes förmåga (de flesta textredigerare som är riktade till kodare gör det). Men ofta betyder det att kompilatorn har stött på ett nyckelord ur sitt sammanhang. Eller så kanske det är ett felstavat ord, ett mellanslag istället för ett understreck eller ett kommatecken.
Tyvärr är de möjliga orsakerna till att vår kod inte kommer att kompilera praktiskt taget oändliga och kompilatorn är helt enkelt inte smart nog att skilja dem åt. Så det sänder ett allmänt, lite kryptiskt meddelande som ORA-00907: missing right parenthesis
och överlåter åt oss att upptäcka själva blomningen.
Det upplagda skriptet har flera syntaxfel. Först kommer jag att diskutera felet som utlöser den där ORA-0097 men du måste fixa dem alla.
Utländska nyckelbegränsningar kan deklareras i linje med referenskolumnen eller på tabellnivå efter att alla kolumner har deklarerats. Dessa har olika syntaxer; dina skript blandar de två och det är därför du skaffar ORA-00907.
In-line-deklarationen har inget kommatecken och innehåller inte referenskolumnnamnet.
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)
Tabellnivåbegränsningar är en separat komponent, och har därför ett kommatecken och nämner referenskolumnen.
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)
Här är en lista över andra syntaxfel:
- Den refererade tabellen (och den refererade primärnyckeln eller unika begränsningen) måste redan existera innan vi kan skapa en främmande nyckel mot dem. Så du kan inte skapa en främmande nyckel för
HISTORYS_T
innan du har skapat den refereradeORDERS
tabell. - Du har stavat namnen på de refererade tabellerna fel i några av de främmande nyckelsatserna (
LIBRARY_T
ochFORMAT_T
). - Du måste ange ett uttryck i DEFAULT-satsen. För DATE-kolumner som vanligtvis är det aktuella datumet,
DATE DEFAULT sysdate
.
Att titta på vår egen kod med ett kallt öga är en färdighet vi alla behöver skaffa oss för att bli framgångsrika som utvecklare. Det hjälper verkligen att vara bekant med Oracles dokumentation. En jämförelse sida vid sida av din kod och exemplen i SQL Reference skulle ha hjälpt dig att lösa dessa syntaxfel på betydligt mindre än två dagar. Hitta den här (11g) och här (12c).
Förutom syntaxfel innehåller dina skript designfel. Dessa är inte misslyckanden, utan dålig praxis som inte bör bli vanor.
- Du har inte nämnt de flesta av dina begränsningar. Oracle kommer att ge dem ett standardnamn men det kommer att vara ett hemskt namn och gör dataordboken svårare att förstå. Att uttryckligen namnge varje begränsning hjälper oss att navigera i den fysiska databasen. Det leder också till mer begripliga felmeddelanden när vår SQL löser en begränsningsöverträdelse.
- Namn dina begränsningar konsekvent.
HISTORY_T
har begränsningar som kallashistorys_T_FK
ochfk_order_id_orders
, vilket inte är till hjälp. En användbar konvention är<child_table>_<parent_table>_fk
. Såhistory_customer_fk
ochhistory_order_fk
respektive. - Det kan vara användbart att skapa begränsningarna med separata satser. Genom att skapa tabeller och sedan primärnycklar och sedan främmande nycklar undviker du problemen med beroendeordning som identifierats ovan.
- Du försöker skapa cykliska främmande nycklar mellan
LIBRARY_T
ochFORMATS
. Du kan göra detta genom att skapa begränsningarna i separata uttalanden men gör det inte:du kommer att få problem när du infogar rader och ännu värre problem med borttagningar. Du bör ompröva din datamodell och hitta ett sätt att modellera förhållandet mellan de två tabellerna så att den ena är föräldern och den andra barnet. Eller så kanske du behöver en annan typ av relation, till exempel en skärningstabell. - Undvik tomma rader i dina skript. Vissa verktyg kommer att hantera dem men andra inte. Vi kan konfigurera SQL*Plus för att hantera dem, men det är bättre att undvika behovet.
- Namnkonventionen för
LIBRARY_T
är ful. Försök att hitta ett mer uttrycksfullt namn som inte kräver ett onödigt suffix för att undvika en sökordskrock. T_CUSTOMERS
är ännu fulare, är både inkonsekvent med dina andra tabeller och helt onödigt, somcustomers
är inte ett sökord.
Att namnge saker är svårt. Du skulle inte tro de bråk jag har haft om bordsnamn genom åren. Det viktigaste är konsekvens. Om jag tittar på en dataordbok och ser tabeller som heter T_CUSTOMERS
och LIBRARY_T
mitt första svar skulle vara förvirring. Varför namnges dessa tabeller med olika konventioner? Vilken konceptuell skillnad uttrycker detta? Så snälla, bestäm dig för en namnkonvention och håll dig till. Gör dina tabellnamn till antingen singular eller plural. Undvik prefix och suffix så mycket som möjligt; vi vet redan att det är en tabell, vi behöver ingen T_
eller en _TAB
.