I am trying to print the plsql variable value (l_console_message) in Java. However, this approach doesn't seem to be working. I belive that something goes wrong at ResultSet bit. I am missing something here. Any idea, what goes wrong?
PreparedStatement statement = null;
try {
statement = connection.prepareStatement("\n" +
" declare " + "\n" +
" p_schema_name varchar2(400):= upper('" + schema + "'); " + "\n" +
" p_temp_table_name varchar2(400) := upper('temp_table_jobs_name'); " + "\n" +
" l_result varchar2(400); " + "\n" +
" l_owner varchar2(200); " + "\n" +
" l_job_name varchar2(200); " + "\n" +
" l_enabled varchar2(200); " + "\n" +
" l_console_message varchar2(4000); " + "\n" +
" cursor c1_temp_table_name is " + "\n" +
" select " + "\n" +
" table_name " + "\n" +
" from all_tables " + "\n" +
" where table_name = p_temp_table_name; " + "\n" +
" begin " + "\n" +
" open c1_temp_table_name; " + "\n" +
" fetch c1_temp_table_name into l_result; " + "\n" +
" if c1_temp_table_name %notfound then " + "\n" +
" execute immediate ' " + "\n" +
" create table '||p_schema_name||'.'||p_temp_table_name||' ( " + "\n" +
" schema_name varchar2 (1000), " + "\n" +
" job_name varchar2(1000), " + "\n" +
" status varchar2(100) " + "\n" +
" )'; " + "\n" +
" l_console_message := p_temp_table_name||' created.'; " + "\n" +
" dbms_output.put_line (l_console_message); " + "\n" +
" end if; " + "\n" +
" close c1_temp_table_name; " + "\n" +
" exception when others then " + "\n" +
" null; " + "\n" +
" end;");
ResultSet rs = statement.execute();
while (rs.next()){
System.out.println(rs.getString(l_console_message));
}
}
catch (SQLException e) {
System.out.println("ERROR: Unable to run SQL statements for schema " + schema + " in beforeMigrate: " + e.getMessage());
}
finally {
if (null != statement) {
try {
statement.close();
}
catch (SQLException se) {
System.out.println("ERROR: Unable to close statement in beforeMigrate: " + se.getMessage());
}
}
}
Thanks in advance :-)
The question linked to from a comment shows an example of what you need to do, but you seem to be struggling to translate that to your situation.
Your anonymous block doesn't (and can't) return a result set, so it shouldn't be executed as a query, and shouldn't be a prepared statement; you need to have a callable statement instead:
CallableStatement statement = null;
try {
statement = connection.prepareStatement("\n" +
...
Then you either need to assign the value of your PL/SQL variable to a bind variable placeholder:
...
" l_console_message := p_temp_table_name||' created.'; " + "\n" +
" ? := l_console_message; " + "\n" +
" end if; " + "\n" +
...
or don't have l_console_message at all (so it doesn't even need to be declared), just assign the string directly to a bind variable placeholder:
...
" ? := p_temp_table_name||' created.'; " + "\n" +
" end if; " + "\n" +
...
Either way the dbms_output call isn't useful here. (It is actually possibly you retrieve the dbms_output buffer from Java, but it's a lot more work).
Then you need to declare an OUT bind variable to receive the string, and call the statement with execute() rather than executeQuery():
statement.registerOutParameter(1, Types.VARCHAR);
statement.execute();
Then you can retrieve the string value that has been put in to the bind variable; e.g. to print it straight to console:
System.out.println(statement.getString(1));
The ResultSet, rs and loop have gone completely.
Your example has following issues:
Anonymous PL/SQL block can return nothing.
Variables declared in a PL/SQL block can't escape the scope. In your example l_console_message variable is visible only in the anonymous PL/SQL block, not in your Java code.
If you want to return a value (or a result set) from a PL/SQL code then you need a stand-alone or package subprogram. Or use the idea linked by #mario-tank where your host environment (your Java code) binds output variables.
Internet and StackOverflow have plenty of examples how to call PL/SQL code from Java.
Related
Let's say I've got below java code which eventually prints everything from the pl/sql query:
try (CallableStatement call = c.prepareCall(
"declare "
+ " num integer := 1000;"
+ " num myString:= 'test';"
+ "begin "
+ " dbms_output.enable();"
+ " dbms_output.put_line('abc');"
+ " dbms_output.put_line('hello');"
+ " dbms_output.put_line(myString);"
+ " dbms_output.get_lines(?, num);"
+ " dbms_output.disable();"
+ "end;"
)) {
call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
call.execute();
Array array = null;
try {
array = call.getArray(1);
System.out.println(Arrays.asList((Object[]) array.getArray()));
}
finally {
if (array != null)
array.free();
}
}
That works fine but what if I wanted to pass a parameter to the pl/sql query? For example 'myString'?
So it would be something like:
"declare "
+ " num integer := 1000;"
+ " num myString:= ?;"
+ "begin "
+ " dbms_output.enable();"
+ " dbms_output.put_line('abc');"
+ " dbms_output.put_line('hello');"
+ " dbms_output.put_line(myString);"
+ " dbms_output.get_lines(?, num);"
+ " dbms_output.disable();"
+ "end;"
How should I pass this parameter? I know that I should use sth like
call.setString(2, "test");
but in what place/line?
Can you please help?
In this case, your input parameter will have index=1 and dbms_output out parameter will have index=2;
There is no type myString, so looks like you want varchar2;
You can use .setString();
I've fixed your variable names:
try (CallableStatement call = c.prepareCall(
"declare "
+ " num integer := 1000;"
+ " str varchar2(100):= ?;"
+ "begin "
+ " dbms_output.enable();"
+ " dbms_output.put_line('abc');"
+ " dbms_output.put_line('hello');"
+ " dbms_output.put_line(str);"
+ " dbms_output.get_lines(?, num);"
+ " dbms_output.disable();"
+ "end;"
)) {
call.setString(1, "test");
call.registerOutParameter(2, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
call.execute();
Array array = null;
try {
array = call.getArray(2);
System.out.println(Arrays.asList((Object[]) array.getArray()));
}
finally {
if (array != null)
array.free();
}
}
Results:
Connected successfully
[abc, hello, test, null]
Another variant is to bind variables by name:
try (CallableStatement call = c.prepareCall(
"declare "
+ " num integer := 1000;"
+ " str varchar2(100):= :in;"
+ "begin "
+ " dbms_output.enable();"
+ " dbms_output.put_line('abc');"
+ " dbms_output.put_line('hello');"
+ " dbms_output.put_line(str);"
+ " dbms_output.get_lines(:out, num);"
+ " dbms_output.disable();"
+ "end;"
)) {
call.setString("in", "test");
call.registerOutParameter("out", Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
call.execute();
Array array = null;
try {
array = call.getArray("out");
System.out.println(Arrays.asList((Object[]) array.getArray()));
}
finally {
if (array != null)
array.free();
}
}
As you can see I used :in and :out as bind variables and used these names in .setString, registerOutParameter and getArray.
i have small problem, i googled it many times but i couldn't get it...
i'm using a query (sqlite) to retrieve some data ..
in this query their is Date() used to increase certain date dynamic number of days (coming from column in the same table) ..
if i put this days static (1,2,3,.....) it works fine but if i put column name it doesn't.
this query fails and i want it to work:
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE "
+ DATE + " = date('" + targetDate + "',' " + REPETITIONS + " day') ";
this works fine :
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE "
+ DATE + " = date('" + targetDate + "','2 day') ";
where
targetDate: date entered by user to get events of that date
DATE: date of every event in the table
REPETETIONS: dynamic number (column in the same table)
the problem is using REPETITIONS in the date function...
create statement
String SQL_CREATE_EVENT_TABLE = "CREATE TABLE " + TABLE_NAME + " ( " +
ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
TITLE + " TEXT ," +
DATE + " TEXT , " +
IS_NOTIFY + " INTEGER , " +
NOTIFICATION_TIME + " TEXT ," +
REPEAT + " INTEGER ," +
REPEAT_DURATION + " INTEGER ," +
REPETITIONS + " INTEGER ," +
CERTAIN_DATE + " TEXT ," +
NOTE + " TEXT ," +
IS_SPOKEN + " INTEGER " +
" );";
and this is the selecting statement
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE " + DATE + " = '" + targetDate
+ "' OR (( " + REPEAT + " = '1' AND " + REPEAT_DURATION + " = '0' ) AND " + DATE + " <= '" + targetDate + "')"
+ " OR( " + REPEAT + " = '1' AND " + REPEAT_DURATION + " = '3' ) AND " + DATE + " <= '" + targetDate + "' AND " + CERTAIN_DATE + " >= '" + targetDate + "'"
+ " OR (" + REPEAT + " = '1' AND " + REPEAT_DURATION + "= '2' ) AND " + targetDate + " >= '" + DATE + "' AND "+ targetDate+ " <= date('" + DATE + "','" + REPETITIONS + " days')";
The variable REPETITIONS in this statement:
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE "
+ DATE + " = date('" + targetDate + "',' " + REPETITIONS + " day') ";
should be a number and not a column name.
The date function in SQLite has various syntaxes but you use this one:
SELECT date('2014-10-23','+7 day');
you must supply a number before day.
Edit try this:
String selectQuery = "SELECT DISTINCT * FROM " + TABLE_NAME + " WHERE "
+ DATE + " = date('" + targetDate + "', " + REPETITIONS + " || ' day') ";
In sqlite date() function, the NNN days is a string modifier and not an expression. Therefore you cannot use column names or even || string concatenation there.
You can format the modifier string in your code and place it in the SQL. This requires additional query to the database, which is likely not what you want.
If you can assume each day is 24 hours (which is not always true, consider e.g. DST events), you could try something like
... date(strftime('%s', '" + targetDate + "', " + REPETITIONS + "*24*60*60, 'unixepoch') ...
where strftime('%s', ...) converts to seconds and date(..., 'unixepoch') converts back to datestamp.
But seriously I'd consider redesigning the schema to better support your functional requirements.
I wrote a piece of JDBC template code, which inserts the record in the table, but the problem is my execution is stuck on this particular snippet, it seems some kind of hang up. I didn't figure out the cause as query properly running in sqldeveloper
List<SalaryDetailReport> reports = salaryDetailReportDAO.findAll(tableSuffix, regionId, circleId);
// the above line find the required data, if data is found then it proceeds
if (reports != null && reports.size() > 0) {
for (SalaryDetailReport salaryDetail : reports) {
try {
SalaryDetail sd = new SalaryDetail();
sd.setDetailReport(salaryDetail);
salaryDetailDAO.save(sd, tableSuffix);
} catch (Exception e) {
log.error("Error occured", e);
e.printStackTrace();
throw new MyExceptionHandler(" Error :" + e.getMessage());
}
}
System.out.println("data found");
} else {
log.error("Salary Record Not Found.");
throw new MyExceptionHandler("No record Found.");
}
You people saw try-catch , my execution stuck inside try and catch and here is the insertion code in my implementation class. when i commented the above code then my application works fine, but why my application stuck here, I am not able to figure it out, kindly help me
#Override
public void save(SalaryDetail details, String tableSuffix) {
String tabName = "SALARY_DETAIL_" + tableSuffix;
// String q = "INSERT INTO " + tabName + "(ID "
String q = "INSERT INTO SALARY_DETAIL_TBL "
+ " (ID "
+ " ,EMP_NAME "
+ " ,EMP_CODE "
+ " ,NET_SALARY "
+ " ,YYYYMM "
+ " ,PAY_CODE "
+ " ,EMP_ID "
+ " ,PAY_CODE_DESC "
+ " ,REMARK "
+ " ,PAY_MODE ) "
+ " (SELECT (sd.SALARY_REPORT_ID) ID "
+ " ,(sd.emp_name) emp_name "
+ " ,(sd.EMP_CODE) EMP_CODE "
+ " ,(sd.amount) NET_SALARY "
+ " ,(sd.YYYYMM) YYYYMM "
+ " ,(sd.pay_code) pay_code "
+ " ,(sd.emp_id) emp_id "
+ " ,(sd.PAY_CODE_DESC) PAY_CODE_DESC "
+ " ,(sd.REMARK) REMARK "
+ " ,(sd.PAY_MODE)PAY_MODE "
// + " FROM SALARY_DETAIL_REPORT_" + tableSuffix + " sd "
+ " FROM SALARY_DETAIL_REPORT_TBL sd "
+ " WHERE sd.PAY_CODE = 999 "
+ " AND sd.EMP_ID IS NOT NULL "
// + " AND sd.EMP_ID NOT IN (SELECT EMP_ID FROM SALARY_DETAIL_" + tableSuffix + ") "
+ " AND sd.EMP_ID NOT IN (SELECT EMP_ID FROM SALARY_DETAIL_TBL) "
+ " ) ";
MapSqlParameterSource param = new MapSqlParameterSource();
param.addValue("id", details.getId());
param.addValue("EMP_NAME", details.getEmpName());
param.addValue("EMP_CODE", details.getEmpCode());
param.addValue("NET_SALARY", details.getNetSalary());
param.addValue("GROSS_EARNING", details.getGrossEarning());
param.addValue("GROSS_DEDUCTION", details.getGrossDeduction());
param.addValue("YYYYMM", details.getYyyymm());
param.addValue("EMP_ID", details.getEmployee() != null ? details.getEmployee().getEmpId() : null);
KeyHolder keyHolder = new GeneratedKeyHolder();
getNamedParameterJdbcTemplate().update(q, param);
// details.setId(((BigDecimal) keyHolder.getKeys().get("ID")).longValue());
}
The main problem is in your query is Not In condition. It will degrade your performance. Try to fetch the "SELECT EMP_ID FROM SALARY_DETAIL_TB" in a separate query and pass in the Not in block in the main query. This will increase the performance of your query. Every time a save is performed this will fire the select query every time.
You have to decide whether you will insert records from SELECT or from the application.
If you don't need to manipulate with data after their select then you can simply call one INSERT INTO SELECT statement without any for cycle. It will be fast because of the only one INSERT statement call.
So you will implement method like copyAllInSalaryDetail(tableSuffix, regionId, circleId) in your SalaryDetailReportDAO and that method will execute INSERT INTO salary_detail_tbl... (...) (SELECT ... WHERE ...) using the same WHERE condition as you have in findAll() method. All inserts will be done only on the Database layer.
If you want to manipulate with data before their insert you can continue with your approach using SalaryDetail bean and for cycle, but you should remove the SELECT part from the INSERT statement and use values from the provided bean. Then the save() method can look like:
#Override
public void save(SalaryDetail details, String tableSuffix) {
// use tableSuffix if it is really needed
String q = "INSERT INTO SALARY_DETAIL_TBL "
+ " (ID "
+ " ,EMP_NAME "
+ " ,EMP_CODE "
+ " ,NET_SALARY "
+ " ,YYYYMM "
+ " ,PAY_CODE "
+ " ,EMP_ID "
+ " ,PAY_CODE_DESC "
+ " ,REMARK "
+ " ,PAY_MODE ) "
+ " VALUES (:id "
+ " ,:emp_name "
+ " ,:emp_code "
+ " ,:net_salary "
+ " ,:yyyymm "
+ " ,:pay_code "
+ " ,:emp_id "
+ " ,:pay_code_desc "
+ " ,:remark "
+ " ,:pay_mode)";
MapSqlParameterSource param = new MapSqlParameterSource();
// KeyHolder keyHolder = new GeneratedKeyHolder();
// details.setId(((BigDecimal) keyHolder.getKeys().get("ID")).longValue());
param.addValue("id", details.getId());
param.addValue("emp_name", details.getEmpName());
param.addValue("emp_code", details.getEmpCode());
param.addValue("net_salary", details.getNetSalary());
param.addValue("pay_code", details.getPayCode());
param.addValue("pay_code_desc", details.getPayCodeDesc());
param.addValue("pay_mode", details.getPayMode());
param.addValue("remark", details.getPayRemark());
param.addValue("yyyymm", details.getYyyymm());
param.addValue("emp_id", details.getEmployee() != null ? details.getEmployee().getEmpId() : null);
getNamedParameterJdbcTemplate().update(q, param);
}
Could you please help what wrong with this query when calling from Java. When I run the same query in PL/SQL developer it runs perfectly but not when i call from java,.
CRE_DTTM is in DATE datatype
String query4="SELECT NVL(SUM(cur_amt),0) FIRST_PAY" +
" FROM ci_ft ft " +
"WHERE sa_id IN "+
" (SELECT sA_id FROM ci_Sa WHERE acct_id='"+acctid.getIdValue()+"' )" +
"AND TRUNC(crE_dttm)>= (SELECT MAX(crE_Dttm) FROM ci_bill" +
" WHERE accT_id='"+acctid.getIdValue()+"' AND crE_dttm<= (SELECT add_months(To_Date('2016-03-10','YYYY-MM-DD'), -1) FROM dual ) )" +
"AND fT_type_flg IN ('PS','PX')AND ft.cRE_dttm <= (" +
" CASE" +
" WHEN ( to_Date(" +
" (SELECT MAX(crE_Dttm)" +
" FROM ci_bill" +
" WHERE accT_id ='"+acctid.getIdValue()+"'" +
" AND crE_dttm < To_Date('2016-03-10','YYYY-MM-DD')" +
" ) , 'YYYY-MM-DD') = to_Date (" +
" (SELECT MAX(crE_Dttm)" +
" FROM ci_bill" +
" WHERE accT_id='"+acctid.getIdValue()+"'" +
" AND crE_dttm<=" +
" (SELECT add_months(To_Date('2016-03-10','YYYY-MM-DD'), -1) FROM dual" +
" ) ) ,'YYYY-MM-DD'))" +
" THEN To_Date('2016-03-10','YYYY-MM-DD')" +
" ELSE" +
" ( SELECT MAX(crE_Dttm)" +
" FROM ci_bill" +
" WHERE accT_id='"+acctid.getIdValue()+"'" +
" AND crE_dttm < To_Date('2016-03-10','YYYY-MM-DD')) " +
" END)";
com.splwg.base.api.sql.PreparedStatement ps4 = createPreparedStatement(query4);
logger.info(ps4);
ps4.execute();
if(!ps4.list().isEmpty())
{
first_pay=new BigDecimal(ps4.list().get(0).get("FIRST_PAY").toString());
logger.info("first_pay=="+first_pay);
}
}
The error is:
ORA-01830: date format picture ends before converting entire input string site:community.oracle.com
Please note the PreparedStatement is from com.splwg.base.api.sql.PreparedStatement
I think you are passing different date formats in your where clause. Please try matching the date format of crE_dttm with To_Date('2016-03-10','YYYY-MM-DD')
e.g. to_date(crE_dttm, 'YYYY-MM-DD') < To_Date('2016-03-10','YYYY-MM-DD')
Thanks
Sabiha
I am trying to insert records into SQL Server using jdbc conn (in java).
I am able to insert into SQL, if I manually copy the query statement in the java file. But its not inserting from the code?
Please help, where am I committing mistake?
PreparedStatement preparedStatement = null;
if (conn != null) {
System.out.println("Connection Successful!");
}
//Create a Statement object
Statement sql_stmt = conn.createStatement();
//Create a Statement object
Statement sql_stmt_1 = conn.createStatement();
//Result Set for Prouduct Table
ResultSet rs = sql_stmt.executeQuery("SELECT MAX(ID), MAX(RG_ID), MAX(WG_ID) FROM " + strDBName + ".[dbo].Product");
if ( rs.next() ) {
// Retrieve the auto generated key(s).
intID = rs.getInt(1);
intRG_ID = rs.getInt(2);
intWG_ID = rs.getInt(3);
}
for (int iCount = 0 ;iCount < arrListLevel_1_Unique.size(); iCount++)
{
//Result Set for Prouduct Table
sql_stmt_1.executeUpdate("\n IF NOT EXISTS(SELECT 1 FROM " + strDBName + ".[dbo].Product WHERE [Name] NOT LIKE '" + arrListLevel_1_Unique.get(iCount) + "') "
+ "\nINSERT INTO " + strDBName + ".[dbo].Product ([Name] ,"
+ "[RG_ID],[WG_ID],[Parent_Product]) "
+ "VALUES ( '" + arrListLevel_1_Unique.get(iCount) + "',"
+ + (intWG_ID + intRowIncrement) + ", " + (intWG_ID + intRowIncrement + 1) + ", 5828)");
intRowIncrement++ ;
}
rs.close();
sql_stmt.close();
sql_stmt_1.close();
//Close the database connection
conn.close();
You have two plus signs + in the fifth row:
+ + (intWG_ID + intRowIncrement) + ...
Otherwise, the problem may lie in the IF ... statement. You can try this instead:
sql_stmt_1.executeUpdate(
" INSERT INTO " + strDBName + ".[dbo].Product ([Name] ,"
+ "[RG_ID],[WG_ID],[Parent_Product]) "
+ " SELECT '" + arrListLevel_1_Unique.get(iCount) + "',"
+ (intWG_ID + intRowIncrement) + ", "
+ (intWG_ID + intRowIncrement + 1) + ", 5828 "
+ " WHERE NOT EXISTS( SELECT 1 FROM " + strDBName
+ ".[dbo].Product WHERE [Name] LIKE '"
+ arrListLevel_1_Unique.get(iCount) + "') "
) ;
I think the problem lies on the "\n", have you tried eliminating those 2 of "\n" and see if it's working?
Actually this kind of implementation (building SQL string with string concatenation) is really bad. At first is prone to SQL injection, and then secondly you will have problem if the value to be inserted contains character single quote or ampersand.
Instead, you should use "prepare statement".
And it's tidier to store the SQL string into a variable before executing it. So that you can log it (for debug purpose), roughly something like this:
String sqlCommand = "select * from " + tableName;
System.out.println(sqlCommand);
sqlStatement.executeUpdate(sqlCommand);
P.S. it is not advised to use system.out.println for debug, you should implement a proper logging system.