Good day, all. I am working on a personal project that needs to interact with an ms access 2016 db. My java application gets data from a user and this info is stored in an Object[]. I am trying to insert the elements of my obj array to a table in my db. This is my code:
Connection conn = null;
PreparedStatement pstmnt = null;
String sql = null;
ResultSetMetaData md = null;
Statement stm = null;
ResultSet rs = null;
int i = 0;
String q = "SELECT * from QueryData";
try{
conn = DriverManager.getConnection("jdbc:ucanaccess://filePath");
stm = conn.createStatement();
rs = stm.executeQuery(q);
md = rs.getMetaData();
int count = md.getColumnCount();
String[] colName = new String[count];
for (int n = 1; n <= count; n++)
colName[n-1] = md.getColumnLabel(n);
while ( i <= data.length) {//data being the object array containing the data to be inserted in db
query = "INSERT into QueryData ('"+colName[i]+"') VALUES ('"+data[i]+"')";
//The following code is where I get the exception
pstmnt = conn.prepareStatement(query);
//some more code follows..
On the first pass throught the while loop, colName[i] is "logDate" which is the first field in the table and data[i] is a LocalDate object formatted as 2016-12-23. I know I did not close the while loop above nor did I given the catch clause, but my program does not run past the pstmnt assignment. I keep getting the exception "net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::3.0.7 unexpected token: logDate".
Any assistance will be greatly appreciated as I've scoured the web amd this forum but could not find a working solution to my problem.
You are surrounding your column name with quotes, which isn't allowed. You can use square brackets instead (although not really necessary unless you have spaces in the field names, which Access allows).
query = "INSERT into QueryData (["+colName[i]+"]) VALUES ('"+data[i]+"')";
You might also need to use # instead of ' to delimit the date value. Access used to use # for date delimiters, and I'm not sure if more recent versions accept ':
query = "INSERT into QueryData (["+colName[i]+"]) VALUES (#"+data[i]+"#)";
Related
I am want to take id of each no which are presented in the array constant. Please find the below code. When i am running this i am getting "ResultSet not positioned properly, perhaps you need to call next." error. but 101 working correctly. rest of the values or not fetched. Please anyone help me
PreparedStatement m_inoutid = null;
docno="[101,102,103,104]";
String minoutid[]=new String[1000];
String documentno = docno.substring(1, docno.length() - 1);
List<String> docnumbers = new ArrayList<String>();
String[] split = documentno.split(",");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < split.length; i++) {
String sql = "select id from mytable where fid=?";
outid = conn.prepareStatement(sql);
String idfromquery=split[i];
outid.setString(1, idfromquery);
ResultSet idResultSet = outid.executeQuery();
idResultSet.next();
id = idResultSet.getString("id");
final List<Object> parameters = new ArrayList<Object>();
parameters.add(null);
parameters.add(id);
myfunction(parameters);
}
I can see here two things that you might try:
You can check if all of your queries return at least one row. Maybe there is an ID you pass to the query that does not validate the WHERE clause for any of the results. You can check this by placing the call to next in a conditional statement like
if(idresultSet.next()) id = idResultSet.getString("id");
Additionally, maybe you should try to place the cursor to the first row (just to be sure) after executing the query. Like
ResultSet idResultSet = outid.executeQuery();
idResultSet.first();
idResultSet.next();
I need to execute a SQL PreparedStatement in Java using jdbc.
I'm facing problems with one of the parameters because it has SQL content and also Strings from a resource file.
It looks something like this:
Required SQL:
SELECT * FROM Table T WHERE T.value = 10 AND T.display IN ('Sample1', 'Sample2')
In the above query, the Sample1 and Sample2 values must be passed through a parameter to a PreparedStatement.
PreparedStatement:
SELECT * FROM Table T WHERE T.value = 10 ?
In my application code I'm setting the parameters like:
statement.setString(1, "AND T.display IN ('Sample1', 'Sample2')");
However this is not returning the appropriate results.
Is there a better way to build this particular parameter considering it has SQL content and Strings too?
EDIT:
Sample1, Sample2 etc. are strings that are retrieved from an external file at run-time and there can be different number of these strings each time. I.e. there can be only one string Sample1 or multiple strings Sample1, Sample2, Sample3, etc..
EDIT2:
Database being used is Oracle.
The ? placeholder can only be used in a position where a value is expected in the query. Having a ? in any other position (as in your question: WHERE T.value = 10 ?) is simply a syntax error.
In other words: it is not possible to parametrize part of the query itself as you are trying to do; you can only parametrize values. If you need to add a dynamic number of parameters, you will need to construct the query dynamically by adding the required number of parameters and using setString(). For example:
StringBuilder sb = new StringBuilder(
"SELECT * FROM Table T WHERE T.value = 10 AND T.display IN (?");
// Note: intentionally starting at 1, first parameter already above
// Assuming always at least 1 parameter
while (int i = 1; i < params.length; i++) {
sb.append(", ?");
}
sb.append(')');
try (
PreparedStatement pstmt = con.prepareStatement(sb.toString())
) {
for (int i = 0; i < params.length; i++) {
pstmt.setString(i + 1, params[i]);
}
try (
ResultSet rs = pstmt.executeQuery();
) {
// Use resultset
}
}
Use this as PreparedStatement
"SELECT * FROM Table T WHERE T.value = 10 AND T.display IN (?, ?);"
and then call
statement.setString(1, "Sample1");
statement.setString(2, "Sample2");
before executing the statement.
Update:
String generateParamString(int params) {
StringBuilder sb = new StringBuilder("(");
for (int i = 1; i < params; i++) {
sb.append("?, ");
}
sb.append("?)");
return sb.toString();
}
List<String> samples = ... // your list with samples.
String stmtString = "SELECT * FROM Table T WHERE T.value = 10 AND T.display IN "
+ generateParamString(samples.size());
// generate statement with stmtString
for (int i = 0; i < samples.size(); i++) {
statement.setString(i + 1, samples.get(i));
}
// execute statement...
I've been trying to figure out what's wrong with the resultset for the past 2 hours. I'm trying to connect to a MS Access database, and I have a similar working method that is almost exactly the same except the sql statements are different. Since the sql statement highlights everything in the table, I assumed the resultset would work, but apparently not. Can anyone give me a pointer?
Here's my code:
public static Video[] searchdatabase(String videoname, String uploadername, int likes, int dislikes, int favorites, int subscribers,int views, String category) throws SQLException
{
String sql = "SELECT COUNT(VideoID) AS Num FROM tblYoutubeVideo";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
rs.next();
int numrows = rs.getInt("Num");
System.out.println("Numrows: "+numrows);
Video[] arr2 = new Video[numrows];
sql = ("SELECT * FROM tblVideo, tblUploader WHERE tblVideo.Video_Name LIKE '"+videoname+"' AND tblUploader.Uploader_Name LIKE '"+uploadername+"'AND tblVideo.Views>"+views+" AND tblVideo.Likes>"+likes+" AND tblVideo.Dislikes<"+dislikes+" AND tblVideo.Favorites>"+favorites+" AND tblUploader.Subscribers>"+subscribers+"ORDER BY (Likes+(Views*0.5)+(Favorites*2)+(Subscribers*2))-2");
System.out.println(sql);
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
for (int i=0;i<arr2.length;i++)
{
rs.next();
int uploaderid2 = rs.getInt("UploaderID");
String uploader_name2 = rs.getString("Uploader_name");
int subscribers2 = rs.getInt("Subscribers");
int videoid2 = rs.getInt("VideoID");
String video_name2 = rs.getString("Video_name");
int favorites2 = rs.getInt("Favorites");
String category2 = rs.getString("Category");
int views2 = rs.getInt("Views");
int likes2 = rs.getInt("Likes");
int dislikes2 = rs.getInt("Dislikes");
Video temp = new Video(uploaderid2, uploader_name2, subscribers2, videoid2, video_name2, favorites2, category2, views2, likes2, dislikes2);
System.out.println(arr2[i]);
arr2[i] = temp;
}
return arr2;
}
Thanks in advance :)
I suspect the problem is here:
rs.next();
You're ignoring the return value of next(), which tells you whether or not you've actually moved onto another valid row, or whether you've reached the end of the results. You're currently assuming that you have numrows results, even though numrows is the number of rows in tblYoutubeVideo and your actual query is filtered.
I would personally remove the first query completely - just use an ArrayList<Video> instead, and instead of your for loop, have:
List<Video> videos = new ArrayList<Video>();
while (rs.next())
{
... read data ...
videos.add(new Video(...));
}
Additionally, not that your current code is vulnerable to SQL injection attacks. Rather than include values directly in your SQL, you should use parameterized SQL with PreparedStatement. You specify placeholders in the SQL itself, and set the parameter values in the statement.
Additionally, you should be closing the statement and result set in finally blocks. (I'd personally close the connection, too - use a connection pool so that you can always open the connection, use it, and close it.)
I'm writing data from Java to an Access database on Windows 32 bit. When I write a record, I need to retrieve the row ID / primary key so that I can a) update the record easily if I want to and b) cross reference other data to that record.
When did something similar in C, I could make a updatable cursor which allowed me to write a new record and simultaneously retrieve the row ID. With Java, it looks as though I should be able to do this, but it throws an exception with the following code.
con = openAccessDatabase();
String selectString = "SELECT ID, RunCount FROM SpeedTable";
try {
PreparedStatement selectStatement = con.prepareStatement(selectString,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet idResult = selectStatement.executeQuery();
int id;
for (int i = 0; i < nWrites; i++) {
idResult.moveToInsertRow();
idResult.updateObject(1, null); // this line makes no difference whatsoever !
idResult.updateInt(2, i);
idResult.insertRow(); // throws java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver]Error in row
id = idResult.getInt(1);
}
selectStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
The only thing I've been able to do is to write a new record and then run a different query to get the Row id back ...
String insertString = "INSERT INTO SpeedTable (RunCount) VALUES (?)";
String idString = "SELECT ID FROM SpeedTable ORDER BY ID DESC";
//
try {
ResultSet idResult = null;
PreparedStatement preparedStatement, idStatement;
preparedStatement = con.prepareStatement(insertString,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
idStatement = con.prepareStatement(idString,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
for (int i = 0; i < nWrites; i++) {
// write the data into the database
preparedStatement.setInt(1, i);
preparedStatement.execute();
// re-run the query to get the index back from the database.
idResult = idStatement.executeQuery();
idResult.next();
int lastIndex = idResult.getInt(1);
idResult.close();
}
This works but becomes impossibly slow when the table has more than a few 10's of 1000's of records in it. There is also a risk of returning the wrong ID if two parts of the program start writing at the same time (unlikely but not impossible).
I know that at least one suggestion will be to either not use Java or not use Access, but they are not options. It's also part of a free open source software package, so I'm reluctant to pay for anything. Writing my own C JNI interface which provides the basic functionality that I need for my application is even less appealing.
Not sure if this works for MS Access but you can try:
st.executeUpdate("INSERT INTO SpeedTable (RunCount) VALUES (1000)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = st.getGeneratedKeys();
rs.next();
long id = rs.getLong(1);
I use the following code
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:access");
String sql = "Select * from table";
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery( sql );
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
for (int i = 1; i <= columns; i++) {
columnNames.addElement( md.getColumnName(i) );
}
while (rs.next()) {
Vector row = new Vector(columns);
for (int i = 1; i <= columns; i++){
row.addElement( rs.getObject(i) );
}
data.addElement( row );
}
rs.close();
stmt.close();
}catch(Exception e){
System.out.println(e);
}
It displays:
java.sql.SQLException:[Microsoft][ODBC Driver Manager] Invalid descriptor index
How is this caused and how can I solve it?
I have had the same exact error, this out of an ODBC Express Driver for Delphi.
The solution I have found is:
Place your varchar(max) and or varbinary(max) fields at the end of your select Query. (Order in the table definition doesn't matter).
This really fixed it for us, thought to share it with you guys.
I doubt the exception is thrown by one of the lines in the posted code. I have my reasons to state so.
A SQLException with the message "Invalid descriptor index" is usually obtained when you read the result set incorrectly. There are various ways in which this scenario can manifest:
Reading columns out of sequence. I'm afraid, some JDBC drivers will require you to read columns in order, starting at the first column. That's the way some drivers have been written; you cannot skip any columns when reading the resulting result set, as the drivers are actually reading a stream and converting objects in the stream to objects of the JDBC types.
You might be reading a column, whose index is invalid, or whose column name doesn't match any of the returned columns in the result set. The simple resolution is to either fix the query to return the needed column, or fix your code to not read the absent column.
If you need to solve it, you need to know which one of the above conditions is true in your code, and rectify accordingly.
I know this bug for many years by using ODBC driver with PHP. Try to place your text and image columns at the end of select list.Dont use
select * from t
but enumerate rigidly
select plain_column1, plain_column2, .... image_column from t
Unfortunately Microsoft doesn't get tired by fixing the bug. JDBC driver works OK.
That will occur if you're trying to get the resultset variable value in the index value of 0.
For example:
Consider a table which has 5 columns:
ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName);
while(rs.next())
{
for(int i=0;i<5;i++)
//This will throw the exception
System.out.println(rs.getString(i)); //Since the value will be returned from 1 not 0
//The below code was the right way
System.out.println(rs.getString(i+1));
}
I got an error
SEVERE: null
java.sql.SQLException: [Microsoft][SQL Server Native Client 10.0]Invalid Descriptor Index
code was
String sqlStr = "select soldItems.payment as aa, Sysuser.name as sname, Books.Name as abookName, soldItems.Qunt as qunt, soldItems.date as soldBooks from Sysuser inner join soldItems on soldItems.CustomerId=Sysuser.id inner join Books on Books.bookId=soldItems.bookId where CustomerId='" + cusId + "' and PaymentDone is NULL";
System.out.println(sqlStr);
DbConnection con = new DbConnection();
con.getConnection();
ResultSet rs = con.getData(sqlStr);
while (rs.next()) {
int i = 0;
dataArry[i][0] = rs.getString("abookName");
dataArry[i][1] = rs.getString("qunt");
dataArry[i][2] = rs.getString("aa");
dataArry[i][3] = rs.getString("soldBooks");
i++;
}
the fix is rs.getString needs to be in the same order of the SQL
so the code needs to be
dataArry[i][2] = rs.getString("aa");
dataArry[i][0] = rs.getString("abookName");
dataArry[i][1] = rs.getString("qunt");
dataArry[i][3] = rs.getString("soldBooks");
I have explained #Remco answer with example which is simple and short and helped me to solve my problem. Find the column info of MYTABLE first and place the column at the end with max values(suppose varchar(max) and or varbinary(max)). Try the example below.
With Error
library(DBI)
library(ODBC)
myquery<- dbGetQuery(con,"SELECT * FROM MYTABLE")
Error in Result_fetch....: Invalid Descriptor Index
Solution
dbcolumnInfo(dbSendWuery(con,"SELECT * FROM MYTABLE")
From the results for DateTimeSampled is varchar(max). Place this column at the end of MYTABLE using following query.
myquery<- dbGetQuery(con,"SELECT [PROCHI],[hb_extract],
[QuantityValue],[QuantityUnit],[Interpretation],
[LabNumber],[LocalClinicalCodeValue],[DateTimeSampled]
FROM MYTABLE")
Enjoy SQL with R