Insert statement Oracle - sql

Here is my table
create table reservations (
ResID int NOT NULL,
GuestID int,
HotelID int,
Check_in DATE,
Check_out DATE,
RoomType varchar2(15),
Price Dec(8,2),
PRIMARY KEY (ResID),
CONSTRAINT FK_GuestIDX FOREIGN KEY(GuestID) REFERENCES Guests(GuestID),
CONSTRAINT FK_HotelID FOREIGN KEY(HotelID) REFERENCES Hotel(HotelID)
);
Table was created with no problems. Now Im trying to populate the table
Here is my insert statement
insert into reservations (1, 1, 2, '17-DEC-2018', '21-DEC-2018', 'Suite', 87.03);
and here is the error that I'm getting
ORA-00928: missing SELECT keyword
What could be the cause for this?

Or missing values:
insert into reservations
values (1, 1, 2, '17-DEC-2018', '21-DEC-2018', 'Suite', 87.03);
That said, I would recommend writing this as:
insert into reservations (ResID, GuestID, HotelID, Check_in, Check_out DATE, RoomType, Price)
values (1, 1, 2, DATE '2018-12-17', DATE '2018-12-21', 'Suite', 87.03);
Note:
List the columns after the insert. This can really prevent hard-to-debug errors.
This uses the DATE keyword to introduce a date constant.
You can also write this using SELECT:
insert into reservations (ResID, GuestID, HotelID, Check_in, Check_out DATE, RoomType, Price)
select 1, 1, 2, DATE '2018-12-17', DATE '2018-12-21', 'Suite', 87.03
from dual;

Related

Update multiple tables in trigger where one of the tables is used for trigger activation

Let's say I have two tables called widgetCustomer and widgetSale. On an insert in widgetSale I want to add a timestamp to the widgetSale row and add the sale id as last_order_id to the widgetCustomer table.
I understand using AFTER INSERT ON will result in an error on trying to update the NEW row, hence we need to use BEFORE INSERT ON clause. Which brings forward a new issue that AUTO_INCREMENT has not yet generated a id for sale hence last_order_id would all be zero. There is a method to do this at MySQL/MariaDB TRIGGER but it seems to fail on my system (i.e., the last order ids are still zero).
As a work around I'm using two different triggers one before insert and one after insert. Although it does work I'm keen to learn if there is a possible flaws with the method above and is there a better way of doing this (both in terms of performance and data integrity).
My code is given below:
DROP TABLE IF EXISTS widgetSale;
DROP TABLE IF EXISTS widgetCustomer;
DROP TABLE IF EXISTS widgetLog;
CREATE TABLE widgetCustomer ( id integer primary key AUTO_INCREMENT, name TEXT, last_order_id INT, stamp TEXT );
CREATE TABLE widgetSale ( id integer primary key AUTO_INCREMENT, item_id INT, customer_id INTEGER, quan INT, price INT, stamp TEXT );
CREATE TABLE widgetLog ( id integer primary key AUTO_INCREMENT, stamp TEXT, event TEXT, username TEXT, tablename TEXT, table_id INT);
INSERT INTO widgetCustomer (name) VALUES ('Bob');
INSERT INTO widgetCustomer (name) VALUES ('Sally');
INSERT INTO widgetCustomer (name) VALUES ('Fred');
SELECT * FROM widgetCustomer;
CREATE TRIGGER stampSale BEFORE INSERT ON widgetSale
FOR EACH ROW BEGIN
SET NEW.stamp = CURRENT_TIMESTAMP();
END
CREATE TRIGGER stampOnRest AFTER INSERT ON widgetSale
FOR EACH ROW BEGIN
UPDATE widgetCustomer SET last_order_id = NEW.id, stamp = CURRENT_TIMESTAMP()
WHERE widgetCustomer.id = NEW.customer_id;
INSERT INTO widgetLog (stamp, event, username, tablename, table_id)
VALUES (CURRENT_TIMESTAMP(), 'INSERT', 'TRIGGER', 'widgetSale', NEW.id);
END
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (1, 3, 5, 1995);
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (2, 2, 3, 1495);
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (3, 1, 1, 2995);
SELECT * FROM widgetSale;
SELECT * FROM widgetCustomer;
SELECT * FROM widgetLog;
I'm using mariadb 10.6.* on Archlinux.

insert date difference in last column

I want to insert date difference of 4th and 5th column in the 6th column but it is giving me error saying column not allowed.
insert into leave25 vALUES (4, 4, 'SICK', TO_DATE('22-AUG-14','DD-MON-YY'), TO_DATE('22-SEP-14','DD-MON-YY'), startdate-enddate)\\
Always specify the column names explicitly in your INSERT statements. It is safer that way.
If you want to avoid writing the dates again, you could select the values from a subquery.
INSERT INTO leave25
(col1,
col2,
col3,
startdate,
enddate,
days)
SELECT t.*,
startdate - enddate
FROM (SELECT 4,
4,
'SICK',
to_date('22-AUG-14', 'DD-MON-YY') as startdate,
to_date('22-SEP-14', 'DD-MON-YY') as enddate
FROM dual) t;
Furthermore, I agree with Aleksej, it is better to have this difference stored as a virtual column rather than a column itself.
You can not do it this way, you need to esplicitly use the values you want to insert:
INSERT INTO leave25
VALUES (
4,
4,
'SICK',
TO_DATE('22-AUG-14', 'DD-MON-YY'),
TO_DATE('22-SEP-14', 'DD-MON-YY'),
TO_DATE('22-SEP-14', 'DD-MON-YY') - TO_DATE('22-AUG-14', 'DD-MON-YY')
Besides, if this column always contains that difference, are you sure you need to store this redundant information?
A different approach could be by using a trigger to populate that column without explicitly giving it a value, but this depends on your environment and your needs.
Use a virtual column:
CREATE TABLE Leave25(
EMPLOYEEID INTEGER
CONSTRAINT LEAVE25__EMPID__FK REFERENCES Employee24,
LEAVEID INTEGER
CONSTRAINT LEAVE25__LEAVEID__PK PRIMARY KEY,
LEAVETYPE VARCHAR2(20)
CONSTRAINT LEAVE25__LEAVETYPE__NN NOT NULL
CONSTRAINT LEAVE25__LEAVETYPE__CHK CHECK (
LEAVETYPE IN 'EARNED', 'SICK'
),
STARTDATE DATE
CONSTRAINT LEAVE25__STARTDATE__NN NOT NULL,
ENDDATE DATE
CONSTRAINT LEAVE25__ENDDATE__NN NOT NULL,
DURATION NUMBER
GENERATED ALWAYS AS ( ENDDATE - STARTDATE ) VIRTUAL
);
And create a sequence to manage the primary key:
CREATE SEQUENCE LEAVE25__LEAVEID__SEQ;
Then you can do:
INSERT INTO leave25 (
EMPLOYEEID, LEAVEID, LEAVETYPE, STARTDATE, ENDDATE
) VALUES (
4, LEAVE25__LEAVEID__SEQ.NEXTVAL, 'SICK', DATE '2014-08-22', DATE '2014-09-22'
)

beginner to sql plus - what am i doing wrong in this query? why am I getting the result as "0 records updated"?

I am trying some question in sql plus in oracle but it is not working and not returning the desired result. can someone please tell me what I am doing wrong?
the question is:-
Develop a query that will identify and mark inactive those customers that have bills overdue by more than 30 days (this can usually be done using a sub-query). Remember, you are only marking a customer as inactive, not actually deleting the customer record from the system.
This is the query I have tried:-
SELECT CUSTID, CUSTFIRSTNAME, CUSTSTATUS FROM CUSTOMER;
UPDATE CUSTOMER
SET CUSTSTATUS='I'
WHERE CUSTID IN
(SELECT CUSTID FROM BILLING
WHERE (SYSDATE - DUEDATE) > 30 AND PAIDDATE IS NULL);
SELECT CUSTID, CUSTFIRSTNAME, CUSTSTATUS FROM CUSTOMER;
values in billing table are these:-
--INSERT STATEMENTS FOR TABLE BILLING
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(1, 1, 30, DATE '2012-07-01', 30, DATE '2012-07-01' );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(2, 2, 80, DATE '2012-06-25', 0, );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(3, 3, 50, DATE '2012-04-01', 0, );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(4, 4, 30, DATE '2012-06-11', 30, DATE '2012-06-11' );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(5, 5, 50, DATE '2012-04-30', 0, );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(6, 6, 80, DATE '2012-06-01', 80, DATE '2012-05-30' );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(7, 7, 30, DATE '2012-06-15', 0, );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(8, 8, 30, DATE '2012-05-30', 0, );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(9, 9, 80, DATE '2012-05-25', 0, );
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(10, 10, 50, DATE '2012-04-01', 0, );
these are the structures of BILLING and Customer table:-
SQL> desc customer;
Name Null? Type
------------------------------------------------------------------------ -------- -----------------
CUSTID NOT NULL NUMBER(5)
CUSTSTATUS NOT NULL CHAR(1)
CUSTDELETERZN VARCHAR2(100)
CUSTDELETEDATE DATE
EMPID NOT NULL NUMBER(5)
CUSTFIRSTNAME NOT NULL VARCHAR2(30)
CUSTLASTNAME NOT NULL VARCHAR2(20)
CUSTSTARTDATE DATE
PACKID NOT NULL NUMBER(2)
CUSTPHONE VARCHAR2(12)
CUSTSTREET VARCHAR2(30)
CUSTCITY VARCHAR2(20)
CUSTSTATE CHAR(2)
CUSTZIP NUMBER(5)
CUSTEMAIL VARCHAR2(30)
SQL> desc billing;
Name Null? Type
------------------------------------------------------------------------ -------- -----------------
CUSTID NOT NULL NUMBER(5)
BILLID NOT NULL NUMBER(5)
BILLAMT NOT NULL NUMBER(5)
DUEDATE NOT NULL DATE
PAIDAMT NUMBER(5)
PAIDDATE DATE
I also tried to write " WHERE (SYSDATE - DUEDATE) > 30 AND PAIDDATE ='');"
this didn't work either.
EDIT:-
I inserted NULL in my INSERT statements now and I am getting this error now:-
UPDATE CUSTOMER
*
ERROR at line 1:
ORA-02290: check constraint (D03318785.CC_CUSTOMER_F_CUSTSTATUS) violated
can anyone plz help?
Create customer table is as follows:-
CREATE TABLE CUSTOMER(
custid NUMBER(5) NOT NULL
CONSTRAINT pk_custid PRIMARY KEY,
custstatus CHAR(1) NOT NULL,
custdeleterzn VARCHAR2(100),
custdeletedate DATE,
empid NUMBER(5) NOT NULL,
custfirstname VARCHAR2(30) NOT NULL,
custlastname VARCHAR2(20) NOT NULL,
custstartdate DATE,
packid NUMBER(2) NOT NULL,
custphone VARCHAR2(12),
custstreet VARCHAR2(30),
custcity VARCHAR2(20),
custstate CHAR(2),
custzip NUMBER(5),
custemail VARCHAR2(30));
This statement:
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(5, 5, 50, DATE '2012-04-30', 0, );
is invalid SQL and will not run.
It will not put "nothing" into the column PAIDDATE. You should have gotten a syntax error running them.
If you ignored that and still committed the inserts, the invalid statements will not have been run and thus those rows have not been inserted (and thus no row with a NULL value for PAIDDATE is in the table). Therefor your update is not finding them.
The error ORA-02290: check constraint (D03318785.CC_CUSTOMER_F_CUSTSTATUS means that the values that are allowed for the CUSTSTATUS columns are limited and the value 'I' that you are trying to assign is not one of them. You will need to find you SQL script that created the check constraint so see which values are allowed.
To retrieve the definition of the check constraint you can use the following statement:
select dbms_metadata.get_ddl('CONSTRAINT', 'CC_CUSTOMER_F_CUSTSTATUS')
from dual;
try this:
WHERE DUEDATE < TRUNC(SYSDATE) - 30 AND PAIDDATE IS NULL
Applying functions to column names should be avoided where possible, and you test for a NULL value using IS NULL
In your insert statements you do not fill the last value (Never seen this before). Try setting it explicitly with a null value like this :
INSERT INTO BILLING(CUSTID,BILLID,BILLAMT,DUEDATE,PAIDAMT,PAIDDATE )
VALUES(5, 5, 50, DATE '2012-04-30', 0, NULL);

Need Help Writing SQL Query in Postgresql

I've been trying to write this query but can't seem to get it right for some reason or another..
What I need to do is:
Change the status of a question to 'closed' if there has not been an update associated with this question inserted into the qUpdateTable in the last 24 hours.
I only want it to be closed if a staff member has replied to it at least once.
You can determine if a staff member or a user has replied to the question by checking the qUpdateTable and seeing if a the StaffID field is empty or has a value for that particular tickets updates. If there is a staffID then it has been updated by a staff member, however if it does not then the qUpdate was done by a user.
Essentialy the way this works is a user posts a question by inserting into the Question table, and replies are made by inserting into the qUpdate table and linked to the original question using the foreign key - "QuestionID".
The tables:
CREATE TABLE Staff
(
ID INTEGER NOT NULL PRIMARY KEY,
Name VARCHAR(40) NOT NULL
);
CREATE TABLE Customer
(
ID INTEGER NOT NULL PRIMARY KEY,
Name VARCHAR(40) NOT NULL,
Email VARCHAR(40) NOT NULL
);
CREATE TABLE Product
(
ID INTEGER NOT NULL PRIMARY KEY,
Name TEXT NOT NULL
);
CREATE TABLE Question
(
ID INTEGER NOT NULL PRIMARY KEY,
Problem VARCHAR(1000),
Status VARCHAR(20) NOT NULL DEFAULT 'open',
Priority INTEGER NOT NULL,
LoggedTime TIMESTAMP NOT NULL,
CustomerID INTEGER NOT NULL,
ProductID INTEGER NOT NULL,
FOREIGN KEY (ProductID) REFERENCES Product(ID),
FOREIGN KEY (CustomerID) REFERENCES Customer(ID),
CHECK (Status IN ('open','closed') AND Priority IN (1,2,3))
);
CREATE TABLE qUpdate
(
ID INTEGER NOT NULL PRIMARY KEY,
Message VARCHAR(1000) NOT NULL,
UpdateTime TIMESTAMP NOT NULL,
QuestionID INTEGER NOT NULL,
StaffID INTEGER,
FOREIGN KEY (StaffID) REFERENCES Staff(ID),
FOREIGN KEY (QuestionID) REFERENCES Question(ID)
);
Some sample inserts:
INSERT INTO Customer (ID, Name, Email) VALUES (1, 'testname1', 'testemail1');
INSERT INTO Customer (ID, Name, Email) VALUES (2, 'testname2', 'testemail2');
INSERT INTO Staff (ID, Name) VALUES (1, 'Don Keigh');
INSERT INTO Product (ID, Name) VALUES (1, 'Xbox');
INSERT INTO Question (ID, Problem, Status, Priority, LoggedTime, CustomerID, ProductID)
VALUES (1, 'testproblem1', 'open', 3, '2012-04-14 09:30', 2, 1);
INSERT INTO Question (ID, Problem, Status, Priority, LoggedTime, CustomerID, ProductID)
VALUES (2, 'testproblem2', 'open', 3, '2012-04-14 09:30', 2, 1);
INSERT INTO qUpdate (ID, Message, UpdateTime, StaffID, QuestionID) VALUES (2, 'testmessage1','2012-07-12 14:27', 1, 1);
INSERT INTO qUpdate (ID, Message, UpdateTime, QuestionID) VALUES (3, 'testmessage1','2012-06-18 19:42', 2);
What I've done so far (which obviously doesn't work)
UPDATE Question
SET Status = 'closed'
WHERE EXISTS
(SELECT qUpdate.QuestionID
MAX(qUpdate.UpdateTime - Now() = INTERVAL '1 day') FROM qUpdate
LEFT JOIN Question ON qUpdate.QuestionID = Question.ID
WHERE qUpdate.StaffID IS NOT NULL);
I realise my explanation may be a bit confusing so if you need more info post and I'll reply ASAP
UPDATE Question
SET Status = 'closed'
where
-- this clause asserts there's at least one staff answer
exists (
select null from qUpdate
where qUpdate.QuestionID = Question.ID
and StaffID is not null
)
-- this clause asserts there's been no update in the last 24 hours
and not exists (
select null from qUpdate
where qUpdate.QuestionID = Question.ID
and qUpdate.UpdateTime > (now() - interval '24 hours')
)
and Status = 'open';
You'll almost certainly want an index on qUpdate(QuestionID) or possibly qUpdate(QuestionID,UpdateTime) or qUpdate(QuestionID,StaffID) to get good performance on the subselects in the exists() tests.

SQL query: Last but one rank for user

My table structure looks like this:
create table rankings (
id IDENTITY NOT NULL,
user_id INT NOT NULL,
game_poule_id INT NOT NULL,
rank INT NOT NULL,
insertDate DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (game_poule_id) REFERENCES game_poules(id) ON DELETE CASCADE
);
All old rankings of users per game are saved in this table. Now I want to have the last but one rank in the table for all users in a gamepoule.
Has someone an idea how to achive this? Thanks
You need to self join the table to get the records you require.
For this answer I created your table without the foreign keys as they are not required to get it to work.
CREATE TABLE Rankings (
id int IDENTITY NOT NULL,
user_id INT NOT NULL,
game_poule_id INT NOT NULL,
rank INT NOT NULL,
insertDate DATETIME NOT NULL
);
Insert some sample data. Without more information I cannot simulate any better than this.
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(1, 100, 3, CURRENT_TIMESTAMP-2)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(1, 100, 2, CURRENT_TIMESTAMP-1)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(1, 101, 6, CURRENT_TIMESTAMP)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(2, 100, 5, CURRENT_TIMESTAMP-2)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(2, 100, 1, CURRENT_TIMESTAMP-1)
INSERT Rankings(user_id,game_poule_id,rank,insertDate)
VALUES(2, 101, 2, CURRENT_TIMESTAMP)
Query for the last but one rank
SELECT Rankings.game_poule_id, Rankings.user_id, rank, MAX(Rankings.insertDate)
FROM Rankings INNER JOIN
(SELECT game_poule_id, user_id, MAX(insertDate) max_insert_date
FROM rankings
GROUP BY game_poule_id, user_id) Max_Ranking_Date
ON Rankings.user_id = Max_Ranking_Date.user_id
AND Rankings.insertDate < Max_Ranking_Date.max_insert_date
AND Rankings.game_poule_id = Max_Ranking_Date.game_poule_id
GROUP BY Rankings.game_poule_id, Rankings.user_id, rank
PLEASE NOTE!
As you can see from the results you will not get a ranking for a game that only has one row per user. But since you are asking for the "last but one" that only makes sense for games with multiple entries.
EDIT:
I've just realised the query I have provided will not return one row per user per game. Anyone want to fix it? I have to get on with some work :)
Another possible (not very nice) solution
SELECT
*
FROM
rankings r
WHERE
FK_gamePoule = 0 AND
r.insertDate = COALESCE(
(SELECT
r2.insertDate
FROM
rankings r2
WHERE
r.FK_user = r2.FK_user ORDER BY r2.insertDate DESC
LIMIT 1
OFFSET 1), '2048-12-31 23:59:59')