ms access database with java - java

I am creating a java program, with which I am editing into a Microsoft Access Database. I have a certain case, in which I need to search if a certain record already exists in my table, if it does, I want to update it, and if not, I want to create it from scratch.
I have found this piece of code:
IF EXISTS (SELECT * FROM USERS WHERE USERID=#UID) select 1 else select
This code gives me an error, saying that a SELECT, UPDATE or DELETE statement was expected.
In a code that I have tried my self, I have done the following:
try{
s = con.createStatement();
s.executeQuery("SELECT * FROM table WHERE date='" + today + "'");
rset = s.getResultSet();
if (rset.getString("date") == null){
s = con.createStatement();
s.executeUpdate("INSERT INTO table VALUES ('" + today + "','" + cflow + "','" + vat + "','" + cnn + "')");
}
}
catch (SQLException exp)
{
System.err.println(exp);
}
But with this code, when the record does not exist yet, the user input is not updated inside the database.
Thanks for your time :)

1st: If I can remember right, then is
IF EXISTS (SELECT * FROM USERS WHERE USERID=#UID) select 1 else select
an incomplete transact sql statement -used by the sql engine from a database system.
2nd:
if (rset.getString("date") == null){}
you should avoid this way, because there is a good chance to get a Nullpointer Exception.
In my eyes a better one is a test the size of resultset for zero or the resultset it self for the value of NULL.
In case the UPDATE statement won't also be executed, check your SELECT statement using the database engine -Ms Access, SQL Server, etc.- directly. The advantage is you can exclude a mistake in your SELECT query.

What about this?
SELECT IF EXISTS (SELECT * FROM USERS WHERE USERID=#UID) THEN 1 ELSE 0 END
or
SELECT IF(EXISTS (SELECT * FROM USERS WHERE USERID=#UID), 1, 0)
(I'm not sure about the real syntax here.)

(rset.getString("date") == null)
should be
(!rset.next())
rset is positioned 'before' the first result that gets returned. next() returns true if there was a 'next' result to get.
Also, what datatype is your 'date' variable? There's no guarantee that a date.toString() will format the date correctly for MS-Access version of SQL.
Rather, prepare a statement
PreparedStatement ps = connetion.prepareStatement("SELECT * from table where date=?");
and set the date like
ps.setDate(1, date);
then issue the query using the prepared statement.
That saves any toString() issues. (I haven't compiled this, it almost certainly won't work as-is, but the idea is there).

Here is what i used to find the last ID in a table. IF the table is empty the no ID will be returned. If table is populated then i needed the next ID for new record.
ResultSet mn = stmt.executeQuery("SELECT MAX(ExamID)FROM ExamResults");
if (mn == null){
jTextField1.setText("1");
} else{
while (mn.next()) {
int lastID =Integer.parseInt(""+(mn.getObject(1)));
jTextField1.setText(""+(lastID+1));
}
}
// close the objects
mn.close();
stmt.close();
conn.close();

Related

How do I check if the sql command returns null or a value?

try{
Statement stm = conn.createStatement();
String sql = "SELECT * from BOOKS WHERE ISBN_No = '" + line + "'";
ResultSet rs = stm.executeQuery(sql);
if(//values are returned) {
displayBookInfo(line);
}
else (//if it is null) {
System.out.println("No book found");
}
stm.close();
} catch (SQLException e) {
e.printStackTrace();
System.out.println("Fail to search the book" + line );
noException = false;
}
After I execute the ResultSet rs = stm.executeQuery(sql); I want to check if the query returned a value or if it was empty so that I can execute either "display book details" or "no book found message". I am just confused about how I should compare and how comparison works.
This code is a security leak. You must fix this first.
You cannot include untrusted inputs in a query like this. What if someone enters, say:
1234'; DROP TABLE books CASCADE; EXECUTE 'FORMAT C: /Y'; --
In the web form? Don't try it, you'll wipe your disk. You get the point, surely.
The right way is to use stm.prepareStatement(sql), where sql is a constant (so not something you insert user entered stuff into), using a ? where user input is needed, then calling .setString(1, line) to then tell your db driver what should go in place of the question mark.
Then, simply rs.next(), which advanced to the next row in the result (first call advances to the first row). If there are no rows left, it returns false instead. Hence, if your query returns 0 rows, the first resultSet.next() call returns false right away.
Your code also fails to close. You must use try-with-resources on everything (ResultSet, (Prepared)Statement, and most importantly the Connection), or your app will crash after a few statements.
NB: Minor nit, if all you want to know is if there's at least one result, add LIMIT 1, and just SELECT 1 FROM instead - it's less overhead that way.

How do I check for value existence / why is ResultSet closed in SQLite?

Setup
I am using JDBC SQLite for my server database.
What I am trying to do
I want to check if a value (for example an ID or a username) already exists in a table.
My Code
PreparedStatement preparedStatement = connection.prepareStatement("select * from " + tableName + " where " + columnName + "=? limit 1");
preparedStatement.setString(1, value);
ResultSet resultSet = preparedStatement.executeQuery();
resultSet.next();
try { // this was just for testing and is dumb because it prints an error every time the value does not exist.
// my code actually wasn't wrong. I just tested it badly ..
// it's replacable with if (resultSet.next())
resultSet.getString(1);
System.out.println("check true");
return true;
} catch (Exception e) {
e.printStackTrace();
System.out.println("check false");
return false;
}
Here I want to check if a specific value already exists in my column(Name) in my table.
The Problems
This code will always throw a SQLException: "ResultSet closed" at resultSet.getString(columnName). It does not matter if the value already exists in the table or not. My query could also be wrong because I don't get what I should put after select. I had a 1 there once, but everyone was using * for "all" and it changed nothing. I seriously don't get this because it is too complicated for me and I just wanted to know what the argument after select does..
Approaches
I tried many things and read a lot of threads, but the only thing I came across was that I need to first call resultSet.next() and that the ResultSet won't throw ResultSet closed exception that way, but it didn't change anything.
If there is a better way to check if a value already exists in a table, please tell me.
Visualisation
I have a table here (the NULL's don't matter they could be some random values) and I want to check ggffvgvg exists or not.
Complete StackTrace
java.sql.SQLException: ResultSet closed
at org.sqlite.core.CoreResultSet.checkOpen(CoreResultSet.java:69)
at org.sqlite.core.CoreResultSet.markCol(CoreResultSet.java:96)
at org.sqlite.jdbc3.JDBC3ResultSet.getString(JDBC3ResultSet.java:436)
at Database.check(Database.java:50)
at ClientHandler.run(ClientHandler.java:72)
resultSet.next() returns a boolean which tells you whether there is a next record or not. Ignoring this returned value is like shooting your own foot with a rocket launcher.
So, if the value you are looking for is not in the result set, (either because it really isn't, or because you did not ask for it properly,) resultSet.next() will return false, and your code will blow up with the exception that you are receiving.
Your resultSet.getString(1) clause will fetch the first column in the result set, (if there is a current row,) and it will return it to you assuming that it is in fact a string. The first column of most tables is usually an integer, or some other kind of key data type, which means that it is rarely a string. If you are lucky, it will be something that the JDBC driver can convert to a string, but you are tempting your fate by assuming that.
If you are only going to check the value of a single column, then your query statement must select that column only. This means that instead of
"select * from " + tableName + " where " + columnName + "=? limit 1"
you must do
"select " + columnName + " from " + tableName + " where " + columnName + "=? limit 1"
However, if I understand correctly what you are trying to achieve, you do not even need to fetch the field and check its value. Simply the true or false result of resultSet.next() should suffice.

MySQL - Object not null?

I am trying to check if a player is already is in the database with this code:
Statement sql = mySql.getConnection().createStatement();
ResultSet check = sql.executeQuery("SELECT * FROM `playerinfo` WHERE Username='" + player.getName() + "';");
System.out.println(check.toString());
if(check != null) {
System.out.println("2");
Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "Player already in database");
check.close();
sql.close();
return;
}
I checked but nothing is in the database and it says that the player already contains in the database
Sorry for bad english
Some considerations:
When checking whether the database contains a certain value, it's good practise to do this using a query that returns a single value (and not SELECT * which returns all columns of all rows that match the WHERE condition). You can do this e.g. by selecting a single check flag (SELECT 1) with a row-limiting clause (LIMIT 1):
SELECT 1 FROM playerinfo WHERE Username = ? LIMIT 1
This query is guaranteed to return only one row (with a single column, '1') if a player with the given name exists, or no rows if there are no players with the given name.
As others have pointed out, when you're inputting parameters into the query, you should use a PreparedStatement instead of a simple statement with concatenated inputs. This way, you can avoid SQL injection and the database is also able to reuse/cache the query (or cursor) internally.
Finally, you should close the resources you use, even if an Exception gets thrown during the execution. This is best done in the finally clause, or if you're on Java 7 or later, using the try-with-resources statement.
With these things in mind, a re-write of your code could look like this:
PreparedStatement ps = null;
try {
ps = mySQL.getConnection()
.prepareStatement("SELECT 1 FROM playerinfo WHERE Username = ? LIMIT 1");
ps.setString(1, player.getName());
ResultSet rs = ps.executeQuery();
// the first invocation of rs.next() returns true if
// there are rows in the result set, or false if no rows were found
if (rs.next()) {
System.out.println("2");
Bukkit.getConsoleSender().sendMessage(ChatColor.RED
+ "Player already in database");
}
rs.close();
} finally {
if (ps != null) {
ps.close();
}
}
I think instead of checking if the ResultSet is null or not, you should check if the ResultSet contains any row or not.
Apart from that, use PreparedStatements.

How to insert and select from mysql simultaneously

I have a requirement where I need to insert mobile number in mysql if and only if the number is is not present.So for this I am first checking if a number is present in mysql using select query .If number is not present then insert.Following is my code
PreparedStatement pt1=con.prepareStatement("select * from registerSmsUsers where mobile='"+mobile+"'");
PreparedStatement pt=con.prepareStatement("insert into registerSmsUsers values(?,?,?)");
pt.setString(1, name);
pt.setString(2, email);
pt.setString(3, mobile);
ResultSet rs1=pt1.executeQuery();
if(rs1.next())
{pt.executeUpdate();}
i dont know whether this is a efficient way or not.Please suggest me a better way then this
Probably the easiest way in mysql is:
insert ignore into registerSmsUsers values(?,?,?)
When assuming you have unique key on mobile
You may check it here: How to 'insert if not exists' in MySQL?
Or here: http://dev.mysql.com/doc/refman/5.6/en/insert.html
Many of the proposed solutions (including yours) have a race condition that can cause a primary key or unique constraint violation. You code also have a possible SQL injection attack by concatenating SQL rather than using prepared statement parameters. Use SELECT...FOR UPDATE.
PreparedStatement ps = con.prepareStatement("SELECT name, email, mobile FROM registerSmsUsers WHERE mobile=? FOR UPDATE",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
ps.setString(1, mobile);
ResultSet rs = ps.executeQuery();
if (rs.next()) { // it exists already
rs.moveToCurrentRow();
rs.updateString(3, mobile);
rs.updateRow();
} else { // it does NOT exist
rs.moveToInsertRow();
rs.updateString(1, name);
rs.updateString(2, email);
rs.updateString(3, mobile);
rs.insertRow();
}
rs.close();
ps.close();
EDIT: Just make sure you have an index on registerSmsUsers.
CREATE INDEX registerSmsUsers_mobile_ndx ON registerSmsUsers(mobile)
or a unique contraint (which implicitly creates an index):
ALTER TABLE registerSmsUsers ADD CONSTRAINT registerSmsUsers_mobile_unq UNIQUE (mobile)
With an index, even with millions of records the update/insert will basically be instant.
EDIT2: Added cursor/result set options.
I think it would be better to create a stored procedure and then in that stored procedure you can first use the IF NOT EXISTS clause to check if the user exists using the select statement. If the user is not present you can insert the user in database.
Something like this:
IF NOT EXISTS(SELECT 1 FROM `registerSmsUsers` WHERE mobile= #mobile) THEN
BEGIN
INSERT INTO
`registerSmsUsers`
(
//column names
)
VALUES
(
//values
);
END;
END IF;
Also there is a INSERT IGNORE statement which you can use like this:
insert ignore into registerSmsUsers values(?,?,?)
if not exists(select * from registerSmsUsers where mobile='232323') <-- will check your mobile no
begin
insert into registerSmsUsers values(?,?,?)
end
This one is also an efficient way to check your method is also working fine but this also can be done
See difference is you will have only one query here
i hope this will help you thanks
[Edit]
Your questions answer
Ya there is a execution time diff between yours and mine query its depends upon a database size what you are using if you are using small size database (probably 1000 people) then you will not see any diff between your query and mine query but if your are using lakhs of users then your will have a performace issues check include execution plan in mysql you will get realtime difference between two
As requested, here is my tweaked version of brettw's answer:
import java.sql.*;
public class MySQLtest {
public static void main(String[] args) {
Connection con;
try {
con = DriverManager.getConnection(
"jdbc:mysql://192.168.1.3/zzzTest?" +
"useUnicode=yes&characterEncoding=UTF-8" +
"&user=root&password=whatever");
String newName = "Gord";
String newEmail = "gord#example.com";
String newMobile = "416-555-1212";
String sql =
"SELECT " +
"id, " +
"name, " +
"email, " +
"mobile " +
"FROM registerSmsUsers " +
"WHERE mobile = ? " +
"FOR UPDATE";
PreparedStatement pst = con.prepareStatement(
sql,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
pst.setString(1, newMobile);
ResultSet rs = pst.executeQuery();
if (rs.next()) {
rs.moveToCurrentRow();
rs.updateString("name", newName);
rs.updateString("email", newEmail);
rs.updateRow();
System.out.println("Existing row updated.");
}
else {
rs.moveToInsertRow();
rs.updateString("name", newName);
rs.updateString("email", newEmail);
rs.updateString("mobile", newMobile);
rs.insertRow();
System.out.println("New row inserted.");
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
Note that id is the Primary Key for the table: int(11) NOT NULL AUTO_INCREMENT

Prepared statement fails, but SQL console works

I am working on a project for uni (happens to be due in 14 hours) and I am at a sticking point. It is a web based web store running in eclipse on apache tomcat and derby.
I have a prepared statement that checks for a user name and passwordhash, no matter what I try this statement returns 0 rows. The same sql runs in the sql scratch pad and returns what is expected.
I have used the debugger to inspect the prepared statement object and the query seems fine. The ?'s in the text are still in place rather than filled with the variables, but that seems normal. I have also tried to run the exact same hand written sql from the console, but without any luck.
The query I run in the sql console is
SELECT * FROM username WHERE username='user#system.com' AND passwordhash='passwordhash'
The prepared statments look like this.
PreparedStatement pstmt = db.prepareStatement("SELECT * FROM reallynice.username " +
"WHERE emailaddress=?" +
" AND passwordhash=?");
pstmt.setString(1,username);
pstmt.setString(2, username + ":" + passwordLogin);
I am at the point where I have tried everything, and have run out of searches to make. I know this is a uni project and the standard reply is to give people somewhere to look. At this point I need spoon feed a path to go down.
EDIT Here is some more background, I have tried running a known working query in this pipeline and it also fails to return any rows.
public static User getUser(String username, String passwordHash) {
DBBean db = new DBBean();
System.out.println("Logging in for username " + username + " and password " + passwordHash);
try {
ResultSet rs;
PreparedStatement pstmt = db.prepareStatement("SELECT * FROM reallynice.username " +
"WHERE emailaddress=?" +
" AND passwordhash=?");
pstmt.setString(1,username);
pstmt.setString(2,passwordHash);
//PreparedStatement pstmt = db.prepareStatement("SELECT * FROM reallynice.product");
//PreparedStatement pstmt = db.prepareStatement("SELECT * FROM reallynice.username WHERE emailaddress='user#me.com' AND passwordhash='megahashstring'");
rs = pstmt.executeQuery();
System.out.println("Rows returned\t" + rs.getRow());
if(rs.getRow() < 1)
return null;
int id = rs.getInt("uid");
String name = rs.getString("name");
String emailaddress = rs.getString("emailaddress");
String password = rs.getString("passwordhash");
boolean isAdmin = false;
pstmt = db.prepareStatement("SELECT * FROM reallnice.admin WHERE uid= ?");
pstmt.setInt(1, id);
rs = pstmt.executeQuery();
if(rs.getMetaData().getColumnCount() > 0)
isAdmin = true;
return new User(id,isAdmin,name,emailaddress,password);
} catch(Exception ex) {
System.out.println(ex);
}
return null;
}
I have also included the other queries I have tried for this.
Whenever I see someone having an experience like this: "no matter what I try this statement returns 0 rows," there are two possible reasons that come immediately to mind:
1) You aren't using the database you think you are. Derby's connection URL, if you say ";create=true", will quite happily make a new, empty database when you connect, if it doesn't find an existing database in the location you expect. This sort of problem arises from a confusion over where the databases are created; a database with a relative name will be created in whatever directory turns out to the be derby.system.home of the Derby instance that gets that connection URL. So check to see if you are using a different current working directory, or for some other reason are connecting to a different database than you think you are.
2) You aren't using the schema you think you are. Derby will quite happily create multiple schemas, and each schema has a separate set of tables, so if you are initially connecting as user A, and then later connect as user B, and don't issue SET SCHEMA, then user A and user B have completely separate sets of tables and so you won't be accessing the tables that you think you are. So check to see if you are connecting as the same user and using the same schema when you connect to the database.
Try changing how you display your logging statement
System.out.println("Rows returned\t" + rs.getRow());
getRow() returns the current row number, not how many records were returned. In order to user getRow() to count the number of entries in the result set you would need to move the pointer of the result set to the last entry.
You have also, not called next() yet, which means you aren't pointing at anything (and most likely the reason you always see 0 as the number). Try using
while(rs.next()){ //go through the entire ResultSet}
or
if(rs.next()) { //access the first record in the ResultSet}
So over all, if you change your code to something like the following you may have better results.
rs = pstmt.executeQuery();
if(rs.next()){
System.out.println("Processing Row " + rs.getRow());
//continue on
}else{
System.out.println("No Records");
}
If you have set your table where the username is a unique key, you can be assured this will return 0 or 1 row. Otherwise use the while() option instead of if()
EDIT::
Also as a side note, because you are not calling next()
if(rs.getRow() < 1)
return null;
will always be 0, which returns null from your method.

Categories

Resources