I am working with Oracle Database 10g, java and try to use ResultSet to insert new row.
I have object of ResultSet which is updateble and insensitive in direction meaning that you can traverse in any direction.
When I insert row in ResultSet using moveToInsertRow, insertRow, and setter method, the row is inserted in Database, but while traversing ResultSet, I am not able to view newly inserted row
Can any one help me.
My Code is :
import java.sql.*;
import java.io.*;
import java.util.Date;
public class TestResultSet{
public static void main(String...args){
try{
Connection con = DriverManager.getConnection("jdbc:oracle:thin:#//localhost:1521/xe", "system", "admin");
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("Select EnrNo, Name, Gender, DOB From Student");
int i;
while(rs.next()){
for(i = 1; i < 5; i++)
System.out.print(rs.getString(i) + ", ");
System.out.println();
}
//Inserting New Row
rs.moveToInsertRow();
rs.updateLong(1, 117020365276L);
rs.updateString(2, "Ashfaq");
rs.updateInt(3, 1);
Date d = new Date();
rs.updateDate(4, new java.sql.Date(d.getYear(), d.getMonth(), d.getDay()));
rs.insertRow();
//New Row Insertion ends here
rs.first(); //Moving to first row
do{
for(i = 1; i < 5; i++) //Index starts from 1, not from 0
System.out.print(rs.getString(i) + ", ");
System.out.println();
}while(rs.next());
}
catch(SQLException ex){ ex.printStackTrace(); }
catch(Exception ex){ ex.printStackTrace(); }
}
}
/*
Student Table Schema
EnrNo Numeric(12) Primary Key
Name varchar2(25);
Gender Numeric(1);
DOB date
*/
The problem is that the new row has been added to the database, not to the current rows recovered from database. So, in order to recognize the new row, you must do another read to your table(s). It could be inneficient (since it depends on how many rows and how complex your query is) but that's how it works.
Knowing this, your code should be like this:
ResultSet rs = stmt.executeQuery("Select EnrNo, Name, Gender, DOB From Student");
int i;
while(rs.next()) {
for(i = 1; i < 5; i++)
System.out.print(rs.getString(i) + ", ");
System.out.println();
}
//Inserting New Row
rs.moveToInsertRow();
rs.updateLong(1, 117020365276L);
rs.updateString(2, "Ashfaq");
rs.updateInt(3, 1);
Date d = new Date();
rs.updateDate(4, new java.sql.Date(d.getYear(), d.getMonth(), d.getDay()));
rs.insertRow();
//New Row Insertion ends here
//Moving to first row of the current recovered resultset
//thus not working as expected
//rs.first();
//close the resultset
rs.close();
//retrieve the rows from database again
rs = stmt.executeQuery("Select EnrNo, Name, Gender, DOB From Student");
do{
for(i = 1; i < 5; i++) //Index starts from 1, not from 0
System.out.print(rs.getString(i) + ", ");
System.out.println();
} while(rs.next());
I remember there were third party libraries that supported the functionality you are looking for, they are pretty expensive.
In general, yes, you will have to refetch. However, you can be smart about it: you can intelligently partition your query to fetch only a few hundred rows
e.g. by using two tables, one for production data, other for new
data, and sometimes merging them (you can use in-memory tables for the new data, and you can create cross-table views, if needed, although not neccessary)
you can create an autoincrement index, and fetch only the latest rows,
or you can use ROWNUM in Oracle, SELECT TOP in SQL Server, LIMIT in MySQL, etc.
and of course, you can implement a custom database driver :-)
In general, if you fetch more than a few hundred rows regularly, something is wrong, and maybe you should reconsider your client side interface and implementation.
A ResultSet that is TYPE_SCROLL_INSENSITIVE is not meant to detect updates to the underlying database (that is what the insensitive means here). If you want the ResultSet to detect changes, then you should use TYPE_SCROLL_SENSITIVE.
However as the changes usually occur in a different transaction, I believe most databases are unable to offer TYPE_SCROLL_SENSITIVE, and if they can then they probably only allow you to see changes to the data of the selected rows, but not detect additional (or removed) rows.
If you try to use TYPE_SCROLL_SENSITIVE, you might want to check if your database actually supports that type (eg using DatabaseMetaData.supportsResultSetType(int)). Or by checking if the created ResultSet is actually of the specified type (the JDBC spec allows drivers to 'downgrade' type and/or concurrency if it isn't supported).
You might also want to check DatabaseMetaData.ownInsertsAreVisible(int) and related methods for your specific database and driver.
Try this:
String query = "Select EnrNo, Name, Gender, DOB From Student";
try {
conn = DriverManager.getConnection(DB_URL, USER, PASS);
// change this to reflect your specific situation
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String EnrNo = rs.getString("EnrNo");
String name = rs.getString("Name");
String gender = rs.getString("Gender");
String date = rs.getString("DOB");
System.out.println(EnrNo + "\t" + name + "\t" + gender + "\t" + date);
}
} catch (SQLException e) {
e.printStackTrace();
}
// make sure you add these as your class variables:
Connection conn = null;
Statement stmt = null;
Related
Good day, just wanna ask. I have a Java GUI where I want to add multiple data from SQL server to my Jtable. The flow here is that I would want to use the text field as search field where I will add the info for searching and use the Jbutton to perform the search action then it will give/show me the data to my Jtable. Actually the code is running however some of the data like the 1st data added to my SQL serve and from data id 7 and and up are not showing. How would I fix this and show multiple data with same order ID form SQL server?
Thank you!!
try {
String query = "select * from `sales_product` where order_id = ?";
pst = con.prepareStatement(query);
pst.setString(1, txsearch.getText());
ResultSet rs = pst.executeQuery();
if(rs.next()) {
while(rs.next()) {
String prodname = rs.getString("prodname");
String price = String.valueOf(rs.getInt("price"));
String qty = String.valueOf(rs.getInt("qty"));
String total = String.valueOf(rs.getInt("total"));
model = (DefaultTableModel) datatable.getModel();
model.addRow(new Object[]{
prodname,
price,
qty,
total
});
int sum = 0;
for (int a = 0; a < datatable.getRowCount(); a++) {
sum = sum + Integer.parseInt(datatable.getValueAt(a, 3).toString());
}
Ltotal.setText(Integer.toString(sum));
}
}
else {
JOptionPane.showMessageDialog(this, "No order found!");
txsearch.setText("");
}
} catch (SQLException ex) {
Logger.getLogger(milktea.class.getName()).log(Level.SEVERE, null, ex);
}
}
if(rs.next()) {
while(rs.next()) {
No need for the if (rs.next()) statement. That is causing you to skip the first row of data in the ResultSet.
All you need is the while (rs.next()) statement to create the loop to read all rows in the ResultSet.
The database has the same format of date. Query is working fine in Oracle DB. In java the resultset is not empty. Cannot think of the possible reason for this problem. Please help.
try {
Class.forName(driverClass);
Connection cn=null;
cn=DriverManager.getConnection(url,username,password);
Scanner sc=new Scanner(System.in);
System.out.print("Enter Ship date in yyyy-mon-dd format: ");
String str=sc.next();
System.out.println(str);
//select PO_NUMBER from PURCHASE_ORDER where SHIPDATE=TO_DATE('2021-JAN-25','YYYY-MON-
DD');
String sql = "select PO_NUMBER from PURCHASE_ORDER where
SHIPDATE=TO_DATE('"+str+"','YYYY-MON-DD')";
System.out.println("Query exec");
Statement stmt = cn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
if(rs.next())
System.out.println("Purchase Order Shipped on "+ str+" are: ");
else
System.out.println("empty rs");
while(rs.next()) {
System.out.println(rs.getInt(1));
}
cn.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
OUTPUT : Enter Ship date in yyyy-mon-dd format: 2021-JAN-25
2021-JAN-25
Query exec
Purchase Order Shipped on 2021-JAN-25 are:
The answer by Elliott Frisch is spot-on. This answer provides you with some recommended practices.
Use PreparedStatement instead of Statement in case of a parametrized query in order to prevent SQL Injection.
Use try-with-resources so that the resources get closed automatically.
Using e.printStackTrace() is bad practices because the stack-trace is of no use to the end-user. The general rule is: If your method can not handle the exception (i.e. can not do something to recover from the exceptional state), it should not catch the exception and should declare throws with the method signature. This will ensure that the calling method will get an opportunity to handle the exception in the desired manner.
As per the documentation of ResultSet#next, it Moves the cursor forward one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.
It means that after making a call to ResultSet#next, you have to grab the value(s) from the ResultSet before making another call to ResultSet#next, which you have missed and therefore the values fetched by the ResultSet from the DB, on the first call to ResultSet#next, is getting wasted.
Either you handle it in the way, Elliott Frisch has suggested or you can do it in an alternative way shown in the following code.
Based on these recommendations, your code should be as follows:
Scanner sc = new Scanner(System.in);
System.out.print("Enter Ship date in yyyy-mon-dd format: ");
String str = sc.next();
String query = "select PO_NUMBER from PURCHASE_ORDER where SHIPDATE = TO_DATE(?, 'YYYY-MON-DD')";
try (Connection cn = DriverManager.getConnection(url,username,password);
PreparedStatement stmt = cn.prepareStatement(query)) {
stmt.setString(1, str);
ResultSet rs = stmt.executeQuery(query);
if(rs.next()) {
System.out.println("Purchase Order Shipped on "+ str+" are: ");
System.out.println(rs.getInt(1));
while(rs.next()) {
System.out.println(rs.getInt(1));
}
} else {
System.out.println("empty rs");
}
}
Your current while loop discards the first row (which is presumably the only row). Easiest solution I can see would be to change it to a do while in the if. Something like,
if(rs.next()) {
System.out.println("Purchase Order Shipped on " + str + " are: ");
do {
System.out.println(rs.getInt(1));
} while(rs.next());
} else {
System.out.println("empty rs");
}
i have two tables WorkSkillsPlanning(WSP) and TrainingAchieved(TA). WSP hold a list of planed training and targeted number of people to be trained e.g. ISOO:90001 10 people while TA holds the actual number of people trained as well as the actual course done. Since WSP and TA are dynamic in the sense that the data they hold is not static neither is known as training plans can change is it possible to run an intersect query on these table to find similarities i.e a course in WSP which has actually be done and recorded in TA. Store the results of the intersect query in an array e.g. MyArrayList{ISO,COMMUNICATION) these being values present in both table and use MyArrayList values to run count queries on TA to establish the number of people who would have done the course i.e ISO and COMMUNICATION and use the resultant to subtract from WSP (ISO,COMMUNICATION).
here is an example, first part
"Select QUALIFICATIONGROUP from APP.WSP intersect select COURSEBOOKED from APP.BOOKCOURSE"
which results in ISO and COMMUNICATION which i want to store in an ARRAY or variable.
second part
select count(COURSEBOOKED) from APP.BOOKCOURSE where COURSEBOOKED = Variable1
rs.getString(Count(COURSEBOOKED))
value returned == 5
re do the process again for COMMUNICATION and any other course in the array, of which after use the values returned from the count query to subtract to subtract WSP total minus TA total.
I hope this makes sense
as requested the first query is
private void updateTable(){
String sql = "Select QUALIFICATIONGROUP from APP.WSP intersect select COURSEBOOKED from APP.BOOKCOURSE";
try (Connection con = DriverManager.getConnection("jdbc:derby:MTD","herbert","elsie1*#");
PreparedStatement pst = con.prepareStatement(sql);){
ResultSet rs = pst.executeQuery();
//while (rs.next()){
jTable1.setModel(DbUtils.resultSetToTableModel(rs));
//}
}
catch (Exception ex) {
JOptionPane.showMessageDialog(null, ex);
}
this will give me data that is in WSP that is also present in AT and display it in a table.
the second query is now supposed to take the first value of Row one in the table and pass it to the second query as below
public void tableOne() throws Exception{
String search = "value of first row from the query ontop";
PreparedStatement pst = null;
ResultSet rs = null;
try{
Connection con = DriverManager.getConnection("jdbc:derby:MTD","herbert","elsie1*#");
String sql = "SELECT COUNT(COURSEBOOKED) from APP.BOOKCOURSE where COURSE BOOKED = '"+search+"'";
pst = con.prepareStatement(sql);
rs = pst.executeQuery();
while(rs.next()){
sum = rs.getString("COUNT(COURSEBOOKED)");
txtSum.setText(sum);
}
}
catch(Exception e){
JOptionPane.showMessageDialog(this, e);
}
}
This query is supposed to run as many times as the rows produced by the first query.
this query select all the data in WSP table.
public void tableTwo() throws Exception{
String sql = "select * from APP.WSP";
try(Connection con = DriverManager.getConnection("jdbc:derby:MTD","herbert","elsie1*#");
PreparedStatement pst = con.prepareStatement(sql);){
ResultSet rs = pst.executeQuery();
while(rs.next()){
jTable1.setModel(DbUtils.resultSetToTableModel(rs));
search= rs.getString("QUALIFICATIONGROUP"); //sets the search string for tableOne();
next = rs.getInt("TOTALTRAININGPLANNED");
System.out.println(search);
System.out.println("");
System.out.println(next);
}
}
catch(SQLException e){
JOptionPane.showMessageDialog(this, e);
}
}
finally the count values from the second query are used to subtract the values
from the variable next (next= rs.getInt("TOTALTRAININGPLANNED");) generated from the last query and the finally value of next = rs.getInt("TOTALTRAININGPLANNED") - value of the second Count query are stored in an variable which will be used to reveal wether planned training and actual training are equal or different.
I hope i have clarified issues
I have a database with a AUTO_INCREMENTING id column and a name column. If I delete a row from the data I would like to update all of the other rows id so the sequence is right again, I am very lost please help me.
I tried this:
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT COUNT(id) FROM " + table_name_products);
int count = 0;
while(rs.next()){
count = rs.getInt("COUNT(id)");
}
stmt = conn.createStatement();
for(int i = 1; i <= count; i++){
if(i > id){
stmt.addBatch("UPDATE " + table_name_products + " SET id = "+ i-- +" WHERE id = "+ i +";");
}
}
I don't think this is possible.
I think the only solution would be to cache all rows after the one you are deleting some place, delete those rows, then add the cached rows to the table again.
There might be database management command to do this, but you wouldn't want to be doing it after every delete.
What about a database trigger. Have a look here.
A database trigger is procedural code that is automatically executed
in response to certain events on a particular table or view in a
database.
I would like to get an integer saved in my MySql DB into an Integer in Java. I have a Table, that includes PlayerName and Level. I would like to get The Level (Integer) From a Specific Player. And then Add Integer "Value" to it. Then put it back in the DB. My Code up to now is:
public void addinputPData(String loc, int value, Player player, String playername){
//add input Player Data
try{
logm("Putting Kill Death Int Data into " +player.getName() + "'s Profile!");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/WebCom", "root", "MyPW");
int ovalue = -1;
Statement stmt = (Statement) con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT "+loc+" FROM PlayerData WHERE PlayerName='"+playername+"'");
if(rs.next()){
ovalue= rs.getInt(loc);
}
if(ovalue == -1){
logm("Error Occured");
}
int nvalue = value + ovalue;
String insert = "UPDATE PlayerData SET "+ loc + "='" + nvalue + "' WHERE PlayerName='" + playername + "'";
stmt.executeUpdate(insert);
con.close();
}catch(Exception e){
logm("Could Not Send Data To MYSQL DATABASE SERVER s: "+ e.getMessage());
}
}
I don't know why this won't work, Is there anything obvious that i am missing? Thank you in advance.
So first what you must understand is that when you won't use parametrized statements, there is big danger of SQL Injection. So your code is very dirty written.
So anyway, use PreparedStatement with parametrized SQL statements for much more better performace. Now rewrite your code like this:
final String SELECT_QUERY = "SELECT level FROM PlayerData WHERE PlayerName = ?";
final String UPDATE_QUERY = "UPDATE PlayerData SET level = ? WHERE PlayerName = ?";
public boolean dataMethod(String playerName) {
Connection con = null;
PreparedStatement ps = null;
PreparedStatement ps1 = null;
ResultSet rs = null;
int dataLevel = 0;
try {
// getConnection etc...
ps = con.prepareStatement(SELECT_QUERY);
ps.setString(1, playerName) // first param is order of ? param, starts with 1(not 0)
rs = ps.executeQuery();
while (rs.next()) {
dataLevel = rs.getInt();
}
if (dataLevel > 0) {
ps1 = con.prepareStatement(UPDATE_QUERY);
ps1.setInt(1, dataLevel);
ps1.setString(2, playerName);
ps1.executeUpdate();
}
return true;
}
catch (SQLExcetion ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
finally {
if (con != null) {
con.close();
}
}
}
Step by step, first init your statement, sets parameters if you have then when you use select, you will retrieve data in ResultSet that is table of data generated with query. imlicitly cursor in ResultSet is position before first row so you have to use next() method to go on current row and with the help of getter method you add data from ResultSet to your variable. Then you check if it's correct, if do, init second statement and execute it. And that's all.
But you should consider when you use more that 1 operation, sets autoCommit on false and all operations will do in one Transaction, because implicitly in JDBC is one operation = one transaction. And second, you should consider to use SQL stored procedures for add any data, update data or delete. It's more safer yet and less code. So let database working when it able to do it and also it's faster of course.
At the last, really you should think about this approach and makes your code more safer, faster and cleaner. Not have look on simplicity but on efficiency, compability and security.
More about SQL Injection
And when you decided right to use stored procedure, you can use it like this:
CREATE OR REPLACE PROCEDURE SOME_NAME(VARCHAR v_name PlayerData.name%type)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
// body
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
So now you have to create String for call procedure.
final String CALL_SOMENAME = "{call SOME_NAME(?)}";
Then intead of PreparedStatement you have to use CallableStatement that is interface used to execute SQL stored procedures.
cs.prepareCall(CALL_SOMENAME); // Creates a cs object for calling db stored procedures
cs.setString(1, playerName);
cs.execute();
I don't know why many people searching the easiest way to do something and don't look at performance and readability of code.
Regards
In the UPDATE statement, you're inserting the value for the "loc" column as a string (there are single quotes around the value). If the database column is an integer, then this could be causing a problem.
Tip: JDBC provides a class called PreparedStatement. This class allow you to build SQL queries safely. It makes sure that all user input is properly escaped in order to avoid security vulnerabilities.
PreparedStatement ps = con.prepareStatement("UPDATE PlayerData SET " + loc + " = ? WHERE PlayerName = ?");
ps.setInt(1, nvalue);
ps.setString(2, playername);
ps.execute();