What would be the possible outcome of this table in oracle? - sql

I have a "Products" table that has two columns: product_code and product_name. The table is empty
and I want to execuite the following SQL statement.
INSERT INTO Products VALUES (100,’PIZZA’);
INSERT INTO Products VALUES (150,’PASTA’);
UPDATE Products SET product_name = ’PAPAYA’
WHERE product_code = 100;
CREATE PROFILE prof_sales LIMIT
IDLE_TIME 15;
UPDATE Products SET product_name = ’POTATO’
WHERE product_code = 150;
ROLLBACK;
Does the table remain empty because of the ROLLBACK?
The table Products will have two records. 100 PAPAYA and 150 PASTA.
Or the table Products will have two records. 100 PIZZA and 150 PASTA.
The table Products will have two records. 100 PAPAYA and 150 POTATO.
The PROFILE prof_sales will not be created.
These are the assumptions I am making and need an explanation for each assumption
as I am learning. Sorry I couldn't check the answers as my oracle 18c crashed for some reason.
It would be very kind if there is anyone who can help.

None of the above.
The table will be empty but not because of the rollback.
All the INSERT and UPDATE statements will fail with the exception:
ORA-01756: quoted string not properly terminated
Because you are using the character ’ for string literals when it should be '.
db<>fiddle here
If you fix the statements so they are all valid SQL statements then a DDL statement will implicitly COMMIT the prior statements; and then all the statements before the DDL statement will be committed and all the statements afterwards will ROLLBACK.
Since this looks like a homework/exam style exercise I'll leave working out exactly what happens to you.

Related

SQL trigger to decrement another table

I've created a Database for a DVD store which contains a Film table to hold info about films + copies available, and a sale table. I've created sequences for the Film and Sale table, to auto-increment the Primary keys FILM_ID and SALE_TRANSACTION_REF respectively, using the following code.
CREATE SEQUENCE Film_Seq
MINVALUE 1
START WITH 1
INCREMENT BY 1
NOCACHE;
CREATE OR REPLACE TRIGGER New_Film
BEFORE INSERT ON FILM
FOR EACH ROW
BEGIN
SELECT Film_Seq.NEXTVAL
INTO :new.FILM_ID
FROM dual;
END;
/
This seems to work handy enough, but when I try to use a trigger to decrement the COPIES_AVAILABLE attribute of the film in Film after a sale with the following code, I get an error:
CREATE OR REPLACE TRIGGER After_Sale
AFTER INSERT ON SALE
DECLARE
ID NUMBER(38) := Sale_Seq.CURRVAL;
BEGIN
UPDATE FILM
SET COPIES_AVAILABLE = COPIES_AVAILABLE - 1
FROM FILM, SALE
WHERE FILM.FILM_ID = SALE.FILM_ID
AND (SALE.SALE_TRANSACTION_REF = ID);
END;
/
I actually get two errors, the first one relates to the declare statement, which is
4/2 PL/SQL: SQL Statement ignored
And the second one has to do with the UPDATE statement and it is
6/2 PL/SQL: ORA-00933: SQL command not properly ended
I've wrecked my brains trying to construct this statement differently, and have searched the documentation but can't seem to find the answer, and help would be greatly appreciated.
Also, looking over my question it may not be obvious but I have already created a sale_seq.
Sorry, it may not be evident what I am trying to achieve here. Whenever a Film is sold and added to the sale table, I want to automatically decrement the Copie_Available for the corresponding film in the film table, so if I left out the AND AND (SALE.SALE_TRANSACTION_REF = Sale_Seq.CURRVAL) clause the trigger will complie grand, but will decrement all copies available for all films in the film table, which is incorrect.
try it like this:
CREATE OR REPLACE TRIGGER After_Sale
AFTER INSERT ON SALE
FOR EACH ROW
BEGIN
UPDATE FILM
SET COPIES_AVAILABLE = COPIES_AVAILABLE - 1
WHERE FILM.FILM_ID = :NEW.FILM_ID
END;
Why save COPIES_AVAILABLE to your database. Why wouldn't you detract for instance [all copies in stock] - [all sold copies] if you want to know available copies.

Need Help using a loop to perform a mass insert in SQL

First off, i should say up front that i am not a very strong SQL person, so please be gentle :)
I need to perform about 400 inserts into a particular table. The data that i will be using for these inserts, i can collect from a SELECT statement that runs off a different table. I only need the data from 1 column from this table.
So, im hoping someone can help me write the SQL that will basically take the list of id's that are returned from my select, and use that list to do a mass insert into another table.
In psuedocode, something like this:
Select BankID from BankTable; - this returns 300 rows
Insert Into AccountTable -- this will add all 300 rows into the 2nd table
Values
(BankID)
thanks in advance guys...
Very simple, you basically said it. :-)
INSERT Into AccountTable (BankId, SecondColumn) SELECT BankId,'XXX' as staticText FROM BankTable;
It can be done in one statement:
Insert Into AccountTable (bankid)
Select BankID from BankTable
This assumes that the column in AccountTable is also named bankid; if not, just set the name appropriately in the parenthesis.
Keep in mind your INSERT statement must include the columns if the select statement does not match your table definition precisely.
INSERT AccountTable (BankID)
SELECT BankID
FROM BankTable
For multiple columns simply include the column list:
INSERT AccountTable (BankID, BankName)
SELECT BankID, BankName
FROM BankTable
You can also run into type conversion issues if the data types of the columns don't match (i.e. integer fields won't take alpha characters, etc.), but it is not a necessity that the column names match. Just get the order of columns and types right and you should be good.

Insert or Replace with sum of old values

I am building Inventory Application using PhoneGap.In that i have one module STOCK for stock management.
Stock Table Query
CREATE TABLE STOCK (
sto_id INTEGER PRIMARY KEY AUTOINCREMENT,
pro_id INTEGER FOREIGNKEY REFERENCES PRODUCT(pro_id) UNIQUE,
quantity TEXT
)
INSERT OR REPLACE Query
INSERT OR REPLACE INTO STOCK (pro_id,quantity) VALUES ("1","5");
There is not a single issue with this query its working perfectly but i want to update SUM of OLD VALUES WITH NEW ONE.
Example:
pro_id quantity
1 5
This is existing record so now when i will fire above query for new transaction which have 3 quantity then quantity should be (5 (old) + 3 (new) ) = 8.
So after updateing record it looks like.
pro_id quantity
1 8
How can i solve this any idea. or let me know if i am on wrong way.
Thanks.
Actually I am not real founder of this solution. The real hero is Daverandom with the help of him i have solve my issue.
He has suggest me to follow this solution and that is really helpful to find my solution.
Older query looks like as
INSERT OR REPLACE INTO STOCK (pro_id,quantity) VALUES ("1","5");
New Query looks like as
INSERT OR IGNORE INTO STOCK (pro_id,quantity) VALUES (1,0) ;
UPDATE STOCK SET quantity = quantity + 2 WHERE pro_id=1;
Update:
If you will not add WHERE pro_id="val" in UPDATE then it will UPDATE all rows.
So that will generate will appropriate result.
When user fire query first time then quantity will be 2 and when you fire same query second time it will 4.
So, We can change that value in each update.
Again thanks to Daverandom.
In SQLite, you can create a trigger to handle such functionality:
CREATE TRIGGER t1 BEFORE INSERT ON STOCK WHEN NEW.pro_id IN (SELECT pro_id FROM STOCK) BEGIN
UPDATE STOCK SET quantity=COALESCE(NEW.quantity, 0)+COALESCE((SELECT quantity FROM STOCK WHERE pro_id=NEW.pro_id), 0) WHERE pro_id=NEW.pro_id;
SELECT RAISE(IGNORE); -- Ignore INSERT
END;
From now on, whenever you try to insert an existing pro_id, update on quantity is done instead. Conflict clause (OR REPLACE) doesn't matter as trigger will handle it (for pro_id).
Yet another, this time without triggers, using single statement solution:
INSERT OR REPLACE STOCK(pro_id, quantity)
SELECT npro_id, COALESCE(nqty, 0)+COALESCE(quantity,0) FROM (
SELECT 123 AS npro_id, 9999 AS nqty
) LEFT JOIN STOCK ON npro_id=pro_id;
Just replace 123 with new prod_id and 9999 with new quantity.

SQLite create a new record if it doesn't exist

Hey so I'm trying to create a new record based on one which already exists, but I'm having trouble ensuring that this record doesn't already exist. The database stores details of transactions and has a field for whether it repeats.
I'm generating the new dates using
SELECT datetime(transactions.date, '+'||repeattransactions.interval||' days')
AS 'newdate' FROM transactions, repeattransactions WHERE
transactions.repeat = repeattransactions.id
Initially I'd like to use SELECT instead of INSERT just for debugging purposes. I've tried to do something with GROUP BY or COUNT(*) but the exact logic is eluding me. So for instance I've tried
SELECT * FROM transactions, (SELECT transactions.id, payee, category, amount,
fromaccount, repeat, datetime(transactions.date,
'+'||repeattransactions.interval||' days') AS 'date' FROM transactions,
repeattransactions WHERE transactions.repeat = repeattransactions.id)
but this obviously treats the two tables as though they were joined, it doesn't append the records to the bottom of the table which would let me group.
I've been struggling for days so any help would be appreciated!
EDIT:
The docs say "The ON CONFLICT clause applies to UNIQUE and NOT NULL constraints". I can't have a unique constraint on the table by definition as I have to create the exact same record for a new transaction with just a new date. Or have I misinterpreted this?
EDIT2:
id payee repeat date
1 jifoda 7 15/09/2011
2 jifoda 7 22/09/2011 <-- allowed as date different within subset
3 grefa 1 15/09/2011 <-- allowed as only date is not-unique
4 grefa 1 15/09/2011 <-- not allowed! exactly same as id 3
SQLite has special DDL statement for duplicates. Like:
create table test(a TEXT UNIQUE ON CONFLICT IGNORE);
insert into test values (1);
insert into test values (1);
select count(*) from test;
1
It can be also ON CONFLICT REPLACE. See docs.

A trigger to find the sum of one field in a different table and error if it's over a certain value in oracle

I have two tables
moduleprogress which contains fields:
studentid
modulecode
moduleyear
modules which contains fields:
modulecode
credits
I need a trigger to run when the user is attempting to insert or update data in the moduleprogress table.
The trigger needs to:
look at the studentid that the user has input and look at all modules that they have taken in moduleyear "1".
take the modulecode the user input and look at the modules table and find the sum of the credits field for all these modules (each module is worth 10 or 20 credits).
if the value is above 120 (yearly credit limit) then it needs to error; if not, input is ok.
Does this make sense? Is this possible?
#a_horse_with_no_name
This looks like it will work but I will only be using the database to input data manually so it needs to error on input. I'm trying to get a trigger similar to this to solve the problem(trigger doesn't work) and forget that "UOS_" is before everything. Just helps me with my database and other functions.
CREATE OR REPLACE TRIGGER "UOS_TESTINGS"
BEFORE UPDATE OR INSERT ON UOS_MODULE_PROGRESS
REFERENCING NEW AS NEW OLD AS OLD
DECLARE
MODULECREDITS INTEGER;
BEGIN
SELECT
m.UOS_CREDITS,
mp.UOS_MODULE_YEAR,
SUM(m.UOS_CREDITS)
INTO MODULECREDITS
FROM UOS_MODULE_PROGRESS mp JOIN UOS_MODULES m
ON m.UOS_MODULE_CODE = mp.UOS_MODULE_CODE
WHERE mp.UOS_MODULE_YEAR = 1;
IF MODULECREDITS >= 120 THEN
RAISE_APPLICATION_ERROR(-20000, 'Students are only allowed to take upto 120 credits per year');
END IF;
END;
I get the error message :
8 23 PL/SQL: ORA-00947: not enough values
4 1 PL/SQL: SQL Statement ignored
I'm not sure I understand your description, but the way I understand it, this can be solved using a materialized view, which might give better transactional behaviour than the trigger:
CREATE MATERIALIZED VIEW LOG
ON moduleprogress WITH ROWID (modulecode, studentid, moduleyear)
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG
ON modules with rowid (modulecode, credits)
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW mv_module_credits
REFRESH FAST ON COMMIT WITH ROWID
AS
SELECT pr.studentid,
SUM(m.credits) AS total_credits
FROM moduleprogress pr
JOIN modules m ON pr.modulecode = m.modulecode
WHERE pr.moduleyear = 1
GROUP BY pr.studentid;
ALTER TABLE mv_module_credits
ADD CONSTRAINT check_total_credits CHECK (total_credits <= 120)
But: depending on the size of the table this might however be slower than a pure trigger based solution.
The only drawback of this solution is, that the error will be thrown at commit time, not when the insert happens (because the MV is only refreshed on commit, and the check constraint is evaluated then)