PL SQL Insert index - oracle

I need to insert into a table 500.000 records, so the process will take a while. I read about the indexes, that increase the speed of a query, but the question is next: on which parameter should I set the index in order to make the INSERT faster? (the id?).
Thanks.
Edited
CREATE OR REPLACE PROCEDURE addNewUser(
firstName IN VARCHAR2,
lastName IN VARCHAR2,
email IN VARCHAR2,
username IN VARCHAR2,
password IN VARCHAR2,
job IN VARCHAR2) AS
v_usersCount NUMBER := 0;
v_userID NUMBER := 0;
BEGIN
SELECT COUNT(*) INTO v_usersCount
FROM Users;
v_userID := v_usersCount + 1;
INSERT INTO Users VALUES(v_userID,firstName,lastName,email,username,password,job);
END addNewUser;
and the data is added like this :
FOR i IN 1..50000
LOOP
addNewTask('Task 1', 'Just Starter', 'High', 1, 'This is a description task.', 'Task Comment', '20-08-2015', 1);
END LOOP;

You are doing a query for each insertion, which makes it slow.
Try calculate the ID outside your stored and pass it to the procedure, so you don't have to query it in your procedure every time.

SELECT COUNT(*)... is one of slowest things you can do in any program. This requires reading every row in the table - so if you're inserting 1000 rows the first time it reads zero rows (fast), next time 1 row (fast), next time 2 rows...and eventually you've executed 1000 queries and read 499500 rows (sum of 0 through 999).
In this case you should use a SEQUENCE to generate non-repeating numbers. I'd rewrite your code as:
CREATE SEQUENCE VALUE_SEQ; -- just take defaults for all parameters
CREATE OR REPLACE PROCEDURE addNewUser(
firstName IN VARCHAR2,
lastName IN VARCHAR2,
email IN VARCHAR2,
username IN VARCHAR2,
password IN VARCHAR2,
job IN VARCHAR2) AS
BEGIN
INSERT INTO Users
VALUES(VALUE_SEQ.NEXTVAL, firstName,lastName,
email,username,password,job);
END addNewUser;

Related

Oracle stored procedure with a query where some search criteria may be missing

I am using Oracle 12c and have a stored procedure that accepts 4 input fields, queries database using the same and return result set. However, these 4 input fields are user input values from front-end so user may or may not enter all 4 input fields. I would need to execute stored procedure with whatever values it receives and ignore the rest.
stored procedure definition:
procedure retrieve_data (
p_sn_no in integer,
p_name in varchar2,
p_city in varchar 2,
p_phone in integer,
return_msg out number)
is begin
select count(*) into return_msg from <table_name>
where sn_no=p_sn_no and name=p_name
and city=p_city and phone=p_phone
end
The requirement is to invoke the above stored procedure with any or all of the input parameters but how to prepare the select statement within the stored procedure with all or few input fields, something like select count(*) into return_msg from <table_name> where sn_no=p_sn_no instead of passing all 4 input fields?
Try this:
procedure retrieve_data
(return_msg out number,
p_sn_no in integer DEFAULT NULL,
p_name in varchar2 DEFAULT NULL,
p_city in varchar2 DEFAULT NULL,
p_phone in integer DEFAULT NULL)
is
begin
select count(*)
into return_msg
from
where sn_no = NVL(p_sn_no, sn_no)
and name = NVL(p_name, name)
and city = NVL(p_city, city)
and phone = NVL(p_phone, phone)
end
The stored procedure call still passes all input parameter values, only those that are not provided by the user will have NULL values, so your query should take advantage of that:
select count(*) into return_msg from <table_name>
where (sn_no=p_sn_no or p_sn_no is null)
and (name=p_name or p_name is null) -- etc.
...

PL-SQL delete value from variable

In a PL SQL procedure I've a variable(declare as NUMBER) as follows,
Store_Values
I'm loading some data into this variable by select query.So if this data matches to the value(some value which will be compared against variable in if statement),then how to delete matched value from variable.
below is the procedure:
CREATE OR REPLACE PROCEDURE UPDATE_SIG_NAME_MAPS(SignatureID NUMBER, RuleCateory VARCHAR2, SignatureMessage VARCHAR2, IsDelete NUMBER, IsNew NUMBER) AS
NumberOfValues NUMBER ;
BEGIN
select VALUE BULK COLLECT into NumberOfValues from list_details where LIST_CONFIG_ID in(fetching from other table's);
if NumberOfValues = SignatureID then
**delete from sometable with where clause**
end if;
insert variable remaining values to the table using for loop
END ;
/
As #Aleksej said, you are trying to fetch into a scalar variable using bulk collect so you need to declare your varible as below:
You can follow the instructions and modify your code accordingly.
CREATE OR REPLACE PROCEDURE UPDATE_SIG_NAME_MAPS (
SignatureID NUMBER,
RuleCateory VARCHAR2,
SignatureMessage VARCHAR2,
IsDelete NUMBER,
IsNew NUMBER)
AS
Type NumberOfValue is table of NUMBER;
NumberOfValues NumberOfValue;
BEGIN
SELECT VALUE
BULK COLLECT INTO NumberOfValues
FROM list_details
WHERE LIST_CONFIG_ID IN (fetching from other table's);
For rec in 1..NumberOfValues.count
loop
if NumberOfValues(rec) = SignatureID then
**delete from sometable with where clause**
insert variable remaining values to the table
end loop;
END ;

Taking multiple value from Oracle Apex page and store it in an table

I have developed 1 apex page where I have one text field. I will insert multiple values by separating it through a comma. I want that when I hit the submit button then it should separate the values on the basis of comma and should insert individually in different rows. For example if I pass "abc,cde,efgh,ijhk,gygg" in my textfield then it should insert "abc" in one row,"cde" in another row and so on. and also it should not through any error when I insert only one value.
I am able to store the value for only one data as I have created a procedure and that procedure takes only one data but I am not getting an idea of if I pass multiple values by separating it via comma then it should insert. I am posting my procedure here.
create or replace procedure Exclude_items(
p_analyze_name in varchar2,
p_material_number in varchar2
)
as
p_analyze_id number;
begin
select analyze_id
into p_analyze_id
from analyzes
where table_name = p_analyze_name;
insert into p20da.test_vishal(ANALYZE_ID,MATNR,) values(p_analyze_id,p_material_number)
end;
Here matnr will be having multiple values separated by comma as it is a text field in apex page but analyze_id will be constant.
I want to write the procedure so that it could separate whenever a comma comes and should not through any error if I only insert one value.
You should take advantage of STRING_TO_TABLE function of APEX_UTIL package. Add below code to Submit process, your exclude_items procedure stays the same.
DECLARE
L_MATERIAL_NUMBER APEX_APPLICATION_GLOBAL.VC_ARR2;
BEGIN
L_MATERIAL_NUMBER := APEX_UTIL.STRING_TO_TABLE(:P2_MATERIAL_NUMBER,',');
FOR I IN 1..L_MATERIAL_NUMBER.COUNT
LOOP
EXCLUDE_ITEMS('tablea', L_MATERIAL_NUMBER(I));
END LOOP;
END;
More Information on API Package Function --> http://docs.oracle.com/cd/E11882_01/appdev.112/e12510/apex_util.htm#CHDFEEJD
How about something like:
create or replace procedure exclude_items( p_analyze_name in varchar2, p_material_number in varchar2 )
as
comma_pos number;
sub_name varchar2(4000);
temp_name varchar2(4000);
p_analyze_id number;
begin
select analyze_id
into p_analyze_id
from analyzes
where table_name = p_analyze_name;
temp_name := p_material_number;
LOOP
comma_pos := instr( temp_name, ',' );
exit when comma_pos = 0;
sub_name := substr( temp_name,1,comma_pos-1 );
insert into p20da.test_vishal(ANALYZE_ID,MATNR,) values(p_analyze_id,sub_name)
temp_name := substr( temp_name, comma_pos + 1 );
END LOOP;
insert into p20da.test_vishal(ANALYZE_ID,MATNR,) values(p_analyze_id,temp_name)
end;
/

How can implement a procedure in ESQL (an internal procedure) from Oracle database

I create a store procedure in Oracle db that insert Customer to my Table
this is my code :
CREATE OR REPLACE PROCEDURE THP.INSERT_CUSTOMER(
P_CUSTNAME IN VARCHAR2,
P_CUSTLAST IN VARCHAR2,
P_CUSTFATHER IN VARCHAR2,
P_NATIONNO IN NUMBER,
P_BIRTHDAY IN VARCHAR2,
P_BIRHTPLACE IN VARCHAR2,
P_EMAIL IN VARCHAR2,
P_CUSTENAME IN VARCHAR2,
P_CUSTELAST IN VARCHAR2,
P_OWNID IN NUMBER,
P_CUSTTYPEID IN NUMBER,
P_GENDERID IN NUMBER,
P_BILLSTID IN NUMBER,
P_BILLSPID IN NUMBER,
P_IDNO IN varchar2,
RESULT OUT INTEGER) IS
CNT NUMBER;
BEGIN
RESULT := 1;
CNT := 0;
SELECT COUNT(1) INTO CNT FROM THP.TBCUSTOMER WHERE NATIONNO=P_NATIONNO ;
IF CNT=1 THEN
COMMIT;
RESULT := 1; --IF RECORD is EXIST
ELSE
BEGIN
INSERT INTO TBCUSTOMER(CUSTID,CUSTNAME,CUSTLAST,CUSTFATHER,NATIONNO,BIRTHDAY,BIRHTPLACE,EMAIL,CUSTENAME,CUSTELAST,OWNID,CUSTTYPEID,GENDERID,BILLSTID,BILLSPID,IDNO)
VALUES(CUSTID_SEQ.NEXTVAL,P_CUSTNAME,P_CUSTLAST,P_CUSTFATHER,P_NATIONNO,P_BIRTHDAY,P_BIRHTPLACE,P_EMAIL,P_CUSTENAME,P_CUSTELAST,P_OWNID,P_CUSTTYPEID,P_GENDERID,P_BILLSTID,P_BILLSPID,P_IDNO);
COMMIT;
RESULT :=0; --IF INSERT NEW COLUMN
END;
END IF;
END INSERT_CUSTOMER;
/
now I want use this procedure in ESQL and create it directly in ESQL not CALL it from Oracle database or other DB
would you please guide me a bout it...
General comments, not an answer ...
count(1)
count(1) = count(*), which is the standard form for "count the number of rows". count(1) has no advantages, so best to use count(*).
RESULT := 1
is redundant at the beginning of the procedure
CNT := 0
... also redundant. The variable name is not very meaningful, and might make people think of a rude word, so perhaps change it to rows_found.
Prefixing the arguments with P_ is not required. If you use one of them in a SQL statement and need to deconflict it from a database object name then prefix it with the procedure name, so you have:
WHERE NATIONNO= INSERT_CUSTOMER.NATIONNO
Is NATIONNO constrained to be unique in the customer table? If not, use:
SELECT COUNT(*)
INTO CNT
FROM THP.TBCUSTOMER
WHERE NATIONNO=INSERT_CUSTOMER.NATIONNO AND
ROWNUM = 1;
(12g will introduce the LIMIT SQL syntax, by the way).
Commiting in a procedure is often held to be bad practice, as the procedure often becomes part of a longer business transaction (eg. inserting a new customer and address) and the commit should be controlled by the application code.
Upper case code is harder to read than lower case -- that's why direction signs on motorways are not uppercase.
The begin-end block for the insert is not required at all.
"birhtplace" is spelled wrong.
So I'd suggest that what you want to convert to ESQL is actually:
create or replace procedure thp.insert_customer(
custname in varchar2,
custlast in varchar2,
custfather in varchar2,
nationno in number ,
birthday in varchar2,
birhtplace in varchar2,
email in varchar2,
custename in varchar2,
custelast in varchar2,
ownid in number ,
custtypeid in number ,
genderid in number ,
billstid in number ,
billspid in number ,
idno in varchar2,
result out integer) is
rows_found number;
begin
select count(*)
into rows_found
from thp.tbcustomer
where nationno=insert_customer.nationno;
if rows_found = 1 then
result := 1;
else
insert into
tbcustomer(
custid ,
custname ,
custlast ,
custfather,
nationno ,
birthday ,
birthplace,
email ,
custename ,
custelast ,
ownid ,
custtypeid,
genderid ,
billstid ,
billspid ,
idno)
values(
custid_seq.nextval,
custname ,
custlast ,
custfather,
nationno ,
birthday ,
birthplace,
email ,
custename ,
custelast ,
ownid ,
custtypeid,
genderid ,
billstid ,
billspid ,
idno);
result :=0;
end if;
end insert_customer;
/
To call an external procedure via ESQL, you need to first declare the external function.
Do it as below:
CREATE PROCEDURE DoSomething (IN in1 CHARACTER, OUT out1 CHARACTER, OUT out2 CHARACTER)
LANGUAGE DATABASE
EXTERNAL NAME "DoSomething";
Now you can call this function from your ESQL function as below:
CALL DoSomething(in,out1,out2) IN Database.yourschema.yourDB;
P.S. The parameters you are passing must be compatible with the parameters of your stored procedure.

Concurrency problems with stored procedure

I need help. I have the following stored procedure but I have concurrency problems. Anybody can tell me how to modify the stored procedure to avoid duplicate key error because two users make the same selection at once?. The primary key is the field IDSOLICITUD and the table os SOLIC, that is numeric and I want to insert into this table a counter each time you access it and return that value to the calling application. The structure of the table I can not change, I can not put a AutoNumber.
CREATE procedure PRC_SOLIC(FECHA IN DATE, IDTRAMITE IN VARCHAR2, ESTADO IN NUMBER, ESTADO_FECHA IN DATE, MENSAJE_ERROR IN VARCHAR2, CPROVIN IN NUMBER, CMUNICI IN NUMBER, NHABITA IN NUMBER, NDOMICI IN NUMBER, REFORIGEN IN VARCHAR2,OPERACION_TIPO IN VARCHAR2, OPERACION_CODIGO IN NUMBER, USUARIO IN VARCHAR2, FINALIDAD IN VARCHAR2, RESULTADO IN VARCHAR2,NUM OUT NUMBER) is
v_Numero NUMBER;
CURSOR c_Solic is SELECT MAX(IDSOLICITUD)+1 FROM SOLIC;
BEGIN
OPEN c_Solic;
FETCH c_Solic INTO v_Numero;
IF (v_Numero is NULL) THEN
v_Numero := 1;
END IF;
INSERT INTO SOLIC VALUES (v_Numero, FECHA, IDTRAMITE, ESTADO, ESTADO_FECHA, MENSAJE_ERROR, CPROVIN, CMUNICI, NHABITA,
NDOMICI, REFORIGEN, OPERACION_TIPO, OPERACION_CODIGO, USUARIO, FINALIDAD, RESULTADO);
NUM := v_Numero;
close c_Solic;
END PRC_SOLIC;
Thank you.
Your tags are confusing, is it Oracle or MySQL? If Oracle then look into using sequences for this sort of thing. See Managing Sequences. You can then create a sequence such as:
CREATE SEQUENCE IDSOLICITUD_SEQ
START WITH 1
INCREMENT BY 1;
And then in your code:
CURSOR c_Solic is SELECT IDSOLICITUD_SEQ.NEXTVAL FROM SYS.DUAL;
edit based on being unable to use AutoIncrement
The following assumes you are using MySQL, for Oracle please see the other answer
Seeing as you can't change it to be an AutoIncrement you seem to have to resort to to explicitly locking the table using LOCK TABLES
http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html
This gives
CREATE procedure PRC_SOLIC(FECHA IN DATE, IDTRAMITE IN VARCHAR2, ESTADO IN NUMBER, ESTADO_FECHA IN DATE, MENSAJE_ERROR IN VARCHAR2, CPROVIN IN NUMBER, CMUNICI IN NUMBER, NHABITA IN NUMBER, NDOMICI IN NUMBER, REFORIGEN IN VARCHAR2,OPERACION_TIPO IN VARCHAR2, OPERACION_CODIGO IN NUMBER, USUARIO IN VARCHAR2, FINALIDAD IN VARCHAR2, RESULTADO IN VARCHAR2,NUM OUT NUMBER) is
BEGIN
// Declare the variable which will hold the "AI" field
DECLARE thisSolicID INT UNSIGNED DEFAULT 0;
// Lock the table for writing
LOCK TABLES SOLIC WRITE;
// Get the "AI" value
SELECT COALESCE(MAX(IDSOLICITUD),0)+1 INTO thisSolicID FROM FROM SOLIC;
// Insert it
INSERT INTO SOLIC VALUES (thisSolicID, FECHA, IDTRAMITE, ESTADO, ESTADO_FECHA, MENSAJE_ERROR, CPROVIN, CMUNICI, NHABITA, NDOMICI, REFORIGEN, OPERACION_TIPO, OPERACION_CODIGO, USUARIO, FINALIDAD, RESULTADO);
// Unlock the table
UNLOCK TABLES;
END PRC_SOLIC;

Resources