Getting 'ORA-00907: missing right parenthesis', cannot find error - sql

After running my script in Oracle I am getting the error code 'ORA-00907: missing right parenthesis'. I have already created the client and employee tables, both of which ran correctly and added the tables alright. However I am getting an issue creating my 'Appointment' table. The code for creating it is below:
create table Appointment
(appointment_num number(9) not null primary key,
appointment_time datetime(),
emp_ID number(4) not null references employee (emp_ID),
client_ID number(9) not null references client (client_ID))
Cannot find where the error is and cannot find any troubleshooting guidance elsewhere for the issue. Any help would be appreciated.

you have datetime(), change it to date. Please note that datetime is invalid datatype on oracle, you need to use date or alternatively timestamp
create table Appointment
(
appointment_num number(9) not null primary key,
appointment_time date,
emp_ID number(4) not null references employee (emp_ID),
client_ID number(9) not null references client (client_ID)
)
Diference between Date and Timestamp
One of the main problems with the DATE datatype was its' inability to be granular enough to determine which event might have happened first in relation to another event. Oracle has expanded on the DATE datatype and has given us the TIMESTAMP datatype which stores all the information that the DATE datatype stores, but also includes fractional seconds.
Reference

Related

Set a Table in Oracle to Only Accept Certain Values for a Column

I am looking to create a table that will only accept certain values in my database and I came across the default values option but I am sure that this won't be something that would work but just wanted to clarify.
As far as I am aware the default option, would allow you to store a value for a row unless this is overwritten by something else.
What I am looking to do is create a table where the STATUS column would only have the values OPEN or CLOSED so my output looks like the following:
ORDER_ID: 001, 002, 003
STATUS: OPEN, CLOSED, OPEN
ORDER_DATE: 2021-05-29 09:01:25, 2021-05-31 17:35:40, 2021-06-01 15:33:55
The table I have created so far looks like:
CREATE TABLE ORDERS (
ORDER_ID NUMBER NOT NULL,
STATUS VARCHAR2(6) NOT NULL,
ORDER_DATE DATE NOT NULL,
PRIMARY KEY(ORDER_ID)
);
I am guessing I need to change the create table query for the order_id to include AUTO_INCREMENT but it's more the status that I want to understand in terms of how to only accept certain values.
You need to create a constraint. Either a check constraint with hardcoded values that the column is allowed. Or you can create a foreign key to a table which contains the allowed values.

Two postgresql tables referencing each other

Question may be basic, I don't have any experience with databases.
I have a postgres db with some tables. Two of them are dates and accounts.
The date table has an account_id field referencing an id table in an account table and a balance field that represents the balance that account had at that date. So, many date entities may reference one account entity, many-to-one, okay.
But an account table also has an actual_date field, that must reference the date entity, with actual balance this account has. One account entity may reference one actual date entuty, but date entity can have one or zero account entities referncing it. And if it does have an account referencing it with it's actual_date, it will always be the same account, date itself referencing with account_id.
What kind of relathinship is this? Is it even possible to implement? And if it is, how do I do it?
I came up with this piece of code, but I have no clue if it does what I think it does.
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users,
actual_date_id DATE UNIQUE REFERENCES dates
);
CREATE TABLE dates (
id SERIAL PRIMARY KEY,
account_id INT REFERENCES accounts,
date DATE,
balance INT,
unconfirmed_balance INT
);
P.S. I create tables with init.sql but work with them with sqlalchemy and it would be greate if someone could also show how to define such model with it.
As written the SQL script would never work for two reasons:
a foreign key can only reference the primary key of a table, not any arbitrary column in it. So actual_date_id should be an integer in order to be able to reference the primary key of the dates table.
you can't reference a table that hasn't been created yet, so the foreign key between accounts and dates must be created after both tables are created.
With circular foreign keys it's usually easier to define at least one of them as deferrable, so that you can insert them without the need of e.g. an intermediate NULL value.
So something along the lines (assuming that users already exists)
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users,
actual_date_id integer UNIQUE -- note the data type
);
CREATE TABLE dates (
id SERIAL PRIMARY KEY,
account_id INT REFERENCES accounts,
date DATE,
balance INT,
unconfirmed_balance INT
);
-- now we can add the foreign key from accounts to dates
alter table accounts
add foreign key (actual_date_id)
references dates (id)
deferrable initially deferred;
It might be better to avoid the circular reference to begin with. As you want to make sure that only one "current balance" exists for each account, this could be achieved by adding a flag in the dates table and getting rid of the actual_date_id in the accounts table.
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users
);
CREATE TABLE dates (
id SERIAL PRIMARY KEY,
account_id INT REFERENCES accounts,
is_current_balance boolean not null default false,
date DATE,
balance INT,
unconfirmed_balance INT
);
-- this ensures that there is exactly one row with "is_current_balance = true"
-- for each account
create unique index only_one_current_balance
on dates (account_id)
where is_current_balance;
Before you change a row in dates to be the "current one", you need to reset the existing one to false.
Unrelated, but:
With modern Postgres versions it's recommended to use identity columns instead of serial

Date time format in Oracle

I am new to sql and am working on an example. Among the tables I have created, I have the comments table:
CREATE TABLE comments (
club VARCHAR2(60) NOT NULL,
nick VARCHAR2(35),
msg_date DATE,
title VARCHAR2(100) NOT NULL,
director VARCHAR2(50) NOT NULL,
subject VARCHAR2(100),
message VARCHAR2(1500),
valoration NUMBER(2),
CONSTRAINT PK_COMMENTS PRIMARY KEY (nick,msg_date),
CONSTRAINT FK_COMMENTS_MEMBER FOREIGN KEY (nick,club) REFERENCES membership ON DELETE CASCADE,
CONSTRAINT FK_COMMENTS_MOVIES FOREIGN KEY (title,director) REFERENCES movies,
CONSTRAINT CK_COMMENTS_VAL CHECK (valoration<11)
);
I am asked to create a trigger that does the following:
if a comment arrives on the same date as another one already stored, register it with the date
'one second later'.
The problem I have is that I do not know how to convert the 'one second' later into a date. Any idea on how to solve this problem?
msg_date + interval '1' second
or alternatively msg_date + (1/(24*60*60))
However this whole scenario is fraught with danger. While checking existing messages in the table within the trigger the table may be changing in other transactions and so there is a real risk of race conditions here - two messages both adding 1 second to an existing message will then have the same date. This would be the case whether the check was in a trigger or application code.
If this is a real world scenario I would avoid the trigger, use a timestamp rather than date, where the precision is between millis and nanos and consider how to deal with the lower risk of messages with the same timestamp as a business problem - what is the implication if it does occur.

Create primary key for table with period (Temporal Validity) in Oracle SQL

I have a question regarding to primary key for Oracle Table with Period.
I have created two tables like following:
create table el_temporal_try( -- Parent Table
id number(10) not null,
ColumnA varchar(10),
constraint el_temporal_try_pk primary key (id),
period for valid_period
);
create table el_temporal_try_son( -- Son Table
id number(10) not null,
ColumnA varchar(10),
parent_id number(10),
constraint el_temporal_try_FY foreign key (parent_id) references el_temporal_try(id),
period for valid_period
);
This script gone through successfully. However I have problem with inserting data:
I have executed following two insert statements into the parent table:
1st: statement
insert into el_temporal_try
(id, columnA,valid_period_start, valid_period_end)
values
(1,'A',sysdate - 10, sysdate - 9);
Result:
1 row inserted.
2nd: statement
insert into el_temporal_try
(id, columnA,valid_period_start, valid_period_end)
values
(1,'B',sysdate - 8, sysdate - 7);
Result
ORA-00001: unique constraint (PBSVW.EL_TEMPORAL_TRY_PK) violated
I understand it is because of the "ID" column. However, my issues because this two rows are for a different period, should it be allowed?
I was intended to use this period for feature to capture the change history of a record as an alternative to flashback. However, does it means that I should not use primary key at this situation?
Thanks in advance!
The problem is related to the id column like you said. it's not possible to add the registry because the primary key is unique, then your second insert statement references the same ID from the first. You need to change the ID always you insert a line.
On Oracle 12c, you can use the identity like this link.
https://www.oracletutorial.com/oracle-basics/oracle-identity-column/
in another version, you can use sequence and trigger to do this.
https://chartio.com/resources/tutorials/how-to-define-an-auto-increment-primary-key-in-oracle/
Thanks for everyone's help on this. This most likely means I cannot use Primary Key/Foreign Key to maintain the referential integrity between the parent and son for my situation within a particular timestamp, but I have to go for something else.
Thanks a lot!

Inserting values into the table

I'm trying to insert the values into the tables that I created.
This is the values that I'm trying to insert.
INSERT INTO DDR_Rental (customer_ID, rental_date, rent_fee, film_title, start_date, expiry_date, rating)
VALUES (12345, '12-Mar-19', '4.99', 'Peppermint', '12-Mar-19', '22-Mar-19', 4);
This is the datatypes and the constraints.
CREATE TABLE DDR_Rental
(customer_ID NUMBER(5),
rental_date DATE,
rent_fee NUMBER(3,2) CONSTRAINT SYS_RENTAL_FEE_NN NOT NULL,
film_title VARCHAR2(20),
start_date DATE,
expiry_date DATE,
rating NUMBER(5),
CONSTRAINT SYS_RENTAL_PK PRIMARY KEY ((customer_ID), (rental_date), (film_title)),
CONSTRAINT SYS_RENTAL_CUS_ID_FK1 FOREIGN KEY (customer_ID) REFERENCES
DDR_CUSTOMER(CUSTOMER_ID),
CONSTRAINT SYS_RENTAL_FILM_TITLE_FK2 FOREIGN KEY (film_title) REFERENCES
DDR_MOVIE_TITLE(FILM_TITLE),
CONSTRAINT SYS_RENTAL_EXP_DATE_CK CHECK (expiry_date >= start_date),
CONSTRAINT SYS_RENTAL_START_DATE_CK CHECK (start_date >= rental_date),
CONSTRAINT SYS_RENTAL_RATING_CK CHECK (REGEXP_LIKE(rating,('[12345]'))));
The error says unique constraint (CPRG250.SYS_RENTAL_PK) violated
It seems like you are trying to add a duplicate rental event for the same film by the same customer on exact one day. That can obviously happen, if you allow in your business logic the situation that a customer can rent a movie, give it back on the same day and rent it back again.
Knowing your business, you have 2 ways to deal with this situation:
Your business model don't allow that. This means that this is a duplicate record and you shouldn't add currently existing record, in which case showing that error is perfectly fine and doesn't allow for duplicates, since this event happened only once.
Your business model allows that. In this case, you should modify your rental_date column to store time along with the date, instead of only storing date, so that you know when the rental event actually happen. You could use datetime type for example to store date with time. This can be done when creating your table, just replace rental_date date with rental_date datetime. If the table is already created you will need to drop and recreate PRIMARY KEY and then after that you could change type of your column using ALTER TABLE ddr_rental ALTER COLUMN rental_date datetime and re-create the primary key. Check values stored in your table after that, since 2019-01-01 will now be represented as 2019-01-01 00:00:00.000 appending the time which wasn't specified before.
In addition to (1) you could wrap your code and handle this exception to return a clear message when this happens, showing that the movie has already been rented.
Moreover, since you don't have a table for storing movies in your inventory, this can lead to a possible mistake, since you may have more than 1 copy of a movie. In this case I suggest that you create separate film and film_copy tables to properly identify which copy of a film has been rented, so that you can rent another copy.
You have a unique constraint in your table. Your table already has a record with customer_id, rental_date and film_title that you want to insert.
Try this query and you will see that there already is a record
select * from DDR_Rental
where customer_id=12345 and rental_date='12-Mar-19' and film_title='Peppermint'