this is my table
CREATE TABLE accounts (
accountid VARCHAR(255),
name VARCHAR2(255),
phone_number INTEGER,
email_addresses VARCHAR2(255),
account_number VARCHAR(255),
password VARCHAR2(255)
);
and now i created one procedure
create or replace PROCEDURE getaccount (
param1 IN VARCHAR2
) AS
BEGIN
DBMS_OUTPUT.PUT_LINE(' SELECT
accountid,
password
FROM
accounts
WHERE
account_number = '||param1) ;
END getaccount;
and also why we used || or operator
second i run this code in SQLDEVELOPER
I GET THIS OUT
call getaccount('123456');
Call completed.
GET THIS MESSAGE
NOW I AM CONNECTING TO JAVA
HERE IS MY CODE IN JAVA
CallableStatement pst = Get.connection().prepareCall("{call getAccount(?)}");
pst.setString(1, Number);
ResultSet rs = pst.executeQuery();
if (rs.next()) {
System.out.println(rs.getString(1));
here Get.connection return Connection .
after i run this i get this error
Enter Account Number : 123456
java.sql.SQLException: Cannot perform fetch on a PLSQL statement: next
at ojdbc10/oracle.jdbc.driver.InsensitiveScrollableResultSet.next(InsensitiveScrollableResultSet.java:409)
at bank.services.SignValidator.getBank(SignValidator.java:20)
at bank.services.KingobankMain.getBank(KingobankMain.java:49)
at bank.services.KingobankMain.main(KingobankMain.java:14)
Your procedure does not return values (output variable ) and you are trying to get data.
This results in an error.
Stored Procedure OUT Parameters:
reate or replace procedure getaccount (
p_account_number in varchar2,
p_account_id out varchar2,
p_password out varchar2
) as
begin
select
accountid,
password
into
p_account_id,
p_password
from
accounts
where
account_number = p_account_number ;
end getaccount;
/
CallableStatement pst = Get.connection().prepareCall("{call getAccount(?,?,?)}");
pst.setString(1, "....");//set account number
pst.registerOutParameter(2, OracleTypes.VARCHAR);
pst.registerOutParameter(3, OracleTypes.VARCHAR);
pst.execute();
//read the OUT parameter now
System.out.println("AccountID="+pst.getString(2)+",password="+pst.getString(3));
..........your of code....
Stored Procedure Oracle SYS_REFCURSOR:
create or replace procedure getaccount (
p_account_number in varchar2,
p_cur out sys_refcursor
) as
begin
open p_cur for
select
accountid,
password
from
accounts
where
account_number = p_account_number ;
end getaccount;
/
CallableStatement pst = Get.connection().prepareCall("{call getAccount(?,?)}");
pst.setString(1, ".....");// set account number
pst.registerOutParameter(2, OracleTypes.CURSOR);
pst.execute();
//read the OUT parameter now
rs = (ResultSet) pst.getObject(2);
while(rs.next()){
System.out.println("AccountID="+rs.getString("accountid")+",password="+rs.getString("password"));
..........your of code....
}
Addition links:
JDBC Basics
Calling PL/SQL from Java
I don't know Java, but: procedure you wrote results in output displayed on the screen, but only if tool you used to call the procedure supports it - e.g. SQL*Plus, SQL Developer, TOAD and similar. For the rest, there will be no result at all.
It looks as if you wanted to run
select accountid, password from accoutns where account_number = 123456
in Java. You should then use a function instead of a procedure. It should return a VARCHAR2 (that select statement) and then you'd execute it in Java. How? Can't tell; as I said, I don't know Java. In Oracle, you'd use dynamic SQL.
Or, if it has to be a procedure, then it should have an OUT parameter so that it returns that select statement to the caller. But, caller then has to have "something" (a variable?) to accept that output into.
As you requested, a procedure with an OUT parameter:
CREATE OR REPLACE PROCEDURE getaccount (param1 IN VARCHAR2,
par_query OUT VARCHAR2)
AS
BEGIN
par_query :=
'SELECT accountid, password FROM accounts WHERE '
|| ' account_number = '
|| DBMS_ASSERT.enquote_literal (param1);
END getaccount;
Note dbms_assert, which is used to prevent SQL injection.
In order to run it in Oracle, you'd have to use a PL/SQL block with a variable that accepts the result returned by that procedure.
SQL> set serveroutput on
SQL>
SQL> create or replace procedure getaccount (param1 in varchar2,
2 par_query out varchar2)
3 as
4 begin
5 par_query :=
6 'SELECT accountid, password FROM accounts WHERE '
7 || ' account_number = '
8 || dbms_assert.enquote_literal (param1);
9 end getaccount;
10 /
Procedure created.
SQL> declare
2 l_out varchar2(200);
3 begin
4 getaccount('12345', l_out);
5 dbms_output.put_line('Result is: ' || l_out);
6 end;
7 /
Result is: SELECT accountid, password FROM accounts WHERE account_number = '12345'
PL/SQL procedure successfully completed.
SQL>
Apparently, you don't want to return a command represented as a string, but result that is produced by that select statement. As commented, consider returning a refcursor. Moreover, use a function instead of a procedure; they are designed to "return" a value. If it is a procedure, you'll have to create OUT parameter(s) and accept their values into something (local variables, probably).
Suppose this is table's contents:
SQL> select * From accounts;
ACCOUNTID PASSWORD ACCOUNT_NUMBER
---------- ---------- --------------------
1 my_pwd 12345
SQL>
Function that returns refcursor:
SQL> create or replace function getaccount (param1 in varchar2)
2 return sys_refcursor
3 is
4 l_rc sys_refcursor;
5 begin
6 open l_rc for
7 'SELECT accountid, password FROM accounts WHERE '
8 || ' account_number = '
9 || dbms_assert.enquote_literal (param1);
10 return l_rc;
11 end getaccount;
12 /
Function created.
SQL> select getaccount('12345') from dual;
GETACCOUNT('12345')
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ACCOUNTID PASSWO
---------- ------
1 my_pwd
SQL>
Or, a procedure with 2 OUT parameters:
SQL> create or replace procedure getaccount
2 (param1 in varchar2,
3 p_accid out varchar2,
4 p_pwd out varchar2) is
5 begin
6 select accountid, password
7 into p_accid, p_pwd
8 from accounts
9 where account_number = param1;
10 end;
11 /
Procedure created.
SQL> set serveroutput on
SQL> declare
2 l_id varchar2(20);
3 l_pwd varchar2(20);
4 begin
5 getaccount('12345', l_id, l_pwd);
6 dbms_output.put_line('ID = ' || l_id ||', PWD = ' || l_pwd);
7 end;
8 /
ID = 1, PWD = my_pwd
PL/SQL procedure successfully completed.
SQL>
Related
I'am creating dynamic tables from java. What I want is that I want to create a trigger on every new table added which will just use the sequence to populate the primary key(serial_no) which is common in every table.How to achieve this ???
EDIT:
I have tried this code but I'am getting a message "procedure created with compilation errors"
create or replace procedure "TRIGGER_CALL" (trigger_name IN VARCHAR2, table_name IN VARCHAR2, sno IN NUMBER) as begin CREATE SEQUENCE abc MINVALUE 1 MAXVALUE 10000 INCREMENT BY 1 START WITH 141 CACHE 20 NOORDER NOCYCLE; CREATE OR REPLACE TRIGGER trigger_name before insert on table_name for each row begin select s_no.nextval into :new.sno from dual; end; end;
EDIT2:
My code
CREATE OR REPLACE
PROCEDURE "TRIGGER_CALL" (p_table_name IN VARCHAR2)
AUTHID CURRENT_USER
AS
l_sql VARCHAR2(4000);
l_dummy NUMBER;
l_trigger_name VARCHAR2(30);
l_seq_name VARCHAR2(30);
BEGIN
--SELECT '1'
--INTO l_dummy
--FROM all_tables
-- WHERE table_name = UPPER(p_table_name);
l_trigger_name := p_table_name || '_trg';
l_seq_name := p_table_name || 's_no';
EXECUTE IMMEDIATE 'CREATE SEQUENCE l_seq_name start with 1 increment by 1 ';
l_sql :=
'CREATE OR replace TRIGGER ' || l_trigger_name ||
' BEFORE INSERT ON ' || p_table_name ||
' FOR EACH ROW
BEGIN
SELECT l_seq_name.NEXTVAL
INTO :new.sno
FROM dual;
END;';
EXECUTE IMMEDIATE l_sql;
END;
/
Please check following code:
CREATE SEQUENCE my_sequence;
/
CREATE OR REPLACE
PROCEDURE "TRIGGER_CALL" (p_table_name IN VARCHAR2)
AUTHID CURRENT_USER
AS
l_sql VARCHAR2(4000);
l_dummy NUMBER;
l_trigger_name VARCHAR2(30);
BEGIN
-- Validate if a p_table_name is a valid object name
-- If you have access you can also use DBMS_ASSERT.SQL_OBJECT_NAME procedure
SELECT '1'
INTO l_dummy
FROM all_tables
WHERE table_name = UPPER(p_table_name);
l_trigger_name := p_table_name || '_trg';
l_sql :=
'CREATE OR replace TRIGGER ' || l_trigger_name ||
' BEFORE INSERT ON ' || p_table_name ||
' FOR EACH ROW
BEGIN
SELECT my_sequence.NEXTVAL
INTO :new.sno
FROM dual;
END;';
EXECUTE IMMEDIATE l_sql;
END;
/
CREATE TABLE my_test(sno NUMBER);
/
BEGIN
trigger_call('my_test');
END;
/
Important notes:
Usage of AUTHID CURRENT_USER eliminates the "insufficient privileges" problem. For reference see: Execute Immediate within a stored procedure keeps giving insufficient priviliges error
Because the dynamic sql simply concatenates the input parameter it needs to be validated to protect against SQL Injection. See also DBMS_ASSERT.
Because of point 2. I used table name to build trigger name.
I have following table:
create table INTERNATIONALIZATION (
ID number not null unique,
LANG char(2) not null,
EXT_ID number not null,
EXT_COLUMN char(32) not null,
EXT_NAME char(32) not null,
TRANS_VAL nvarchar2(512) not null
);
And following code that aims to retrieve one and only one result from it (I am 100% sure that record exists).
public Optional<String> getTranslation(long idSkill, Locale lang, String extColumn, String extName) {
try {
return Optional.of(jdbcTemplate.queryForObject("select TRANS_VAL from INTERNATIONALIZATION where ext_id = ? and lang = ? and ext_column = ? and ext_name = ?", String.class, idSkill, lang.toLanguageTag(), extColumn, extName));
} catch (IncorrectResultSizeDataAccessException ex) {
return Optional.empty();
}
}
The problem is that when I always get the Optional.empty() as the IncorrectResultSizeDataAccessException is thrown, because no records are found.
When I execute this sql query in Oracle SQL Developer, I get the correct result.
What is causing this problem? Could it have something to do with nvarchar2 type of desired column?
You probably need to verify the arguments passed to the query. They may not be the same as those you used at Oracle SQL Developer.
For debugging, when you catch the exception, print the values used.
try {
return Optional.of(jdbcTemplate.queryForObject("select TRANS_VAL from INTERNATIONALIZATION where ext_id = ? and lang = ? and ext_column = ? and ext_name = ?", String.class, idSkill, lang.toLanguageTag(), extColumn, extName));
} catch (IncorrectResultSizeDataAccessException ex) {
return Optional.empty();
// print idSkill, lang.toLanguageTag(), extColumn, extName here
}
Also, as you are using CHAR columns, you have to take care with the white spaces padded when comparing. As you are using bind variables, there might be a issue when comparing chars against varchars.
Created a test table:
SQL> create table t1 (c1 char(5));
Table created.
SQL> insert into t1 values ('A');
1 row created.
SQL> commit;
Commit complete.
Comparing with literals, no problem:
SQL> select count(*) from t1 where c1 = 'A';
COUNT(*)
----------
1
SQL> select count(*) from t1 where c1 = 'A ';
COUNT(*)
----------
1
As the c1 is a char column, the data is padded to the left:
SQL> select '<'|| c1 || '>' from t1;
'<'||C1
-------
<A >
When comparing with a varchar2 bind variable
SQL> var s varchar2(5)
SQL> exec :s := 'A' ;
PL/SQL procedure successfully completed.
SQL> select count(*) from t1 where c1 = :s;
COUNT(*)
----------
0
Data has to be equal (5 characteres - one letter, 4 spaces):
SQL> exec :s :='A '
PL/SQL procedure successfully completed.
SQL> select count(*) from t1 where c1 = :s;
COUNT(*)
----------
1
That's just a tip, but I think you would be better off using varchar2 columns:
create table INTERNATIONALIZATION (
ID number not null unique,
LANG varchar2(2) not null,
EXT_ID number not null,
EXT_COLUMN varchar2(32) not null,
EXT_NAME varchar2(32) not null,
TRANS_VAL nvarchar2(512) not null
);
I have written a simple function in PostgreSQL database. From my JAVA source code I am calling this function like
SELECT getData('active');
I am getting the data correct but the table header of the dataset is showing my function name (getdata) not userid and username. In this situation how I can get data?
CREATE or REPLACE FUNCTION getData(value text)
RETURNS TABLE(
userid integer,
username varchar(50)
) AS -- text AS --
$body$
DECLARE
fullsql TEXT;
records RECORD;
exeQuery TEXT;
BEGIN
fullsql:= 'SELECT userid, username from user_index where status='''value'''';
exeQuery := 'SELECT * FROM (' || fullsql || ') AS records';
RETURN QUERY EXECUTE exeQuery;
END
$body$
LANGUAGE plpgsql;
Currently the output is
getdate
--------------
501,alexanda
502,cathie
But I want to output like:
userid username
------|---------
501,alexanda
502,cathie
i am trying to acheive following:
SELECT usr.username FROM cust_invoice_index as inv
INNER JOIN
(SELECT getdata('active')) as usr ON (usr.userid=inv.userid_edit)
Following query is working fine:
SELECT usr.username FROM cust_invoice_index as inv
INNER JOIN
(SELECT userid, username from user_index where status='active') as usr ON (usr.userid=inv.userid_edit)
As your function returns a result set you should be using select * from getdata('active').
Don't put calls to set returning functions into the select list.
SELECT usr.username
FROM cust_invoice_index as inv
JOIN (SELECT * FROM getdata('active')) as usr ON usr.userid=inv.userid_edit
I have created a single procedure for update for different table say country & department.
and in procedure i'hve mentioned an input parameter for table name along with other parameter.
But unfortunately i got an error. Here is mySql Procedure:
CREATE DEFINER=`satish`#`%` PROCEDURE `p_update_Master_Name`(
IN tbl_Name VARCHAR(35),
IN tbl_column_old_value VARCHAR(35),
IN tbl_column_new_value VARCHAR(35),
IN tbl_user_id INT,
OUT msg INT
)
BEGIN
IF EXISTS (SELECT Name from tbl_name where Name = tbl_column_new_value) then
SET msg := '1';
-- failed case
else
UPDATE tbl_name SET Name= tbl_column_value, Modified_Date=now(), Modified_by=tbl_user_id where Name = tbl_column_old_value;
set msg := '0';
-- success
END IF;
END
Im calling this procedure from java file.
CallableStatement cs = conn.prepareCall("{ call p_update_Master_Name(?,?,?,?,?)}");
cs.setString(1, "country");
cs.setString(2, real);
cs.setString(3, mod);
cs.setInt(4, 01);
cs.execute();
cs.registerOutParameter(5, Types.INTEGER);
int i=cs.getInt(5);
but it gives me a mysql.jdbc exception.
com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Table 'sims.tbl_name' doesn't
exist
Please help me. Thanx in advance
You can't use variables to define table or column (or any other db object for that matter) names in static SQL queries. They should be literals.
You have to use dynamic SQL to achieve your goal. Read more on the topic SQL Syntax for Prepared Statements
Your stored procedure might look like
DELIMITER $$
CREATE PROCEDURE p_update_Master_Name
(
IN tbl_Name VARCHAR(35),
IN tbl_column_old_value VARCHAR(35),
IN tbl_column_new_value VARCHAR(35),
IN tbl_user_id INT,
OUT msg INT
)
BEGIN
SET #sql = CONCAT('SELECT (COUNT(*) > 0) INTO #result FROM ', tbl_name, ' WHERE Name = \'', tbl_column_new_value, '\'');
PREPARE stmt FROM #sql;
EXECUTE stmt;
SET msg = #result;
IF #result = 0 THEN
SET #sql = CONCAT('UPDATE ', tbl_name,
' SET Name = \'', tbl_column_new_value,
'\', Modified_Date = NOW(), Modified_by = ', tbl_user_id,
' WHERE Name = \'', tbl_column_old_value, ' \'');
PREPARE stmt FROM #sql;
EXECUTE stmt;
END IF;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
Here is SQLFiddle demo
It seems there is some error with the procedure syntax
wrong one:
1. SELECT Name from *tbl_name* where Name = tbl_column_new_value) then
SET msg := '1'
In the above line of code you didn't set any value to tal_name;
You can refer the below syntax concentrate on INTO in the query:
CREATE OR REPLACE PROCEDURE getDBUSERByUserId(
p_userid IN DBUSER.USER_ID%TYPE,
o_username OUT DBUSER.USERNAME%TYPE,
o_createdby OUT DBUSER.CREATED_BY%TYPE,
o_date OUT DBUSER.CREATED_DATE%TYPE)
IS
BEGIN
SELECT USERNAME , CREATED_BY, CREATED_DATE
INTO o_username, o_createdby, o_date
FROM DBUSER WHERE USER_ID = p_userid;
END;
I have a requirement where I have to call a MySql Stored Procedure with three IN parameters and 6 OUT parameters.
PROCEDURE
DELIMITER $$
DROP PROCEDURE IF EXISTS GET_PRODUCT_INFO $$
CREATE PROCEDURE GET_PRODUCT_INFO(IN productName varchar(25),
IN divisionID int(11), IN productQuantity int(11),
OUT Price double, OUT price_without_vat double,
OUT vat double, OUT Quantity int, OUT ProductsId int, OUT ExpDate date)
BEGIN
select I.quantity into Quantity from ProductInventory I
where I.pname=productName and I.divid=divisionID ;
if Quantity > productQuantity THEN
select P.productID,P.price,P.price_without_vat,P.vat, I.quantity,P.ExpiryDate
into ProductsId,Price,price_without_vat,vat,Quantity,ExpDate
from product P,ProductInventory I
where P.pname=productName and I.pname=productName
and P.orgid=divisionID and I.divid=divisionID ;
update productinventory
set quantity=(quantity-productQuantity)
where pname=productName and divID=divisionID;
END IF;
END $$
call GET_PRODUCT_INFO('Crocin',1,2,#Price,#price_without_vat,#vat,#Quantity,#ProductsId,#ExpiryDate)$$
Here I am able to retrieve the record in mysql cmd prompt...
But whenever I am trying to call the procedure from my JDBC code am getting this error
EXCEPTION
java.sql.SQLException: Parameter index of 9 is out of range (1, 8)
at com.mysql.jdbc.CallableStatement.checkParameterIndexBounds(CallableStatement.java:1002)
at com.mysql.jdbc.CallableStatement.checkIsOutputParam(CallableStatement.java:971)
callableStatement = (CallableStatement)con.prepareCall("{call GET_PRODUCT_INFO(?,?,?,?,?,?,?,?,?)}");
callableStatement.setInt(2, 1);
callableStatement.setInt(3, quantity);
callableStatement.registerOutParameter(4, Types.DOUBLE);
callableStatement.registerOutParameter(5, Types.DOUBLE);
callableStatement.registerOutParameter(6, Types.DOUBLE);
callableStatement.registerOutParameter(7, Types.INTEGER);
callableStatement.registerOutParameter(8, Types.INTEGER);
callableStatement.registerOutParameter(9, Types.DATE);--->Exception here
callableStatement.setString(1, "SomeText");
Include this too. You've missed out 1 parameter.