Resultset skips columns - java

I am developing a software in Java, what I am doing is searching a value in full sqlite database (55 Columns and 1000 rows) and updating it.
I can find that value in the database but when I am try to update it I want to skip columns which have only NULL values. Using ResultSet it automatically skips other columns which have non-null values.
How can I check if ResultSet is not skipping the columns, finding the desired column and updating that value?
What I tried is:
ArrayList<String> arr = new ArrayList<String>() ;
rs = statement.executeQuery(); // that is the select statement
//Select * FROM table_name WHERE column1 like %VALUE%' OR column2 like %VALUE% and other columns like this too...
List<String> cols = Arrays.asList(getColLabels());
// I am getting Column Labels from ResultSetMetaData and it works fine
while(rs.next()){
for(String column: cols){
String value;
if(rs.getBoolean(column)){
//That is the problematic area, if ResultSet finds a column with full of NULL values it skips to next column.
// But other columns it skips too , which have not null Values and after that ResultSet does not find a proper column.
if((value = rs.getObject(column).toString()).matches(".*"+searchedVal+".*") ){
//searchedVal is searched value
arr.add("UPDATE Table_Name SET "+column+" ='"+newValue+"' WHERE "+ column+" ='" +value+"';" );
// then send array in another function to update to database
break;
}
}
}
}
Thank you for your help.

Please try to solve the problematic area with the data tier(SQL command), not the business trie(java code).
You want to have rows which all of the columns must be non null? so simply add more condition clauses(not null) to your sql command
something like:
Select * FROM table_name WHERE column1 like %VALUE%' OR column2 like %VALUE% and column_n like %VALUE% and (column1 not null and column2 not null and column_n not null)

I found the answer,
rs.getBoolean does not work with different type of column types, so I changed getObject function.
Working code is:
ArrayList<String> arr = new ArrayList<String>() ;
rs = statement.executeQuery(); // that is the select statement
//Select * FROM table_name WHERE column1 like %VALUE%' OR column2 like %VALUE% and other columns like this too...
List<String> cols = Arrays.asList(getColLabels());
// I am getting Column Labels from ResultSetMetaData and it works fine
while(rs.next()){
for(String column: cols){
String value;
if(rs.getObject(column) != null){
if((value = rs.getObject(column).toString()).matches(".*"+searchedVal+".*") ){
//searchedVal is searched value
arr.add("UPDATE Table_Name SET "+column+" ='"+newValue+"' WHERE "+ column+" ='" +value+"';" );
// then send array in another function to update to database
break;
}
}
}
}

Related

Java Sql 'select sum' giving incorrect value

I'm not experienced in java and I'm stuck with this problem and couldn't figure out the cause for weeks. I have a sql query that selects, counts and groups by the column "name". Next in the 'while(rs.next())' I am trying to select the sum of two other columns, a column named "kolicina" and a column named "cena" here is the code of that method:
public ArrayList<Artikli> getSum(String date){
ArrayList<Artikli> list = new ArrayList<Artikli>();
String query = "select name, count(name) as count from izvestaj where dateZat = '"+date+"' group by name";
try {
rs = st.executeQuery(query);
while(rs.next()){
Artikli art = new Artikli();
art.name = rs.getString("name");
String q = "select sum(kolicina) as total from izvestaj where name = '"+art.name+"' and dateZat = '"+date+"'";
rs2 = st2.executeQuery(q);
while(rs2.next()){
art.kolicina = rs2.getInt("total");
}
String q1 = "select sum(cena) as total1 from izvestaj where name = '"+art.name+"' and dateZat = '"+date+"'";
rs3 = st3.executeQuery(q1);
while(rs3.next()){
art.cena = rs3.getInt("total1")/rs.getInt("count");
}
list.add(art);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
The problem is that the second query returns the correct sum of the column kolicina, but the third query returns result set with the sum multiplied by the count number (from the first query... That's why i divide it with the count in the end), but still, it doesn't actually return the correct ammount. Column "cena" is actually price in english, so it seems that it's making some average price and than multiplies it with the number of records... I double-checked the insert queries and they are fine, so I am sure i insert the correct values. Any help appreciated.
Instead of issuing two distinct queries per name, just issue
select name,
sum(kolicina) as total,
sum(cena) as total1
from izvestaj
where name is not null and
dateZat = ?
group by name
(re. the questino mark : read up on PreparedStatements and how to set up parameterized queries in order to protect yourself properly against SQL injections.)
(I think you can even skip the first query as its results will also be contained in this query's results.)

Prepared statement with set null in query doesn't return any record

I use prepared statements to read/write data in my DB (SQLite). In my table INVENTORY, there are records which have null value in the column paleta (the column is defined as VARCHAR in the table). I want to select these records and I tried:
sq = "SELECT * FROM INVENTORY WHERE paleta = ? AND product = ? AND lot = ?";
//...
stm = c.prepareStatement(sq);
stm.setNull(1, java.sql.Types.VARCHAR);
stm.setString(2, "theIdOftheProduct");
stm.setString(3, "theLotOftheProduct");
ResultSet rs = stm.executeQuery();
The above query doesn't return anything.. I removed the paleta = ? and I get the records I want.. How can I define the query like SELECT * FROM INVENTORY WHERE paleta is null etc.. using the query parameters?
What you are trying to do is equivalent to writing SELECT * FROM INVENTORY WHERE paleta = NULL ..., which doesn't work.
Since you are essentially searching for rows having a constant value in the paleta column (which happens to be NULL), you can eliminate the first query parameter and explicitly check for null:
sq = "SELECT * FROM INVENTORY WHERE paleta IS NULL AND product = ? AND lot = ?";
stm = c.prepareStatement(sq);
stm.setString(1, "theIdOftheProduct");
stm.setString(2, "theLotOftheProduct");
I found my answer in https://stackoverflow.com/a/4215618/1052284
You'll have to decide upon an unused value. I simply kept it at '' since I don't have empty values.
sq = "SELECT * FROM INVENTORY WHERE IFNULL(paleta, '') = ? AND product = ? AND lot = ?";
//...
stm = c.prepareStatement(sq);
stm.setString(1, ""); // '' for NULL, otherwise a specific value
stm.setString(2, "theIdOftheProduct");
stm.setString(3, "theLotOftheProduct");
But beware if you many queries, it's VERY slow. I clock in at about 4000 times slower, on average, than queries without IFNULL. ~50ms instead of microseconds.

Get inserted row to Oracle with java

I am building a java program to insert data to my oracle database.
My problem is that I need to insert into two tables, and to reach unique rows I use in TABLE_A triggers for id before insert get next val in a sequence.
But i need the same id for the TABLE_B for connection.
( i cant get getval because what if another user uses the program... )
So I need to reach somehow that when I use executeql(sql) command in return I see what I have submit.
Now I use that I have name and date, so I select the id where name and date is the just inserted.
But its not the best because in one day I can insert more names. So now this will not unique.
like :
insert into table a ( name,date) val ( 'Ryan','2014.01.01')
id here is autoincremented by sequence
than another sql run:
inert into table_b ( id,someval) val ( select id from table_a where
name ='Ryan', date='2014.01.01, 23)
so i need something like:
system.out.println(smtp.executesql(sql).whatIinsertednow())
*than console:* '1 row insered (id,name,date) : ( 1, Ryan, 2014.01.01)
PreparedStatement prepareStatement = connection.prepareStatement("insert...",
new String[] { "your_primary_key_column_name" });
prepareStatement.executeUpdate();
ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
if (null != generatedKeys && generatedKeys.next()) {
Long primaryKey = generatedKeys.getLong(1);
}
I have found the answer this is perfectly works. I can insert from JAVA and its return with the key.
Full version:
CREATE TABLE STUDENTS
(
STUDENT_ID NUMBER NOT NULL PRIMARY KEY,
NAME VARCHAR2 (50 BYTE),
EMAIL VARCHAR2 (50 BYTE),
BIRTH_DATE DATE
);
CREATE SEQUENCE STUDENT_SEQ
START WITH 0
MAXVALUE 9999999999999999999999999999
MINVALUE 0;
And the Java code
String QUERY = "INSERT INTO students "+
" VALUES (student_seq.NEXTVAL,"+
" 'Harry', 'harry#hogwarts.edu', '31-July-1980')";
// load oracle driver
Class.forName("oracle.jdbc.driver.OracleDriver");
// get database connection from connection string
Connection connection = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:sample", "scott", "tiger");
// prepare statement to execute insert query
// note the 2nd argument passed to prepareStatement() method
// pass name of primary key column, in this case student_id is
// generated from sequence
PreparedStatement ps = connection.prepareStatement(QUERY,
new String[] { "student_id" });
// local variable to hold auto generated student id
Long studentId = null;
// execute the insert statement, if success get the primary key value
if (ps.executeUpdate() > 0) {
// getGeneratedKeys() returns result set of keys that were auto
// generated
// in our case student_id column
ResultSet generatedKeys = ps.getGeneratedKeys();
// if resultset has data, get the primary key value
// of last inserted record
if (null != generatedKeys && generatedKeys.next()) {
// voila! we got student id which was generated from sequence
studentId = generatedKeys.getLong(1);
}
}
source : http://viralpatel.net/blogs/oracle-java-jdbc-get-primary-key-insert-sql/
You can accomplish that by using the RETURNING clause in your INSERT statement:
INSERT INTO table_a ( name,date) val ( 'Ryan','2014.01.01') RETURNING id INTO ?

Get all primary keys in a MySQL table using Java

How could I get the names of all primary keys in a MySQL table using Java? Let's say I have a table:
Name │ Phone Number │ verified
─────┼──────────────┼─────────
John │ 871-123-1842 │ 0
Mark │ 912-917-8172 │ 1
Matt │ 182-134-9917 │ 1
Jake │ 971-991-8264 │ 1
I would like to get the values John, Mark, Matt, and Jake from the table.
I know there could be an alternative of just having a list of all of all of the primary keys, and adding to it whenever a new one is added, just I'm looking for something simpler, that will take up less space. I'm looking for something like:
PreparedStatement query = mySqlConnection.prepareStatement("SELECT * FROM `table`");
ResultSet results = query.executeQuery();
List<Object> results = results.getPrimaryKeyValues(); //I don't know what to put here
So, how could I achieve getting an Array, or something that I can turn into an Array, of all of the primary keys inside of a MySQL table using Java?
First off, I suppose you don't know what columns are Primary Keys on your table. The first step would be to get these column names, and then get the values.
To get the column names:
public ArrayList<String> findPrimaryKeyColumnNames(Connection connection,
String catalog, String schema, String table){
/* open the connection*/
...
ArrayList<String> columns = new ArrayList<String>();
DatabaseMetaData dbData = connection.getMetaData();
Resultset result = dbData.getPrimaryKeys(catalog, schema, table);
while (result.next())
columns.add(result.getString("COLUMN_NAME"));
...
/* you should... PROBABLY... close your connection ;) */
return columns;
}
What this method does is it returns an ArrayList containing the names of the columns that are Foreign Keys from the table you put in your parameter.
With this new info, you can easily make a dynamic query that goes like:
String query = "SELECT ";
for(String column : columns) //columns contains the info from the first method
query += column + ", ";
query = query.substring(0, query.length - 2); //you want to get rid of that extra comma
query += "FROM " + tableName;
You can then recover the data from this query and it will only contain your primary keys for a given table.
There is no method like getPrimaryKeyValues().
You need to iterate through the ResultSet to create your own list of values. Something like:
String sql = "Select Name from yourTableNameHere";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery( sql );
List<String> names = new ArrayList<String>();
while (rs.next())
{
names.add( rs.getString(1) );
}
rs.close();
stmt.close();
System.out.println( names );
DatabaseMetaData databaseMetaData = conn.getMetaData();
ResultSet resultSet = databaseMetaData.getPrimaryKeys(null, null , tablename);
while (resultSet.next()) {
String primarykeys= resultSet.getString(4);
System.out.println(primarykeys);
}

Check if number is already in field before concatenating?

I am writing a crawler that scans many urls and then puts all the words found in each webpage into a table. In this same table the ID of the url is stored. If the word is repeated in another page, the ID of the url the word was found on is concatenated with a comma separating them. So if a word appears on multiple pages, all the concatenated ID numbers in the field might look like:
2,3,6,8,9
At the moment, if the number appears multiple times on the same page, the ID number will be added each time the number is found so the URLID field might end up looking like:
2,2,2,4,7,8,8,8,8,8,9,9
Using Java is there a way I get it to check if the number exists in the field already and only add it if it is not already there? I have looked through the api but cannot seem to find a suitable way to do this. Any ideas?
Addition:
public void updateWordTable( String[] array, int urlid ) throws SQLException, IOException {
Statement stat = connection.createStatement();
String wordQuery;
String query;
for (String item : array) {
if(item.matches("[A-Za-z0-9]+")){
wordQuery = "SELECT * FROM word WHERE word = '"+item+"'";
ResultSet rs = stat.executeQuery(wordQuery);
if(!rs.next()){
query = "INSERT INTO word VALUES ('"+item+"',"+urlid+")";
stat.executeUpdate( query );
}
else {
//query = "UPDATE word SET urlid = concat(urlid, ',"+urlid+"') WHERE word = '"+item+"' ";
//query = "UPDATE word SET urlid = CASE WHEN FIND_IN_SET( '"+urlid+"', urlid ) > 0 THEN urlid ELSE CONCAT( urlid, ',', '"+urlid+"' )END WHERE word = '"+item+"' ";
String query2 = "UPDATE word SET urlid = CASE WHEN FIND_IN_SET( ?, urlid ) > 0 THEN urlid ELSE CONCAT( urlid, ',', ? )END WHERE word = ? ";
PreparedStatement pst = connection.prepareStatement( query2 );
pst.setLong( 1, urlid );
pst.setLong( 2, urlid );
pst.setString( 3, item);
int result = pst.executeUpdate();
//stat.executeUpdate( query2 );
}
}
}
stat.close();
}
... is there a way I get it to check if the number exists in the field already and only add it if it is not already there?
You can do it using JAVA, but leave that checking to MySQL as it has such search features.
Using MySQL, you can use FIND_IN_SET function on comma separated values in the column. This will solve your problem to not reprocess in JAVA to find if such id exists.
select
FIND_IN_SET( value_to_find, column_with_cs_values ) > 0 as bool_matched
from table_name
Add where condition and others if any required.
And in the JAVA code you can just read the resultset for getBoolean.
boolean idMatched = rs.getBoolean( "bool_matched" );
if( idMatched ) {
// dont update table
}
else {
// update table
}
Alternatively, you can directly update the table column.
Example:
UPDATE table_name
SET column_name_with_cs_values =
CASE WHEN FIND_IN_SET( value_to_find,
column_name_with_cs_values
) > 0 THEN column_name_with_cs_values
ELSE CONCAT( column_name_with_cs_values, ',', value_to_find )
END
-- add where etc here
;
In JAVA, you can use the above query like the following with PreparedStatement.
String query = "UPDATE word
SET urlid = CASE WHEN FIND_IN_SET( ?, urlid ) > 0 THEN urlid
ELSE CONCAT( urlid, ',', ? )
END
WHERE word = ? ";
PreparedStatement pst = con.prepareStatement( query );
pst.setString( 1, urlid );
pst.setString( 2, urlid );
pst.setString( 3, item);
int result = pst.executeUpdate();
I guess your values are stored in mysql because your question is tagged mysql. In java you can request your database with a select and check if the value is already inserted.
Or if your are not in the mysql world but only java, use a structure that give you the guartantee of unicity as a Set instead of a List.
The easiest way would be just to load those values into Set. Set will take case to have unique elements only.
The idea is whenever you store your IDs this structure should keep uniqueness. Set is the best one when we talk about Java.
If you would like to have some mechanism on database to provide uniqueness that's another story.
That's just the general tip.
If your field is a String then you can use regex
boolean exists = s.matches("(^|.*,)"+ n + "($|,.*)");
Step1: Store new url_id in temp variable.
Step2: now check this url_id existence in your table by select statement, you can do this by below query, suppose new url_id is 7:
SELECT COUNT(url_id) FROM mytable WHERE (url_id LIKE '7,%' OR url_id LIKE '%,7' OR url_id LIKE '%,7,%');
Step3: if you get any count from above query then leave it, otherwise add in your table.
I was having a project coded in pl/sql that comes across the case like yours. My variable is stored in a String and I have to check if the number was already in the String variable. I did it from using
IF instr('2,3,6,8,9,' '2,') <= 0 THEN
' Code to append the '2,'
End If
For JAVA there is something similar to instr method, String.indexOf()
http://www.tutorialspoint.com/java/java_string_indexof.htm
However note that it will return 0 if it's the first character, so probably it will be < 0
String a = "2,3,6,8,9,";
If a.indexOf(ID + ",") < 0 { // -1 equivalent to NOT FOUND
// code to append ID + ",";
}
Note I need to check on ID + "," reason is e.g.
ID = "2";
a = "20,3,6,8,9,";
It will return me 0 due to the 20. Therefore I'm using comma as a delimiter for every number found.
So after I finish append variable a, I would remove the last comma by
a = a.substring(0, a.length()-1); // this will remove the last ","
System.out.println(a); // the output should be - 2,3,6,8,9
This is using Java if your variable is stored in Java.

Categories