I'm trying to insert CLOBs into a database (see related question). I can't quite figure out what's wrong. I have a list of about 85 clobs I want to insert into a table. Even when inserting only the first clob I get ORA-00911: invalid character. I can't figure out how to get the statement out of the PreparedStatement before it executes, so I can't be 100% certain that it's right, but if I got it right, then it should look exactly like this:
insert all
into domo_queries values ('select
substr(to_char(max_data),1,4) as year,
substr(to_char(max_data),5,6) as month,
max_data
from dss_fin_user.acq_dashboard_src_load_success
where source = ''CHQ PeopleSoft FS''')
select * from dual;
Ultimately, this insert all statement would have a lot of into's, which is why I just don't do a regular insert statement. I don't see an invalid character in there, do you? (Oh, and that code above runs fine when I run it in my sql developer tool.) And I if I remove the semi-colon in the PreparedStatement, it throws an ORA-00933: SQL command not properly ended error.
In any case, here's my code for executing the query (and the values of the variables for the example above).
public ResultSet executeQuery(String connection, String query, QueryParameter... params) throws DataException, SQLException {
// query at this point = "insert all
//into domo_queries values (?)
//select * from dual;"
Connection conn = ConnectionPool.getInstance().get(connection);
PreparedStatement pstmt = conn.prepareStatement(query);
for (int i = 1; i <= params.length; i++) {
QueryParameter param = params[i - 1];
switch (param.getType()) { //The type in the example is QueryParameter.CLOB
case QueryParameter.CLOB:
Clob clob = CLOB.createTemporary(conn, false, oracle.sql.CLOB.DURATION_SESSION);
clob.setString(i, "'" + param.getValue() + "'");
//the value of param.getValue() at this point is:
/*
* select
* substr(to_char(max_data),1,4) as year,
* substr(to_char(max_data),5,6) as month,
* max_data
* from dss_fin_user.acq_dashboard_src_load_success
* where source = ''CHQ PeopleSoft FS''
*/
pstmt.setClob(i, clob);
break;
case QueryParameter.STRING:
pstmt.setString(i, "'" + param.getValue() + "'");
break;
}
}
ResultSet rs = pstmt.executeQuery(); //Obviously, this is where the error is thrown
conn.commit();
ConnectionPool.getInstance().release(conn);
return rs;
}
Is there anything I'm just missing big time?
If you use the string literal exactly as you have shown us, the problem is the ; character at the end. You may not include that in the query string in the JDBC calls.
As you are inserting only a single row, a regular INSERT should be just fine even when inserting multiple rows. Using a batched statement is probable more efficient anywy. No need for INSERT ALL. Additionally you don't need the temporary clob and all that. You can simplify your method to something like this (assuming I got the parameters right):
String query1 = "select substr(to_char(max_data),1,4) as year, " +
"substr(to_char(max_data),5,6) as month, max_data " +
"from dss_fin_user.acq_dashboard_src_load_success " +
"where source = 'CHQ PeopleSoft FS'";
String query2 = ".....";
String sql = "insert into domo_queries (clob_column) values (?)";
PreparedStatement pstmt = con.prepareStatement(sql);
StringReader reader = new StringReader(query1);
pstmt.setCharacterStream(1, reader, query1.length());
pstmt.addBatch();
reader = new StringReader(query2);
pstmt.setCharacterStream(1, reader, query2.length());
pstmt.addBatch();
pstmt.executeBatch();
con.commit();
Of the top of my head, can you try to use the 'q' operator for the string literal
something like
insert all
into domo_queries values (q'[select
substr(to_char(max_data),1,4) as year,
substr(to_char(max_data),5,6) as month,
max_data
from dss_fin_user.acq_dashboard_src_load_success
where source = 'CHQ PeopleSoft FS']')
select * from dual;
Note that the single quotes of your predicate are not escaped, and the string sits between q'[...]'.
One of the reason may be if any one of table column have an underscore(_) in its name . That is considered as invalid characters by the JDBC . Rename the column by a ALTER Command and change in your code SQL , that will fix .
Oracle provide some explanation for ORA-00911. You can got this explanation after executing SQL request in Oracle SQL Developer.
ORA-00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual
But in your case it seems to be double ' character
Related
I am trying to calculate over time to add it to salary the overtime time stored in table attendance and the salary is stored in other table contain total basic hourly
I want to get the result from the 2 tables display them in java another store in another table for future reference
int Eid = Integer.parseInt(jTextField2.getText());
try{
Class.forName("com.mysql.jdbc.Driver");
Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/hr","root","adam");
String query="SELECT * FROM sallary where Eid ="+Eid +";"
java.sql.PreparedStatement preparedStatement = null;
preparedStatement = con.prepareStatement(query);
String select="select 83 *((time_to_sec(sum(overtime)) /60)/60)from att where Eid="+Eid +";";
java.sql.PreparedStatement preparedStatement2 = null;
preparedStatement2 = con.prepareStatement(select);
int eid;
double basic ,total,hourly;
ResultSet rs2 = preparedStatement2.executeQuery();
ResultSet rs = preparedStatement.executeQuery();
double overtime=rs2.getDouble(1);
// I tried this on MySQL command line it worked, however on java its error:
// the right syntax to use near 'sum(overtime)' at line 2
eid =rs.getInt("Eid");
basic =rs.getDouble("basic");
total=rs.getDouble("total");
hourly=rs.getDouble("hourly");
Object[] row = {eid,basic,total,hourly,overtime};
model = (DefaultTableModel) st.getModel();
model.addRow(row);
} catch (ClassNotFoundException | SQLException ex) {
Logger.getLogger(payroll.class.getName()).log(Level.SEVERE, null, ex);
}
The actual error message you got was something like "See the manual for your version of MySQL for the right syntax to use near 'sum(overtime)' at line 2." This error message tells you exactly what you need to do.
Looking at the manual:
https://dev.mysql.com/doc/refman/5.7/en/select.html
You can see that the SELECT statement syntax does not include a semicolon at the end.
The semicolon is a statement separator, useful when you give multiple statements at the console. JDBC queries are one statement at a time, so the semicolon makes no sense and is a syntax error.
By the way, you should leave out the statement Class.forName("com.mysql.jdbc.Driver");. There is simply no need for it. It was needed in earlier versions, but has been unnecessary for the last 15 years or so.
I have a sqlite database which contains strings. I am reading those strings from my javafx interface. Everything is working smoothly, however my problem is when I am trying to read strings with apostrophe. My code for reading the strings is the following:
String sql = "select * from Questions where Subject = ? and Grade = ? and Level = ? and questionId = ?";
PreparedStatement pst = gui.connectionQuestions.prepareStatement(sql);
pst.setString(1,gui.textSubjectQTest);
pst.setString(2,gui.showGradeLabel.getText());
pst.setString(3,gui.showCurrentLevelLabel.getText())
pst.setString(4,list.get(counter));
ResultSet rs = pst.executeQuery();
if(rs.next())
{
String temp = rs.getString("Question");
gui.question.setText(temp);
...
sql = "Update Questions set Used ='"+1+"' where Question = '"+gui.question.getText().replaceAll("'", "/'")+"'";
pst = gui.connectionQuestions.prepareStatement(sql);
pst.execute();
In the above code I peform a query to return the question string and add it to a label gui.question. However due to the apostrophe I am receiving the following error (I got the error due to the last line):
[SQLITE_ERROR] SQL error or missing database (near "(": syntax error)
I tried to follow the solution from here, however my prob still remains. How can I solve the thing with the apostrophe?
EDIT: I tried to escape character using double apostrophe. This approach is working but it changes my string to double apostrophe, which is not useful.
The quote or apostrophe character is escaped by doubling it.
BTW You don't need the if (temp.contains("'")).
I write a little program to admin my video collection.
/*
insert new data set into the table
*/
int next = 0;
rs = st.executeQuery("Select max(category_id) from category;");
if (rs.next()) {
next = rs.getInt(1) + 1;
System.out.println(next);
}
String query = "INSERT INTO category VALUES (" + next + ", 'Mystics', now());";
rs = st.executeQuery(query);
//on this place is the exception thrown
// this will not execute anymore
rs = st.executeQuery("DELETE FROM category WHERE name = 'Mystics';");
The program can select on tables, make joins but insert make trouble.
I try to insert some new data in my table (see Java-code). After the second test the output show me that the data was inserted. But after Insert was an exception thrown.
1 & 2 are the tests from yesterday and today. (3) was inserted but not selected yet.
1 Mystics 2015-07-05
2 Mystics 2015-07-06
3
org.postgresql.util.PSQLException: query produced no result.
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:287)
at postgre_java.Zetcode.main(Zetcode.java:55)
do you have some advises for me?
Do not manipulate data with read statements!
If you want to insert, update, delete data in db use
Statement stmt = conn.createStatement();
stmt.executeUpdate(SQL);
executeQuery returns resultset, but all that INSERT, UPDATE, DELETE can return is number of affected rows and that is what executeUpdate is returning.
And never, never, never*100 use string concatenation in SQL use Prepared statements!
In Java, you use executeQuery for a SELECT statement or some other statement which returns something. If you want to execute an INSERT, UPDATE or DELETE without returning something, you should use executeUpdate().
Statement#executeUpdate() is meant for that purpose
String query = "INSERT INTO category VALUES (" + next + ", 'Mystics', now());";
int noOfRows= st.executeQuery(query)
but it doesnt return a ResultSet , rather the no of rows affected that you could store into an Integer
Also your is highly vulnerable to Sql injection , try using the PreparedStatements to safeguard your code
I am trying to use a SQL Select statement for a query in Java. I currently have the following:
ResultSet rs = stmt.executeQuery("SELECT *" +
" FROM " + table +
" WHERE " + selection +
" VALUES " + selectionArgs);
where "selection" is a string and "selectionArgs" is a string array.
String selection = "documentFK=?";
String[] selectionArgs = { ... };
Is it possible to use the VALUES command to replace the ? like in with the INSERT command? Either way, what would be the correct syntax?
Thanks for the help.
I believe what you're looking for is the IN statement. Your query should look like this:
SELECT *
FROM table
WHERE documentFK IN ('doc1', 'doc2', 'doc3')
AND userFK IN ('user1', 'user2', 'user3')
This is (obviously) going to make your code a bit more ugly. You'll have to ensure that the WHERE keyword is used for the first clause, but the AND keyword is used for every other clause. Also, each list will have to be comma-delimited.
no, that is not the way it's done. first you create the statement from the query, using the question marks as place holders for the real values you want to put there. then you bind these values to the statement.
//the query
String sql = "SELECT " + "*" +
" FROM " + table +
" WHERE documetFK = ?";
//create the statement
PreparedStatement stmt = connection.prepareStatement(sql);
//bind the value
stmt.setInt(1, 4); //1 is "the first question mark", 4 is some fk
//execute the query and get the result set back
ResultSet rs = stmt.executeQuery();
now, if you want this thing with selection string and some args, then you're going to have a loop in your java code. not sure what your array looks like (you're not giving me that much to go on), but if it's made up from strings, it would be something like this:
//the query
String sql = "SELECT " + "*" +
" FROM " + table +
" WHERE " + selection;
//create the statement
PreparedStatement stmt = connection.prepareStatement(sql);
//bind the values
for(int i = 0; i < selectionArgs.length; i++) {
stmt.setString(i, selectionArgs[i]); //i is "the nth question mark"
}
//execute the query and get the result set back
ResultSet rs = stmt.executeQuery();
Can you use a PreparedStatement?
First of all SELECT .. WHERE .. VALUES is incorrect SQL syntax. Lose the VALUES part.
Then you're looking for prepared statements.
In your example it's going to look something like this:
String sql = "SELECT * FROM myTable WHERE documentFK=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "myDocumentFK"); // parameters start from 1, not 0. also we're assuming the parameter type is String;
ResultSet rs = pstmt.executeQuery();
Or with multiple parameters:
String sql = "SELECT * FROM myTable WHERE documentFK=? AND indexTerm=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "myDocumentFK"); // parameters start from 1, not 0. also we're assuming the parameter type is String;
pstsm.setInt(2, 100); // assume indexTerm can be 100 and is an integer
ResultSet rs = pstmt.executeQuery();
However, all of this doesn't worth your while since you can simply do the same by concatenating the value into the statement. But be aware of the SQL injections, so don't forget to escape the parameters that you're passing into the database.
PS: I was typing this way too long. You already have the answers :-)
As a side note, you may want to take a look at this to prevent SQL injections:
https://www.owasp.org/index.php/Preventing_SQL_Injection_in_Java
Sormula can select using "IN" operator from a java.util.Collection of arbitrary size. You write no SQL. It builds the SQL SELECT query with correct number of "?" parameters. See example 4.
I am working with a Java prepared statement that gets data from an Oracle database. Due to some performance problems, the query uses a "virtual column" as an index.
The query looks like this:
String status = "processed";
String customerId = 123;
String query = "SELECT DISTINCT trans_id FROM trans WHERE status = " + status + " AND FN_GET_CUST_ID(trans.trans_id) = " + customerId;
Connection conn = getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(query);
ps.execute();
...
} catch (...)
This does not work. Having the function as part of the where clause causes a SQLException. I am aware of CallableStatement, and know I could use that first and then concatenate the results. However, this table uses FN_GET_CUST_ID(trans_id) as part of it's index. Is there a way to use a prepared statement with a database function as a query parameter?
Never concatenate arguments for the SQL into the String. Always use placeholders (?) and setXxx(column, value);.
You'll get the same error if you'd run the SQL in a your favorite DB tool. The problem is that Oracle can't use the function for some reason. What error code do you get?
If Customer ID is numeric keep in int not in String. Then try doing the following:
String query = "SELECT DISTINCT trans_id FROM trans WHERE status = ? AND FN_GET_CUST_ID(trans.trans_id) = ?";
ps = conn.prepareStatement(query);
ps.setString(1, status);
ps.setInt(2, customerId);
ps.execute();
Besides other benefits of prepared statement you won't have to remember about string quotations (this causes your error most likely) and escaping of the special characters.
At the first glance, the query seems to be incorrect. You are missing an apostrophe before and after the usage of status variable (assuming that status is a varchar column).
String query = "SELECT DISTINCT trans_id FROM trans
WHERE status = '" + status + "' AND FN_GET_CUST_ID(trans.trans_id) = " + customerId;
EDIT: I am not from java background. However, as #Aron has said, it is better to use placeholders & then use some method to set values for parameters to avoid SQL Injection.