Hello to All stackOverflow goodfellas , I'm so noob in The Procedures with oracle database 21c enterprise edition , As my past background always works with Direct jdbc but now I need to write program with Procedures that call and every time I need to change some Algorithm to call data from database don't change the main code form java . as you know if I do, need compile , build and deploy to server get more time , so going to straight problem view!(I'm not sure is good way or we have better way)
I have two table Like :
CREATE TABLE C##CREATOR.USERS
(
ID NUMBER(11, 0) NOT NULL
, USERNAME VARCHAR2(20 CHAR) NOT NULL
, DATECREATION TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP NOT NULL
, CONSTRAINT USERS_PK PRIMARY KEY
(
ID
)
DEFERRABLE INITIALLY IMMEDIATE
USING INDEX
(
CREATE INDEX C##CREATOR.USERS_PK ON C##CREATOR.USERS (ID ASC)
LOGGING
TABLESPACE DPS_PERMANENT
PCTFREE 10
INITRANS 2
STORAGE
(
INITIAL 65536
NEXT 1048576
MINEXTENTS 1
MAXEXTENTS UNLIMITED
BUFFER_POOL DEFAULT
)
NOPARALLEL
)
ENABLE
)
LOGGING
TABLESPACE DPS_PERMANENT
PCTFREE 10
INITRANS 1
STORAGE
(
INITIAL 65536
NEXT 1048576
MINEXTENTS 1
MAXEXTENTS UNLIMITED
BUFFER_POOL DEFAULT
)
NOCOMPRESS
NO INMEMORY
NOPARALLEL;
And :
CREATE TABLE C##CREATOR.USERPASSWORDS
(
ID NUMBER(11, 0) NOT NULL
, USERID NUMBER(11, 0) NOT NULL
, PASSWORD VARCHAR2(20 BYTE) NOT NULL
, DATECREATION TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP NOT NULL
, CONSTRAINT USERPASSWORDS_PK PRIMARY KEY
(
ID
)
USING INDEX
(
CREATE UNIQUE INDEX C##CREATOR.USERPASSWORDS_PK ON C##CREATOR.USERPASSWORDS (ID ASC)
LOGGING
TABLESPACE DPS_PERMANENT
PCTFREE 10
INITRANS 2
STORAGE
(
INITIAL 65536
NEXT 1048576
MINEXTENTS 1
MAXEXTENTS UNLIMITED
BUFFER_POOL DEFAULT
)
NOPARALLEL
)
ENABLE
)
LOGGING
TABLESPACE DPS_PERMANENT
PCTFREE 10
INITRANS 1
STORAGE
(
INITIAL 65536
NEXT 1048576
MINEXTENTS 1
MAXEXTENTS UNLIMITED
BUFFER_POOL DEFAULT
)
NOCOMPRESS
NO INMEMORY
NOPARALLEL;
As other side In Procedures :
CREATE OR REPLACE PROCEDURE SYSTEM_LOGIN_GET_USER_WITH_PASSWORD
(
INP_USERNAME IN VARCHAR2
, user_cursor OUT SYS_REFCURSOR
) AS
BEGIN
OPEN user_cursor FOR
SELECT USERS.USERNAME , USERS.ID , USERPASSWORDS.PASSWORD FROM USERS
LEFT OUTER JOIN USERPASSWORDS
ON USERS.ID = USERPASSWORDS.USERID WHERE
USERS.USERNAME = INP_USERNAME ORDER BY USERPASSWORDS.DATECREATION DESC
FETCH FIRST 1 ROWS ONLY;
END SYSTEM_LOGIN_GET_USER_WITH_PASSWORD;
If Calling from Java with :
package mehritco.ir.megnatis.dps.repository;
import mehritco.ir.megnatis.dps.repository.rdbms.oracle.OracleConnection;
import mehritco.ir.megnatis.users.User;
import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OracleTypes;
import java.sql.*;
public class RepoUsers {
public User get(User userToFind){
try {
Connection oracleConnection = OracleConnection.getPoolConnection().getConnection();
String queryToGetUser ="{ execute SYSTEM_LOGIN_GET_USER_WITH_PASSWORD(?,?) }";
CallableStatement callableStatement = oracleConnection.prepareCall(queryToGetUser);
callableStatement.setString(1,userToFind.getUsername());
callableStatement.registerOutParameter(2, OracleTypes.CURSOR);
callableStatement.execute();
ResultSet resultSet = ((OracleCallableStatement)callableStatement).getCursor(2);
while (resultSet.next()) {
for(int i=1;i<=resultSet.getMetaData().getColumnCount();i++){
System.out.println(resultSet.getString(i));
}
}
return null;//for test
}catch (SQLException sqlException){
sqlException.printStackTrace();
System.out.println(sqlException.getMessage());
return null;
}
}
}
I got error :
java.sql.SQLException: Non supported SQL92 token at position: 3
I found my Mistake around :
{ execute SYSTEM_LOGIN_GET_USER_WITH_PASSWORD(?,?) }
and when changed to 'call' works.
{ call SYSTEM_LOGIN_GET_USER_WITH_PASSWORD(?,?) }
Related
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>
I am developing a java sample in which I execute query one after other to get ddl of indexces.My java code is -
Statement stmt2 = con.createStatement();
ResultSet rs2 =null;
String query = "set long 100000";
rs2 =stmt2.execute(query);
query = "set longchucksize 100000";
rs2 = stmt2.executeQuery(query);
query = "SELECT DBMS_METADATA.GET_DDL('INDEX','SYS_IL0000091971C00001$$','CCEEXPERTS') FROM dual";
rs2 = stmt2.executeQuery(queryForScript);
when the following statement run it throws ORA-00922: missing or invalid option exception
String query = "set long 100000";
rs2 =stmt2.execute(query);
How I execute these statement?
Set long 10000 is a SQL*PLUS command, not a standard SQL that's why you hit the error.
Example
ResultSet rs = stmt.executeQuery("SELECT DBMS_METADATA.GET_DDL('TABLE','YOUR_OBJECTS','JAY') as ddl FROM dual");
while(rs.next()){
System.out.println(rs.getString(1));
}
Output
CREATE TABLE "JAY"."YOUR_OBJECTS"
( "OWNER" VARCHAR2(128) NOT NULL ENABLE,
"OBJECT_NAME" VARCHAR2(128) NOT NULL ENABLE,
"SUBOBJECT_NAME" VARCHAR2(128),
"OBJECT_ID" NUMBER NOT NULL ENABLE,
"DATA_OBJECT_ID" NUMBER,
"OBJECT_TYPE" VARCHAR2(23),
"CREATED" DATE NOT NULL ENABLE,
"LAST_DDL_TIME" DATE NOT NULL ENABLE,
"TIMESTAMP" VARCHAR2(19),
"STATUS" VARCHAR2(7),
"TEMPORARY" VARCHAR2(1),
"GENERATED" VARCHAR2(1),
"SECONDARY" VARCHAR2(1),
"NAMESPACE" NUMBER NOT NULL ENABLE,
"EDITION_NAME" VARCHAR2(128),
"SHARING" VARCHAR2(13),
"EDITIONABLE" VARCHAR2(1),
"ORACLE_MAINTAINED" VARCHAR2(1)
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "ORAPDB1_TBS1"
I got partial DDL while running the same statement on SQL*PLUS.
SQL> SELECT DBMS_METADATA.GET_DDL('INDEX','SYS_IL0000092981C00086$$','JAY') as ddl FROM dual;
DDL
--------------------------------------------------------------------------------
CREATE UNIQUE INDEX "JAY"."SYS_IL0000092981C00086$$" ON "JAY"."SYS_EXPORT_SCH
Here I can obtain whole DDL by setting SET LONG BUT I get complete output on Java Application.
Output(Eclipse)
CREATE UNIQUE INDEX "JAY"."SYS_IL0000092981C00086$$" ON "JAY"."SYS_EXPORT_SCHEMA_01" (
PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "ORAPDB1_TBS1"
PARALLEL (DEGREE 0 INSTANCES 0)
I have a table structure like below:
PROD(PROD_ID NUMBER,PROD_NAME VARCHAR2(100), MATCH_SCORE NUMBER)
Based upon some calculation (backend logic which is not part of our application) sometimes Infinity is getting stored in MATCH_SCORE.
The question is why it is allowing Infinity in a NUMBER column (MATCH_SCORE).
I've tried to get Infinity into the column myself:
INSERT INTO PROD VALUES(1,"PEN",1.0F/0); -- Doesn't work
INSERT INTO PROD VALUES(1,"PEN",BINARY_DOUBLE_INFINITY); -- Doesn't work.
The Oracle Documentation says:
The following numbers can be stored in a NUMBER column:
Positive numbers in the range 1 x 10-130 to 9.99...9 x 10125 with up to 38 significant digits
Negative numbers from -1 x 10-130 to 9.99...99 x 10125 with up to 38 significant digits
Zero
Positive and negative infinity (generated only by importing from an Oracle Database, Version 5)
(my emphasis)
We are not migrated from version 5, it is still happening in Oracle 11.
Java MCVE illustrating how issue arises:
SQL:
CREATE TABLE test_infinity ( value NUMBER );
Java:
try {
Class.forName( "oracle.jdbc.OracleDriver" );
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:orcl",
"username",
"password"
);
PreparedStatement st = con.prepareCall( "INSERT INTO test_infinity VALUES ( :value )" );
((OraclePreparedStatement)st).setNUMBERAtName( "value", NUMBER.posInf() );
st.execute();
st.close();
con.close();
}
catch ( ClassNotFoundException | SQLException ex ){}
I have a MSSQL database and a Java Spring application which uses Spring's Transaction Management.
I have a query of "IF NOT EXIT, INSERT .." which is ran from multiple threads.
For some reason I get a primary key constraint violation, even through I check for existence before writing, all happens inside a transaction.
I wanted to know what is the reason for that, and how to prevent it.
The query:
IF NOT EXISTS (SELECT docId FROM documentStatus WHERE docId='abc')
BEGIN INSERT INTO documentStatus
VALUES ('abc',1,0,NULL)
END
ELSE
BEGIN
UPDATE documentStatus SET documentStatus.count=documentStatus.count+1
WHERE docId ='abc'
END;
DDL for documentStatus
CREATE TABLE Dss.dbo.docStatus
(
docId NVARCHAR(256),
count INT NOT NULL DEFAULT 1,
error INT NOT NULL DEFAULT 0,
errorMsg NVARCHAR(1024) DEFAULT NULL,
CONSTRAINT PK_docStatus PRIMARY KEY (docId ASC)
)
DDL -
USE tempdb
GO
IF OBJECT_ID('dbo.docStatus', 'U') IS NOT NULL
DROP TABLE dbo.docStatus
GO
CREATE TABLE dbo.docStatus (
docId NVARCHAR(256) PRIMARY KEY,
[count] INT NOT NULL DEFAULT 1,
error INT NOT NULL DEFAULT 0,
errorMsg NVARCHAR(1024)
)
Your example -
IF NOT EXISTS (
SELECT docId
FROM docStatus
WHERE docId = N'abc'
)
BEGIN
INSERT INTO dbo.docStatus (docId) VALUES (N'abc')
END
ELSE
BEGIN
UPDATE docStatus
SET [count] += 1
WHERE docId = N'abc'
END
MERGE statement -
;WITH cte AS
(
SELECT *
FROM dbo.docStatus
WHERE docId = N'abc'
)
MERGE cte t
USING (
SELECT docId = N'abc'
) s ON s.docId = t.docId
WHEN MATCHED
THEN
UPDATE SET t.[count] += 1
WHEN NOT MATCHED BY TARGET
THEN
INSERT (docId, [count])
VALUES (s.docId, 1);
I am building a java program to insert data to my oracle database.
My problem is that I need to insert into two tables, and to reach unique rows I use in TABLE_A triggers for id before insert get next val in a sequence.
But i need the same id for the TABLE_B for connection.
( i cant get getval because what if another user uses the program... )
So I need to reach somehow that when I use executeql(sql) command in return I see what I have submit.
Now I use that I have name and date, so I select the id where name and date is the just inserted.
But its not the best because in one day I can insert more names. So now this will not unique.
like :
insert into table a ( name,date) val ( 'Ryan','2014.01.01')
id here is autoincremented by sequence
than another sql run:
inert into table_b ( id,someval) val ( select id from table_a where
name ='Ryan', date='2014.01.01, 23)
so i need something like:
system.out.println(smtp.executesql(sql).whatIinsertednow())
*than console:* '1 row insered (id,name,date) : ( 1, Ryan, 2014.01.01)
PreparedStatement prepareStatement = connection.prepareStatement("insert...",
new String[] { "your_primary_key_column_name" });
prepareStatement.executeUpdate();
ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
if (null != generatedKeys && generatedKeys.next()) {
Long primaryKey = generatedKeys.getLong(1);
}
I have found the answer this is perfectly works. I can insert from JAVA and its return with the key.
Full version:
CREATE TABLE STUDENTS
(
STUDENT_ID NUMBER NOT NULL PRIMARY KEY,
NAME VARCHAR2 (50 BYTE),
EMAIL VARCHAR2 (50 BYTE),
BIRTH_DATE DATE
);
CREATE SEQUENCE STUDENT_SEQ
START WITH 0
MAXVALUE 9999999999999999999999999999
MINVALUE 0;
And the Java code
String QUERY = "INSERT INTO students "+
" VALUES (student_seq.NEXTVAL,"+
" 'Harry', 'harry#hogwarts.edu', '31-July-1980')";
// load oracle driver
Class.forName("oracle.jdbc.driver.OracleDriver");
// get database connection from connection string
Connection connection = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:sample", "scott", "tiger");
// prepare statement to execute insert query
// note the 2nd argument passed to prepareStatement() method
// pass name of primary key column, in this case student_id is
// generated from sequence
PreparedStatement ps = connection.prepareStatement(QUERY,
new String[] { "student_id" });
// local variable to hold auto generated student id
Long studentId = null;
// execute the insert statement, if success get the primary key value
if (ps.executeUpdate() > 0) {
// getGeneratedKeys() returns result set of keys that were auto
// generated
// in our case student_id column
ResultSet generatedKeys = ps.getGeneratedKeys();
// if resultset has data, get the primary key value
// of last inserted record
if (null != generatedKeys && generatedKeys.next()) {
// voila! we got student id which was generated from sequence
studentId = generatedKeys.getLong(1);
}
}
source : http://viralpatel.net/blogs/oracle-java-jdbc-get-primary-key-insert-sql/
You can accomplish that by using the RETURNING clause in your INSERT statement:
INSERT INTO table_a ( name,date) val ( 'Ryan','2014.01.01') RETURNING id INTO ?