EDIT
Putting this here in case it helps others. My problem was a failure in understanding how PreparedStatement works. I had believed that the "?"...setInt() syntax was a simple substitution that constructs an SQL statement, interprets it and sends that to the DB, which is not the case. The answers below explain in detail the problem.
ORIGINAL QUESTION
I'm having some trouble getting an Oracle package function call to execute from within a Java app. I am receiving the below error:
ORA-01858: a non-numeric character was found where a numeric was expected
I believe I have constructed the call correctly, and the only place I'm using a string is for a date field (not a numeric one). The function has the signature:
function f_get_mr_target(a_plan_id number,a_machine number,a_shift_id number,a_shift_dt date) return number;
My java code invoking the function is as follows:
public Double checkMRTarget(int planId, int machineNum, int shiftId, String date)
{
//Instantiate the return value
Double mrTarget = null;
//Get the MR target
try
{
//Ready the connection
con = nativeDataSource.getConnection();
//The query string
String sql = "select pkg_bcs.f_get_mr_target(?,?,?,?) target from dual";
//Prepare the query
stmt = null;
stmt = con.prepareStatement(sql);
stmt.setInt(1, planId);
stmt.setInt(2, machineNum);
stmt.setInt(3, shiftId);
stmt.setString(4, date);
//Execute the query
ResultSet rs = stmt.executeQuery();
//Extract the value from the result set
mrTarget = rs.getDouble("target");
}
catch (Throwable e)
{
System.out.println("Error getting mrTarget: " + e);
}
finally
{ closeDBConnections(); }
//Return the value
return mrTarget;
}
Con is a public Connection object shared by all other methods in the class. Stmt is a PreparedStatement object, also shared. The parameters are passed as follows:
planId = 986548
machineNum = 5227
shiftId = 10
date = "trunc(sysdate)"
I've verified that running
select pkg_bcs.f_get_mr_target(986548, 5227, 10, trunc(sysdate)) target from dual;
works just fine in SQLDeveloper. As far as I can tell, it's getting a number where it expects a number
You've called setString, so Java sent a String that Oracle can't implicitly convert into a DATE.
You can convert it to a java.sql.Date, java.sql.Time, or java.sql.Timestamp by first parsing the date with a SimpleDateFormat, and creating the appropriate object, and calling setDate, setTime, or setTimestamp instead of setString.
Alternatively, you can get Oracle to convert it by calling to_date in your JDBC SQL:
// Your date format may vary.
String sql = "select pkg_bcs.f_get_mr_target(?,?,?,to_date(?, 'YYYY-MM-DD')) target from dual";
the 4th parameter which is date do not work with String. It waits for a Date object.
Here is your method signature, pass a Date object instead of String.
public Double checkMRTarget(int planId, int machineNum, int shiftId, Date date)
Substituting a string datatype to a Date parameter is a catastrophe. It will surely the ORA-01858 exception in this case (in context of you code).
Parameter substitution demands exact binding which serves its purpose of being strongly typed.
Please convert the fourth parameter i.e. the string parameter into a date object. & then implement what you wish to. It should work fine then.
Also, trunc(sysdate) in SQL query does not return a string to the SQL client. Rather it returns the date(internal conversion). This is designed such that the parser recognize the date type efficiently and consistently.
Related
I have App Java and its connect for JDBC and execute this query:
String date = '21-Dec-16';
StringBuilder query = new StringBuilder("SELECT * ");
query.append("FROM TEST WHERE PUBLISHED_DATE='").append(date).append("'");
connection = getConnection(jdbc);
stmt = connection.createStatement();
rs = stmt.executeQuery(query.toString());
syso query => select * from TEST where PUBLISHED_DATE='21-Dec-16'
and error:
java.sql.SQLDataException: ORA-01858: a non-numeric character was found where a numeric was expected
i too test:
select * from TEST where PUBLISHED_DATE=TO_DATE('21-Dec-16','DD-MON-RR')
and error:
java.sql.SQLDataException: ORA-01843: not a valid month
Nevertheless, i execute this query in my sql developer and works!
The immediate cause of your error is that you are using a date format which is incorrect for an Oracle query. But that aside, you should seriously consider using a prepared statement here. In addition to protecting your program against SQL injection, it will also relieve you from worrying about how to format your date for the query. Instead, you can simply bind the direct Java date object to the query.
String query = "SELECT * FROM TEST WHERE PUBLISHED_DATE = ?";
PreparedStatement stmt = connection.prepareStatement(query);
stmt.setDate(1, date); // here 'date' is an actual Date object, not a string
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
// access each record
}
If you absolutely must continue down your current road, I would expect the following raw query to run without error:
SELECT * FROM TEST WHERE PUBLISHED_DATE = '2016-12-21'
You could use a Java SimpleDateFormat object to obtain this from a Date object.
If you want to use that format for dates, you have to change the language settings of your database session:
Statement s = connection.createStatement();
s.execute("alter session set NLS_LANGUAGE = 'AMERICAN'");
and then you can use the TO_DATE function as in your second example.
I have a following PL/SQL procedure:
CREATE OR REPLACE PROCEDURE getDogInfo
(Dog_ID IN NUMBER, Dog_name OUT VARCHAR) AS
BEGIN
SELECT Dog_name INTO Name
FROM Dog_family
WHERE ID = Dog_ID;
END;
I need to make a java class file that does the same. I've been trying like this:
import java.sql.*;
import java.io.*;
public class Procedure {
public static void getDogInfo (int Dog_ID, String Dog_name)
throws SQLException
{ String sql =
"SELECT Dog_name INTO Name FROM Dog_family WHERE ID = Dog_ID";
try { Connection conn = DriverManager.getConnection("jdbc:default:connection:");
PreparedStatement apstmt = conn.prepareStatement(sql);
apstmt.setInt(1, Dog_ID);
apstmt.registerOutParameter(2, java.sql.Types.VARCHAR);
ResultSet rset = apstmt.executeQuery();
rset.close();
apstmt.close(); //Connection close
}
catch (SQLException e) {System.err.println(e.getMessage());
}
}
}
What am I doing wrong? Can someone help me get this working? Thanks
Have alook at this link showing you how to correctly use PreparedStatements.
You will find that the parameter should be ? not Dog_ID
Try
SELECT Name FROM Dog_family WHERE ID = ?
It will also show you how to iterate through your resultSet
Well, you do not tell us what the problem is, but I see several issue right away:
Your select statement should not have an INTO clause. That is a PL/SQL construct. You need to
return the result of the query back as a result set.
Your input parameter, Dog_ID will not be used, because you have not
named the parameter correctly in the SQL statement.
Java string parameters cannot be updated within the method, which I
am assuming that is what you are attempting. You either need to
return a string value from the method, or use a StringBuilder
reference, or some other container to pass in. See this link
There is no "out" parameter to register. Read up on result sets here
So, change your SQL statement to something like this(since you are using a positional parameter as opposed to a named parameter):
"SELECT Dog_name FROM Dog_family WHERE ID = ?"
You should read about JDBC (and Java in general too).
The query should be :
SELECT Name
FROM Dog_family
WHERE ID = ?
(assuming Name is the column name you are selecting from the table - it wasn't clear whether Name or Dog_name was the column name).
Then after you execute the query and get a result set :
String name = null;
if (rset.next()) {
name = rset.getInt (1);
}
...
return name;
Finally, your function should return a String. You can't pass the String as a parameter and update its value. String is immutable in Java.
One more thing - the line apstmt.registerOutParameter(2, java.sql.Types.VARCHAR); is not needed. registerOutParameter is only used with CallableStatement, which is a statement you use to execute a stored procedure.
When I try to execute the below code it gives me an java.sql.SQLException: ORA-01861: literal does not match format string error.
I am trying to copy some of the column values from customer1_details table to customer2_details table. The columns datatype which I am trying to move is TIMESTAMP(6) for TIME_REGISTERED, DATE_DISCHARGED columns and the datatype for DATE_OF_BIRTH column is DATE
try
{
Connection conn=Address.getOracleConnection();
int id = 1;
Date dob = null;
Timestamp timereg = null,datedischarged = null;
Statement stmt=conn.createStatement();
ResultSet res=stmt.executeQuery("SELECT TIME_REGISTERED,DATE_DISCHARGED,DATE_OF_BIRTH from customer1_details WHERE customer_id = '"+id+"' ");
if(res.next())
{
timereg=res.getTimestamp("TIME_REGISTERED");
datedischarged=res.getTimestamp("DATE_DISCHARGED");
dob=res.getDate("DATE_OF_BIRTH");
}
String sql1="INSERT INTO customer2_details(TIME_REGISTERED_3,DATE_DISCHARGED_3,DATE_OF_BIRTH,customer_ID) "
+ "VALUES('"+timereg+"','"+datedischarged+"','"+dob+"','"+id+"') ";
PreparedStatement pst=conn.prepareStatement(sql1);
pst.executeUpdate();
pst.close();
conn.close();
}
catch(Exception e)
{ System.out.print(e); }
It will be more helpful if anyone provides the answer without using INSERT INTO ... SELECT ... statement.
YOu can do it in one statement with a query like:
"INSERT INTO customer2_details (TIME_REGISTERED_3,DATE_DISCHARGED_3,DATE_OF_BIRTH,customer_ID)
SELECT TIME_REGISTERED,DATE_DISCHARGED,DATE_OF_BIRTH, customer_id
from customer1_details WHERE customer_id = '"+id+"' "
This is most likely caused by passing your Date and Timestamp variables as Strings to the insert statement.
When you insert or update Date or Timestamp values, there is a default format in which you can pass those values as strings. What you pass is java's idea of how to convert Dates and Timestamps into strings. These two don't seem to match.
Your best bet is probably to use bind variables, then the framework should take care of that.
An Alternative would be to use Oracle's to_date() function, where you can specify the format string. You would then define a format string which considers java's way of representing dates as strings. However, I am not sure if the java representation depends on the locale. If so, you would have to write you own date_to_string() method, which always returns dates in the same format, or your program may work on some computers, but not on others with a different locale.
And finally you can do an insert-select which bypasses the java layer entirely.
Read the timestamps as strings with getString();
OR call toString() in your java Timestamp object instances.
String sql1="INSERT INTO customer2_details(TIME_REGISTERED_3,DATE_DISCHARGED_3,DATE_OF_BIRTH,customer_ID) "
+ "VALUES('"+timereg.toString()+"','"+datedischarged.toString()+"','"+dob.toString()+"','"+id+"') ";
I have 3 comboboxes in Java which are ;
'departurecities={city1,city2,city3}
destinationcities={city1,city2,city3}
date={1,2,3,4,5,6...}
I want to define a variable for the date because I don't know, what user will bus date, so I need a variable for SQL query.
I want to query like that:
sql=select busid from buses where dep='city1'and des='city2' and
datebus=(????variable????);
how can I define it ???
Please help me ..
Thanks in advance
PreparedStatement
In case you want to pass a variable to your SQL statement, I would recommend a PreparedStatement. See Oracle Tutorial.
You can use setInt in order to pass an integer, setString to pass a String etc.
Here is the API.
Here is an example:
String result = null;
String query = "select busid from buses where dep='city1'and des='city2' and datebus=?";
try {
PreparedStatement preps = con.prepareStatement(query);
preps.setInt(1, Integer.parseInt((String) date.getSelectedItem()));
preps.execute();
rs = preps.getResultSet();
if (rs.next()) {
result = rs.getString(...);
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
I assume that datebus is declared as an integer in your database table.
You can use a String type for a constant like '2012-12-31 12:00 am', or, Date or GregorianCalendar if you want to manipulate days/date differences in Java.
In SQL, you can convert string or character values into SQL's internal date format with the to_date() function:
SQL examples:
to_date('29-Oct-09', 'DD-Mon-YY')
to_date('10/29/09', 'MM/DD/YY')
to_date('120109', 'MMDDYY')
So, if you wanted to create a SQL command from Java:
String date = "12/31/2012";
String dep = "city1";
String des = "city2";
String SQL = "INSERT INTO buses VALUES(" + dep + "," + des + ",to_date(" + date + ",'MM/DD/YYYY'));";
I have a form which captures a date that the user input in a JFormattedTextField. Then the Date need to be stored in a database (postgresql) using PreparedStatement. I am having error messages at the line pStat.setDate(4, dob);.
Date dob = (Date)ftxtDOB.getValue();
String add = txtAddress.getText();
String country = txtCountry.getText();
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection("jdbc:postgresql://127.0.0.1:5432/postgres", "postgres","cisco");
pStat = conn.prepareStatement("INSERT INTO customer_info VALUES (?,?,?,?,?,?)");
pStat.setString(1, id);
pStat.setString(2, surname);
pStat.setString(3, fName);
pStat.setDate(4, dob);
}catch(Exception e){
}
Edit: I have this error message from the compiler.
no suitable method found for setDate(int,java.util.Date)
method java.sql.PreparedStatement.setDate(int,java.sql.Date,java.util.Calendar) is not applicable
(actual and formal argument lists differ in length)
method java.sql.PreparedStatement.setDate(int,java.sql.Date) is not applicable
(actual argument java.util.Date cannot be converted to java.sql.Date by method invocation conversion)
Edit: SOLVED, I used:
pStat.setDate(4, new java.sql.Date(dob.getTime()));
What error message?
Guessing that it's actually a compiler error message, are you sure you are using java.sql.Date and not java.util.Date?
Edit: As you edited question, yes you will need new java.sql.Date(date.getTime()) or something (data handling in Java is a mess! (at the moment)).