Why won't this stored procedure call from Java work? - java

Here is my stored procedure:
CREATE OR REPLACE PROCEDURE VIEWBROKERS
(o_username OUT USERS.USERNAME%TYPE)
AS
BEGIN
SELECT USERNAME
INTO o_username
FROM USERS
WHERE Role_ID = 3 ;
END VIEWBROKERS;
Here is my method calling the stored procedure:
public ResultSet pullBrokers() {
ResultSet rs = null;
try {
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
con = DriverManager.getConnection(Messages.getString("OracleUserManagement.0"), Messages.getString("OracleUserManagement.1"), Messages.getString("OracleUserManagement.2")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
String storedProcedure = "{call VIEWBROKERS(?)}";
CallableStatement statement = con.prepareCall(storedProcedure);
statement.registerOutParameter(1, java.sql.Types.VARCHAR);
rs = statement.executeQuery();
con.commit();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
And lastly when I tried to print out the results:
public class TEST {
public static void main(String[] args) throws SQLException{
OraclePullListOfUsers pull = new OraclePullListOfUsers();
ResultSet rs = pull.pullBrokers();
try {
while (rs.next()){
System.out.println(rs.getString(1));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
I get the error message ORA-01422: exact fetch returns more than requested number of rows
Which is strange ,because there are only two rows of data in the table...
If someone could point me in the right the direction, that would be awesome!

Looks like you're problem is not related to Java, just on the SQL side. Could it be that both those two rows in the table have Role_ID=3?

The root cause for your problem:
ORA-01422: exact fetch returns more than requested number of rows
is that PL/SQL select into statement expects a query to match to exactly one row. If the query returns no rows or if the query return more than one row (as in your case) it will throw an exception.
You can't use select into to save the results to a single out variable if the query can return more than one row. Instead your subprogram should return a cursor (that is a pointer to a record set) that your Java component can query. Note that returning a cursor is not the only option, but in your case it looks like a good starting point.
This issue has been addressed several times in StackExchange universe. Please take a look e.g.
Return many rows on a plsql Oracle10g
How to return multiple rows from the stored procedure? (Oracle PL/SQL)
Calling Oracle PL/SQL stored procedure from java middle tier using JDBC on Linux?
A Java example Using Ref Cursors To Return Recordsets.

Related

invalid column index error in java while fetching data from oracle 10g database. Cant figure out whats wrong

Code snippet:
On a button click, actionevent will be called
public void actionPerformed(ActionEvent e)
{
Function f = new Function();
Function is a nested class which i have used to establish the connection with the database.
The code snippet for function class is also provided in the end.
ResultSet rs = null;
String Cid ="cust_id";
String Pno="cust_phone";
String cat="cust_cat";
String start_date="st_date";
String Adv_amt="adv";
String Adv_end="end_date";
String Address="addr";
t2 is the Textfield name which i have used to get entry of customer name. I want to use this customer name as a PK to fetch all the other data about that customer from DB.
rs=f.find(t2.getText());
try{
if(rs.next())
{
t1.setText(rs.getString("cust_id"));
t3.setText(rs.getString("cust_phone"));
t4.setText(rs.getString("cust_cat"));
t5.setText(rs.getString("st_date"));
t6.setText(rs.getString("adv"));
t7.setText(rs.getString("end_date"));
t8.setText(rs.getString("addr"));
}
else
JOptionPane.showMessageDialog(null,"No data for this name");
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null,ex.getMessage());
}
}
Here is the code snippet for nested class Function which is inside the main class:
class Function{
Connection con=null;
ResultSet rs= null;
PreparedStatement ps = null;
public ResultSet find(String s)
{
try
{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
con = DriverManager.getConnection("jdbc:oracle:thin:#Localhost:1521:xe","system","qwerty");
ps= con.prepareStatement("Select * from gkkdb where cust_name='?'");
ps.setString(1,s);
rs= ps.executeQuery();
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, ex.getMessage());
}
return rs;
}
}
Please help figure out the problem.
Don't put the parameter placeholder ? in single quotes.
This:
ps = con.prepareStatement("Select * from gkkdb where cust_name='?'");
should be
ps = con.prepareStatement("Select * from gkkdb where cust_name = ?");
The ? is not recognized as a placeholder if you enclose it in single quotes.
Sorting out the bind variable will fix your immediate issue.
You should explicitly specify what columns you want selected and that way you'll only get what you need (someone might add a BLOB column later) and you'll get them in the right order (someone might change the table create script before running on another DB instance, although you are looking up the columns by name, a different order would only impact if you were using positional indexes).
Ditto on the other answer re: bind variables (i.e. no quotes)
Plus, "select * from" is never a good idea, ask your DBA.
Obviously your code is for example, but you should make sure you free up any resources (Connection, Statement, ResultSet) as soon as they are done with. Use Java 7 try-with-resources.

Proper use of Stored Procedure using Select

I created a Stored Procedure where I can select the column that I address in my Stored Procedure via Callable Statement. I tried to use SELECT SECTION NAME FROM allsections_list WHERE SECTION_NAME = ? Similar to syntax of Prepared Statement but I think its not compatible using this syntax. I'm just new learning this mysql.
Stored Procedure
CREATE STORED PROCEDURE getSECTION_NAME(OUT SECTION_NAME VARCHAR)
SELECT SECTION_NAME FROM allsections_list
Code
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
String searchSection = Section_SearchSection_Textfield.getText();
String searchSection_Name = Section_SectionName_TextField.getText();
if (searchSection.isEmpty())
{
JOptionPane.showMessageDialog(null, "Please fill up this fields");
}
else
try (Connection myConn = DBUtil.connect();
CallableStatement myCs = myConn.prepareCall("{call getSECTION_NAME(?)}"))
{
myCs.setString(1, searchSection_Name);
try (ResultSet myRs = myCs.executeQuery())
{
int resultsCounter = 0;
while (myRs.next())
{
String getSection_Name = myRs.getString(1);
Section_SectionName_TextField.setText(getSection_Name);
resultsCounter++;
}
}
}
catch (SQLException e)
{
DBUtil.processException(e);
}
When I search a records. If the records exist it the value will print out to the textfields. But it doesn't print out. And it throws me a error getSECTION_NAME does not exist. What if I want select multiple values? Because I'm having a project where I'm making a Enrollment System. I choose this Stored Procedure specially than Batch Statement based on what I read. Any help will appreciate. Thanks!
I don't use MySql, but here's a similar example in Oracle (I think this Works in MySql as well).
CREATE PROCEDURE get_section_name(OUT secName VARCHAR(100))
BEGIN
SELECT SECTION_NAME INTO secName FROM allsections_list WHERE some_condition = 100; //your procedure does not use any input arguments if you want to return just one record then you'll probably need to specify a where clause
END
/ //when executing a stored procedure in a DB client you will need to specify a terminator character (in this case slash /)
Note that there's no return statement because we're using OUT parameters.
The getOutValueForStoredProcedure method calls the stored procedure and retrieves the out value.
public String getOutValueForStoredProcedure(String procedureName, int sqlType) throws EasyORMException{
String out=null;
CallableStatement stmt=null;
try{
//out parameters must me marked with question marks just as input parameters
sqlQuery = "{call " + procedureName +"(?)}";
stmt=conn.prepareCall(sqlQuery);//I assume that a Connection has been created
stmt.registerOutParameter(1, sqlType);
stmt.execute();
out = stmt.getString(1);//you get the out variable through the Statement, not the ResultSet
}catch(Exception e){
//log exception
}finally{
//close stmt
}
return out;
}
To call this stored procedure, you can use
String out = getOutValueForStoredProcedure("get_section_name", java.sql.Types.VARCHAR);
For creating stored procedures in MySql , check this link http://code.tutsplus.com/articles/an-introduction-to-stored-procedures-in-mysql-5--net-17843
For a more elaborate example, check this http://www.mkyong.com/jdbc/jdbc-callablestatement-stored-procedure-out-parameter-example/

How to return result sets from Stored Procedure?

I created a Stored Procedure where I can fetch all my data that I inserted in my following textfields. How can I fetch all of this data by calling my Callable Statement? I think this is the easiest way than Batch Statement based on what I read. I only drag and drop this following components just a practice purposes.
Stored Procedure
CREATE PROCEDURE show_data(OUT FULLNAME VARCHAR(50), OUT ADDRESS VARCHAR(50))
PARAMETER STYLE JAVA
LANGUAGE JAVA
READS SQL DATA
DYNAMIC RESULT SETS 1
EXTERNAL NAME 'Frame.searchButton'
I used OUT parameter to retrieve values using getXXX() methods. I'm just little bit confuse since this is my first time to use Stored Procedure in derby.
GUI
After the user search the following record in Database. If the value exist it will print to the designated textfields.
SOURCE CODE
String searchRecord = searchTf.getText();
String searchQuery = "SELECT * FROM SAMPLEONLY";
ResultSet data[] = null;//Why should I use this array?
try (Connection myConn = DriverManager.getConnection(url, user, pass);
PreparedStatement myPs = myConn.prepareStatement(searchQuery);)
{
String addFullname = fullnameTf.getText();//first field
String addAddress = addressTf.getText();//second field
data[0] = myPs.executeQuery();
CallableStatement cs = myConn.prepareCall("{ call showData(?, ?)}");
cs.setString(1, addFullname);
cs.setString(2, addAddress);
boolean hasResults = cs.execute();
if (hasResults) {
ResultSet rs = cs.getResultSet();
while (rs.next()) {
String getFullname = rs.getString(1);//get the value
String getAddress = rs.getString(2);
fullnameTf.setText(getFullname);//set the text here
addressTf.setText(getAddress);
}//end of while
rs.close();//close the resultset
}//end of if
}//end of try
catch (SQLException e)
{
e.printStackTrace();
}
}//end of else
}
After I insert in Search textfields it throws me a error NullPointerExeption. I follow Derby Reference Manual so I can have a guide writing a proper Stored Procedure. This code is mine most of the part. Guide me if I missed something wrong. Feel free to comment thanks.

SQLServerException: A result set was generated for update

I'm trying to insert a new record into an MS SQL database, and I'm getting an exception I've never seen before. When I call executeUpdate the following exception is thrown:
com.microsoft.sqlserver.jdbc.SQLServerException: A result set was generated for update.
This is the Java code that produces the error:
// addComment method adds a new comment for a given requestId
public CommentBean addComment(CommentBean comment) {
PreparedStatement stmt = null;
INative nat = null;
Connection conn = null;
try {
nat = dbConn.retrieveNative();
conn = (Connection)nat.getNative("java.sql.Connection");
stmt = conn.prepareStatement(ADD_COMMENT);
stmt.setInt(1, comment.getRequestId());
stmt.setString(2, comment.getComment());
stmt.setString(3, new SimpleDateFormat("MM/dd/yyyy").format(comment.getDateCreated()));
stmt.setString(4, comment.getCreatedBy());
comment.setCommentId(stmt.executeUpdate()); // exception
} catch(Exception ex) {
System.err.println("ProjectRegistration::SQLDAO - addComment");
ex.printStackTrace();
} finally {
try {
if (stmt != null) stmt.close();
} catch (Exception e) {}
}
return comment;
}// end addComment
Where ADD_COMMENT is defined as a String:
private static final String ADD_COMMENT = "INSERT INTO RequestComments OUTPUT INSERTED.commentId VALUES(?,?,?,?)";
For the sake of being thorough, the table is defined as:
CREATE TABLE RequestComments (
commentId int NOT NULL PRIMARY KEY IDENTITY(1,1),
requestId int FOREIGN KEY REFERENCES Requests(requestId),
comment varchar(400),
dateCreated date,
createdBy varchar(12)
);
I don't think I'm doing anything terribly complicated here, but I can't think of why I'm getting this exception. I have a method in the same class which does the exact same type of insertion (literally the same query with a different table name and number of values), and it has no issues. Does anyone have any ideas on how to resolve this issue?
This particular error can also be caused by an INSERT-trigger, which has a SELECT-statement as a part of the trigger code.
To test whether this is the case, you can try:
using executeQuery(), instead of executeUpdate() - and display the result.
executing the insert in tool like MySQL Workbench, SQL Server Management Studio, or whatever flavour of database design tools are available for your DBMS, to see whether a result is returned.
Related: sql server error "A result set was generated for update"
I'm hoping this may help others looking at the same error message, as it did for me. My solution was to live with a call to executeQuery(), although it only handles an underlying issue, instead of fixing it.
This instruction stmt.executeUpdate() is not returning the commentId, it returns a ResultSet which you could then get the commentId from. Something like this,
ResultSet rs = stmt.executeQuery(); // Not update, you're returning a ResultSet.
if (rs.next()) {
comment.setCommentId(rs.getInt(1));
}
you are using OUTPUT in your insert query i.e you will get a resultset after your query executes and to hold that you need an object of class ResultSet to hold that data
SqlServer : When SET NOCOUNT is ON, the count is not returned. When SET NOCOUNT is OFF, the count is returned.
Connection conn = DriverManager.getConnection(connectDB,user,pwd);
String sql = " set nocount off;INSERT INTO test (name) values (1)";
PreparedStatement prepareStatement = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
System.out.println(prepareStatement.executeUpdate());
ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
if(generatedKeys.next()){
System.out.println(generatedKeys.getString(1));
}
Related:
set-nocount-on-usage
I've had a similar problem where after a while an insert on a autonumber table would give a "A result set was generated for update." at random. I use connection pooling and somehow the driver can get into a state where executeUpdate in combination with Statement.RETURN_GENERATED_KEYS doesn't work anymore. I found out that in this state an executeQuery does the trick, but in the initial state executeQuery does not work. This lead me to the following workaround:
PreparedStatement psInsert = connection.prepareStatement("INSERT INTO XYZ (A,B,C) VALUES(?,?,?)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = null;
try {
psInsert.setString(1, "A");
psInsert.setString(2, "B");
psInsert.setString(3, "C");
Savepoint savePoint = connection.setSavepoint();
try {
psInsert.executeUpdate();
rs = psInsert.getGeneratedKeys();
} catch (SQLServerException sqe)
{
if (!sqe.getMessage().equals("A result set was generated for update."))
throw sqe;
connection.rollback(savePoint);
rs = psInsert.executeQuery();
}
rs.next();
idField = rs.getInt(1);
} finally {
if(rs != null)
rs.close();
psInsert.close();
}

SQL - how to return multiple rows with one SQL query?

I have a managed bean which makes SQL queries to Oracle database. This is just very simple example how I make SQL queries. This is the table structure:
GLOBALSETTINGS
---------------------------------
SessionTTL VARCHAR2(40 BYTE)
MAXACTIVEUSERS NUMBER
ACTIVEUSERS VARCHAR2(20 BYTE)
I use this table just to store application settings. In the example listed below I can fetch just one string with one SQL statement. I want with SQL query to fetch the content of the three rows - SessionTTL, MAXACTIVEUSERS, ACTIVEUSERS. Is it possible?
public String CheckUserDB(String userToCheck) throws SQLException {
String storedPassword = null;
String SQL_Statement = null;
if (ds == null) throw new SQLException();
Connection conn = ds.getConnection();
if (conn == null) throw new SQLException();
try {
conn.setAutoCommit(false);
boolean committed = false;
try {
SQL_Statement = "SELECT Passwd from USERS WHERE Username = ?";
PreparedStatement passwordQuery = conn.prepareStatement(SQL_Statement);
passwordQuery.setString(1, userToCheck);
ResultSet result = passwordQuery.executeQuery();
if(result.next()){
storedPassword = result.getString("Passwd");
}
conn.commit();
committed = true;
} finally {
if (!committed) conn.rollback();
}
}
finally {
conn.close();
}
return storedPassword;
}
P.S I want the content of the rows.
I'm hoping I understand what you are asking for, but I fear I don't as it seems too simple, but anyway...
I think you want the contents of 3 columns, not rows. And yes you can, you just specify the columns you want returned in your SQL statement:
SELECT SessionTTL, MAXACTIVEUSERS, ACTIVEUSERS FROM GLOBALSETTINGS WHERE (condition)...
you can also use * as a shortcut for all columns iof you don't want to explicitly specify them:
SELECT * FROM GLOBALSETTINGS WHERE (condition)...
Some background reading on SQL syntax might be useful
If I read this correctly (sorry if mistaken), all you want to do is change your SQL command to select ALL COLUMNS in your database table.
To do so:
string SqlAll = #"SELECT Database.SessionTTL, Database.MAXACTIVEUSERS, Database.ACTIVEUSERS FROM Database";
This will retrieve ALL columns in the database. You can also have conditional statements in your queries when you want to filter for logical reasons, such as TOP 20 to get the first 20 results from the result set.
If you like to return multiple lines with one sql query, you may want to look into ArrayList as you need a loop, where the code would go through your records and match and find all possible results until the end of the records list.

Categories

Resources