Want to insert timestamp through procedure in oracle - sql

I have this procedure
PROCEDURE insertSample
(
return_code_out OUT VARCHAR2,
return_msg_out OUT VARCHAR2,
sample_id_in IN table1.sample_id%TYPE,
name_in IN table1.name%TYPE,
address_in IN table1.address%TYPE
)
IS
BEGIN
return_code_out := '0000';
return_msg_out := 'OK';
INSERT INTO table1
sample_id, name, address)
VALUES
(sample_id_in, name_in, address_in);
EXCEPTION
WHEN OTHERS
THEN
return_code_out := SQLCODE;
return_msg_out := SQLERRM;
END insertSample;
I want to add 4th column in table1 like day_time and add current day timestamp in it.. ho can i do that in this procedure.. thank you

Assuming you you have (or add) a column to the table outside of the procedure, i.e.
ALTER TABLE table1
ADD( insert_timestamp TIMESTAMP );
you could modify your INSERT statement to be
INSERT INTO table1
sample_id, name, address, insert_timestamp)
VALUES
(sample_id_in, name_in, address_in, systimestamp);
In general, however, I would strongly suggest that you not return error codes and error messages from procedures. If you cannot handle the error in your procedure, you should let the exception propagate up to the caller. That is a much more sustainable method of writing code than trying to ensure that every caller to every procedure always correctly checks the return code.

Using Sysdate can provide all sorts of manipulation including the current date, or future and past dates.
http://edwardawebb.com/database-tips/sysdate-determine-start-previous-month-year-oracle-sql

SYSDATE will give you the current data and time.
and if you add the column with a default value you can leave your procedure as it is
ALTER TABLE table1 ADD when_created DATE DEFAULT SYSDATE;

Related

PLS00215: String length constraints must be in range (1..32767)

I am new to pl/sql. I want to create a procedure that has three parameters called 'startMonth', 'endMonth', 'thirdMonth'. In the procedure, I am executing a sql query which is in 'run_sql' column in table_query. Values for 'startMonth', 'endMonth', 'thirdMonth' are needed to this query. This is how I wrote the procedure. My plan is to put all the sql queries in a separate table and execute in the for loop in the procedure. There I am creating a table called table1 and in the next month I want to drop it and create the table again. This is how I have written the procedure.
CREATE OR REPLACE procedure schema.sixMonthAverage (startMonth varchar,endMonth varchar ,thirdMonth varchar )
IS
start_date varchar := startMonth;
end_date varchar := endMonth;
begin
for c_rec in(select run_sql from table_query)
loop
dbms_output.put_line(startmonth);
dbms_output.put_line(endmonth);
execute immediate c_rec.run_sql using start_date, end_date;
Execute IMMEDIATE 'commit';
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Exception');
END;
This is the query in the run_sql column in table_query.
create table table1
as
select account_num,bill_seq,bill_version,
to_char(start_of_bill_dtm,''YYYYMM-DD'') st_bill_dtm,
to_char(bill_dtm - 1,''YYYYMM-DD'') en_bill_dtm,
to_char(actual_bill_dtm,''YYYYMM-DD'') act_bill_dtm,
round((invoice_net_mny + invoice_tax_mny)/1000,0) mon_bill,
bill_type_id,bill_status
from billsummary
where to_char(bill_dtm - 1,''YYYYMM'') between'||chr(32)||
startMonth ||chr(32)||'and'|| chr(32)||endMonth ||chr(32)||
'and cancellation_dtm is null;
But when I try to compile the procedure it gives me the error 'PLS00215: String length constraints must be in range (1..32767). Though I searched for the error I could not find the exact reason. It seems to be a problem in variable assigning. But I could not resolve it.
--Update
As it is given in the answer I converted the strings to dates.
CREATE OR REPLACE procedure REPO.sixMonthAverage (startMonth varchar2,endMonth varchar2 ,thirdMonth varchar2 )
IS
start_date date := TO_DATE(startMonth, 'yyyymm');
end_date date := TO_DATE(endMonth, 'yyyymm');
But when executing the query it gives the error message that ORA-00904: "END_DATE": invalid identifier. But it does not show any error message for the start_date and what would be the reason for this error message?
The error is pointing you to where the problem is. String declarations (char, varchar, varchar2 - but you should only be using varchar2, not varchar) need a length; so for example:
CREATE OR REPLACE procedure sixMonthAverage (startMonth varchar2,endMonth varchar2 ,thirdMonth varchar2 )
IS
start_date varchar2(10) := startMonth;
end_date varchar2(10) := endMonth;
...
Notice the procedure arguments do not specify a length; only the local variable declarations.
If those represent dates then they, and passed-in arguments, should probably be dates, not strings. It depends what your dynamic SQL is expecting though - if that is converting the strings to dates and specifying the format mask then I guess it's OK; otherwise you should be passed dates, or convert the strings to dates. The example you showed doesn't seem to have any bind variables to populate, though.
Dropping and recreating tables is generally not something you want to be doing though. You could delete/truncate and repopulate a table; or use partitioning if you want to keep more than one month; or use a view (or materialized view).

Use v('APP_USER') as default value for column in Oracle Apex

I am trying to use v('APP_USER') as default value for a column. I get null when I use it in select like
select v('APP_USER') from dual;
But when I use it as default in column, like below, I am getting error.
create table test_table (col_1 varchar2(50) default NVL(v('APP_USER'), SYS_CONTEXT('USERENV','OS_USER')));
Error
create table test_table (col_1 varchar2(50) default NVL(v('APP_USER'), SYS_CONTEXT('USERENV','OS_USER')))
Error report -
ORA-04044: procedure, function, package, or type is not allowed here
04044. 00000 - "procedure, function, package, or type is not allowed here"
*Cause: A procedure, function, or package was specified in an
inappropriate place in a statement.
*Action: Make sure the name is correct or remove it.
Can anyone explain this or have a turnaround for this ??
There are other options than V('APP_USER'). Since Apex 5, the APP_USER is stored in the sys_context and that is a lot more performant than the V() function. It is available as SYS_CONTEXT('APEX$SESSION','APP_USER').
It also works as a default value for tables:
create table test_table
(col_1 VARCHAR2(100) DEFAULT SYS_CONTEXT('APEX$SESSION','APP_USER'));
Table TEST_TABLE created.
That being said, the best practice for audit columns is a trigger that populates the the 4 audit columns (as #Littlefoot suggested). Have a look at quicksql (under SQL Workshop > Utilities or on livesql.oracle.com). You can have it generate the triggers for you if you set "include Audit columns" and "Apex Enabled". An example of such a generated trigger is:
create or replace trigger employees_biu
before insert or update
on employees
for each row
begin
if inserting then
:new.created := sysdate;
:new.created_by := nvl(sys_context('APEX$SESSION','APP_USER'),user);
end if;
:new.updated := sysdate;
:new.updated_by := nvl(sys_context('APEX$SESSION','APP_USER'),user);
end employees_biu;
/
One option is to use a database trigger, e.g.
CREATE OR REPLACE TRIGGER trg_biu_test
BEFORE INSERT OR UPDATE ON test
FOR EACH ROW
BEGIN
:new.col1 := v ('APP_USER');
END;
/

Having a hard time with procedure not formatting the query entry correctly

Create a dynamic procedure that will change the contents of any column for any row in the AA_EMPLOYEE table using the employee id. i.e.
BEGIN
dyn_aa_employee('emp_dob', '01-jan-18', 110);
END;
Will change the date of birth for employee ID 110
CREATE OR REPLACE PROCEDURE dyn_aa_employee
(p_col VARCHAR2,
p_dob IN aa_employee.emp_dob%TYPE,
p_id NUMBER)
IS
BEGIN
EXECUTE IMMEDIATE 'UPDATE aa_employee
SET '|| p_col ||' = :ph_dob
WHERE EMP_NUM = :ph_id'
USING p_dob, p_id;
BEGIN
dyn_aa_employee('emp_dob', '01-jan-18', 110);
END;
The top code has to work for the bottom code. The issue is it's changing the emp dob to 01-jan-0018, however I want it to change to exactly 01-jan-18.
My professor gave me a 0 for this assignment I'm just trying to figure out what I did wrong.
Assuming that aa_employee.emp_dob is of type date AND assuming that by '01-jan-18' you mean January 1st, 2018, either you do this:
BEGIN
dyn_aa_employee('emp_dob', date '2018-01-01', 110);
END;
or you could change your procedure to:
CREATE OR REPLACE PROCEDURE dyn_aa_employee (
p_col VARCHAR2,
p_dob IN aa_employee.emp_dob%TYPE,
p_id NUMBER)
IS
BEGIN
EXECUTE IMMEDIATE
'UPDATE aa_employee SET ' || p_col || ' = :ph_dob WHERE EMP_NUM = :ph_id'
USING TO_DATE (p_dob, 'DD-MON-YY'), p_id;
END;
It would be interesting to see the actual assignment, though. It's a rather confused scenario overall and I don't see how it teaches you much except to identify several things you probably shouldn't do.
Well first off you didn't specify the date format you were passing. Therefore accepting whatever format the professor had setup. This is a bad plan, to be safe always specify your date format and don't depend on the default. Defaults can and are changed too often. This is a good lesson why you should always specify the actual date format you're using. Try the following to see the difference:
with ds as
(select '01-jan-18' dt_stg from dual)
select to_date(dt_stg), to_date(dt_stg, 'dd-mon-rr') from ds;
Secondly, seems the assignment was to create a procedure that could update any column. This procedure can update only a column having the same type as "aa_employee.emp_dob%TYPE",presumable a date, but it cannot update any other column type.
Finally, if your trying to figure out what professor thinks you did wrong, then try something strange: ask your professor!

Stored procedure enabling a user to lend multiple books to a borrower

I'm having a lot of trouble trying to work this out. Essentially, I'm trying to create a procedure in Oracle SQL Developer which enables two books to be lent out to a borrower. The tables and values are correctly setup. I feel like my created procedure may be pretty close (on the right track), but I get confused about the syntax, especially with the dates and when trying to call the procedure.
There are a few other related tables in the schema, but the gist is I'm trying to insert library/borrower records into a table called loan. The values being inserted are: 2x isbn, branchid, cardno, dateout (when book/s are borrowed) and datein (null by default, until book/s are returned). These are the column names in the loan table.
This is the procedure I've been working on:
create or replace procedure BorrowTwoBooks(
p_isbn in varchar2,
p_isbn2 in varchar2,
p_branchid in number,
p_cardno in number
)
is
pDate Date Default SysDate;
begin
insert into loan values(p_isbn, p_branchid, p_cardno, pDate, null);
insert into loan values(p_isbn2, p_branchid, p_cardno, pDate, null);
end BorrowTwoBooks;
and this is an example of how I'd try to call the procedure once it's created:
begin
BorrowTwoBooks(
'9-9996751-3-1','1','489',pDate);
'1-8744165-3-2','1','489',pDate);
end;
where I'm hoping the syntax would be:
begin
BorrowTwoBooks(
'[isbn1],'[branchid],[cardno],[dateout]);
'[isbn2],'[branchid],[cardno],[dateout]);
end;
Any help would be greatly appreciated. This is my first post, thanks everyone in advance for the help. :)
for your procedure the syntax would be:
begin
BorrowTwoBooks([isbn1],[isbn2],[branchid],[cardno]);
end;
try to call:
begin
BorrowTwoBooks('9-9996751-3-1','1-8744165-3-2','1','489');
end;
Yoc created procedure that takes 4 parameters. Two of them are ISBNs of books and two others are common for both books so call should look like:
begin
BorrowTwoBooks(
'9-9996751-3-1','1-8744165-3-2',1,489);
end;
Also date is not a parameter of function. You set it to sysdate when procedure called.
You already got the answer regarding the specific case, but it seems to me that you want a procedure that have date as a parameter that is sysdate by default, but can be populated with some other date if needed.
If this is the case, your procedure should look like this:
create or replace procedure BorrowTwoBooks(
p_isbn in varchar2,
p_isbn2 in varchar2,
p_branchid in number,
p_cardno in number,
p_date in date default sysdate)
is
begin
insert into loan(isbn, branchid, cardno, dateout, datein)
values(p_isbn, p_branchid, p_cardno, p_date, null);
insert into loan(isbn, branchid, cardno, dateout, datein)
values(p_isbn2, p_branchid, p_cardno, p_date, null);
end BorrowTwoBooks;
You can call it without providing date:
begin
BorrowTwoBooks('9-9996751-3-1', '1-8744165-3-2', '1', '489');
end;
Or you can call it with the specific date:
declare
l_date date;
begin
l_date := to_date('2016/10/05', 'yyyy/mm/dd');
BorrowTwoBooks('9-9996751-3-1', '1-8744165-3-2', '1', '489', l_date);
end;
There is another way to call the procedure - by providing parameter names. This syntax may be easier for you to understand:
begin
BorrowTwoBooks(p_isbn => '9-9996751-3-1',
p_isbn2 => '1-8744165-3-2',
p_branchid => '1',
p_cardno => '489');
end;

Time constraint on a sql trigger

I have the following table called employees
create table employees
(
eno number(4) not null primary key,
ename varchar2(30),
zip number(5) references zipcodes,
hdate date
);
And I'm trying to set a trigger on the table that will fire before an update or delete that will check the system time first to see if the time is between 12:00-13:00, if it is it will allow the insertion, otherwise prevent it.
My guess is so far:
CREATE or REPLACE TRIGGER twelve_one
BEFORE INSERT or Update ON employees
BEGIN
IF
....
ELSE
....
END;
But that's how far I've gotten into unfortunately. Can someone please help me to retrieve the system time first? Then how can I set up that IF ELSE block? And finally How to abort the transaction/insertion/update?
I'm using Oracle SQL Developer 4.02.15
Many Thanks
I assume you must declare temporary variable to set time now, and then compare the temporary variable.
CREATE OR REPLACE TRIGGER TWELVE_ONE
BEFORE INSERT OR UPDATE
ON EMPLOYEES
FOR EACH ROW
DECLARE
V_DATE VARCHAR2 (10);
BEGIN
SELECT TO_CHAR (SYSDATE, 'hh24:mi:ss') INTO V_DATE FROM DUAL;
IF (V_DATE >= '12:00:01' AND V_DATE < '13:00:00')
THEN
INSERT INTO TABLE ..
ELSE
UPDATE TABLE...
END IF;
END;