JDBC : Converting resultSet to String based on user input within scope [duplicate] - java

This question already has an answer here:
Getting the data type of a ResultSet column [duplicate]
(1 answer)
Closed 3 years ago.
I was wondering what is the best practice to convert resultSet to String based on user input. I came across a problem which to convert user input from another class.
For an example , i have 2 java class.
query.java & result.java
For result.java. User will key in within the scope to get their desired output. Lets say that there are 2 columns in the database 'name' & 'age'
From my point of view, to make the code neater , i have to classify into 2 different class to make it oop.
result.java
// User will key in datatype as either age or name
public ArrayList<String> result(String datatype){
..
ArrayList<String> data = new ArrayList<String> data;
data = new query.queryArr(datatype);
for(..)..
..
//Database column is
return data
}
At first, i was confused how i can get this method to work
Query.java
public String ArrayList<String> queryArr(String userinput){
ArrayList<String> result = new ArrayList<String>();
..
..
while (rs.next()) {
// The main probelm is, if i return it as age. it will prompt error as the datatype declared in database is integer.
//if it return as integer, this will crash the application as the return type is not the right datatype as it is declared as integer
result.add(rs.getString(userinput));
}
return result;
UPDATE
After realising that the return type can be either integer or string.
I have come to conclusion that the return type should be an object.
public ArrayList<String> recordsQuery(String getRecords){
ArrayList<String> result = new ArrayList<String>();
try{
..
..
ResultSet rs = stmt.executeQuery("select "+ getRecords +" from bills");
while (rs.next()) {
result.add(rs.getObject(1).toString());
}
return result;
}
Do let me know if this is not the best practice to retrieve my data.

JDBC requires a number of default conversions (see table B.6 in the JDBC 4.3 specification). Specifically for getString it lists the following supported JDBC types:
TINYINT, SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
NUMERIC, BIT, BOOLEAN, CHAR, VARCHAR, LONGVARCHAR, BINARY, VARBINARY,
LONVARBINARY, DATE, TIME, TIMESTAMP, DATALINK, NCHAR, NVARCHAR,
LONGNVARCHAR
So, calling ResultSet.getString on an INTEGER column should work just fine and the driver should take care of this for you.
In other words, you should be able to unconditionally use
while (rs.next()) {
result.add(rs.getString(1))
}
If this doesn't work, then you should report a bug to the vendor that created this JDBC driver as the implementation doesn't fulfill the requirements of the JDBC specification.

you can see at java doc result set page
Object getObject(int columnIndex)
throws SQLException
List<String> result = new ArrayList<>();
while (rs.next()) {
Object obj = rs.getObject(1);
if(obj instanceOf String)
result.add(rs.getString(1));
else if(obj instanceOf Integer)
// doing something
}
return result;

Related

Having trouble reading String from MySQL table to Eclipse

I have a project of coupons but I have an issue when trying to read a coupon to Eclipse. I have a table of categories which are connected to my coupons table in row "CATEGORY_ID" which is an int. when using add Method I convert my ENUM to int in order to add it to CATEGORY_ID with no problem.
my issue is when trying to read it, I try and convert it to STRING to get a text value, however, I get an exception.
here is my code:
ENUM CLASS:
public enum Category {
FOOD(1), ELECTRICITY(2), RESTAURANT(3), VACATION(4), HOTEL(5);
private Category(final int cat) {
this.cat = cat;
}
private int cat;
public int getIDX() {
return cat;
}
private Category(String cat1) {
this.cat1 = cat1;
}
private String cat1;
public String getName() {
return cat1;
}
}
A Method to add coupon to table COUPONS:
// sql = "INSERT INTO `couponsystem`.`coupons` (`COMPANY_ID`,`CATEGORY_ID`,`TITLE`, `DESCRIPTION`,
`START_DATE`, `END_DATE`, `AMOUNT`, `PRICE`, `IMAGE`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";
#Override
public void addCoupon(Coupon coupon) throws SQLException {
Connection connection = pool.getConnection();
try {
PreparedStatement statement = connection.prepareStatement(ADD_COUPON);
statement.setInt(1, coupon.getCompanyID());
statement.setInt(2, coupon.getCategory().getIDX());
statement.setString(3, coupon.getTitle());
statement.setString(4, coupon.getDescription());
statement.setDate(5, (Date) coupon.getStartDate());
statement.setDate(6, (Date) coupon.getEndDate());
statement.setInt(7, coupon.getAmount());
statement.setDouble(8, coupon.getPrice());
statement.setString(9, coupon.getImage());
statement.execute();
} finally {
pool.restoreConnection(connection);
}
}
Method to get coupon:
// GET_ONE_COUPON = "SELECT * FROM `couponsystem`.`coupons` WHERE (`id` = ?);";
#Override
public Coupon getOneCoupon(int couponID) throws SQLException {
Connection connection = pool.getConnection();
Coupon result = null;
List<Category> cats = new ArrayList<Category>(EnumSet.allOf(Category.class));
try {
PreparedStatement statement = connection.prepareStatement(GET_ONE_COUPON);
statement.setInt(1, couponID);
ResultSet resultSet = statement.executeQuery();
resultSet.next();
result = new Coupon(resultSet.getInt(1), resultSet.getInt(2), Category.valueOf(resultSet.getString(3)),
resultSet.getString(4), resultSet.getString(5), resultSet.getDate(6), resultSet.getDate(7),
resultSet.getInt(8), resultSet.getDouble(9), resultSet.getString(10));
} finally {
pool.restoreConnection(connection);
}
return result;
on column index (3) I try a and convert ENUM to string to get a text value, here is where I get an exception.
EXCEPTION:
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant coupon.beans.Category.5
at java.base/java.lang.Enum.valueOf(Enum.java:240)
at coupon.beans.Category.valueOf(Category.java:1)
at coupon.dbdao.CouponsDBDAO.getOneCoupon(CouponsDBDAO.java:125)
at coupon.Program.main(Program.java:65)
Hope I am clear with my question. I have no issue adding any more information.
valueOf expects a string that corresponds to the name of the enum element, like "FOOD" but it looks like you pass a number. If you want to pass the id (number) from your enum you need a method to translate between the number and the enum element. Something like this
//in the enum Category
public static Category categoryFor(int id) {
switch (id) {
case 1:
return FOOD;
case 2:
return ELECTRICITY;
//... more case
default:
return HOTEL;
}
}
and then call it like
Category.categoryFor(resultSet.getInt(2))
or you need to store the actual name of the element in your table.
Also you shouldn't use *, "SELECT * ...", in your query but a list of column names so it is clear what column you map in your java code, "SELECT COMPANY_ID, CATEGORY_ID,TITLE,..."
As I understood correctly you're storing the category in your coupon as an enum constant in your code model. While storing it to the database you're mapping it to an integer value with the methods provided by you.
The culprit is in the Category.valueOf(resultSet.getString(3)) method/ part. The Enum.valueOf method is a default method on enums provided by Java and it's working with a String as a parameter - probably therefore you're also using resultSet.getString(3) instead of resultSet.getInt(3) which would have been more intuitive.
From the JavaDoc (which you can find here) it says:
... The name must match exactly an identifier used to declare an enum
constant in this type. (Extraneous whitespace characters are not
permitted.) ...
This means for to get the valueOf method working you need to call it exactly with one of the following values as its arguments: FOOD, ELECTRICITY, RESTAURANT, VACATION, HOTEL. Calling it with the int values like 1, 2, ... or 5 will lead to the IllegalArgumentException you face.
There a two solutions to fix the problem:
Either change your database model to store the enum values/ constants as strings in the table by calling the toString method on the category value before the insert into the database (then your code reading the coupons from the database can stay unchanged).
Or you need to provide your own custom implementation of the "valueOf" method - e.g. findCategoryById - which will work with integer values as its arguments. By writing your own findCategoryById method your code inserting the coupons into the database can remain unchanged.
To implement your own findCategoryById the signature of the method in the Category enum should look like:
public static Category findCategoryById(int index)
Then you can iterate through all available constants by Category.values() and compare the cat with the argument passed to the method and return the matching value based on it.
In case none matches you can simply return null or also throw an IllegalArgumentException. The latter one I'd personally prefer since it follows the "fail fast" approach and can avoid nasty and time consuming search for bugs.
Note: Enums in Java also have an auto generated/ auto assigned ordinal. You can simply request it by calling the ordinal method on a value of your enum. In your case the ordinals are matching the self assigned cat values, so that you could make use of them, instead of maintaining the cat attributes yourself.
When working with the ordinals it's worth mentioning that the order in which you specify your constants in the enum matters! When you change the order of the constants so the ordinals will. Therefore you also need to be careful when working with ordinals. Therefore you might prefer sticking with your current approach (which is not bad at all and widely used), since it avoids the ordering problems ordinals have.

SQL how to use prepareStatement update specify fields with IsNull for int and double?

I would like to use prepareStatement to update the table. But the input may be null value. By using IsNull, it can only apply to varchar, how about int, double?
I will receive a json object(only the fields need to be update), eg:
{ {
price: 1.56 OR name: "aa", OR ...
} age:10
}
For the int and double, if the value didn't set, when I get the value, it will return 0, how can I set it to null when the user didn't pass in to me?
My class :
private String name;
private int age;
private double price;
//public get & set method
My java:
strQuery = "UPDATE table SET name=IsNull(?, name), age=IsNull(?, age), price=IsNull(?, age) WHERE id= ?";
stmt = (PreparedStatement) conn.prepareStatement(strQuery);
stmt.setString(1, obj.getName()); //string
stmt.setString(2, obj.getAge()); //int
stmt.setString(3, obj.getPrice()); //double
stmt.setString(4, id);
My question:
how to catch the json input, if the field(int/double) is not available then set it to null?
I tried to use Double instead of double, it's work, but I'm not sure this is the good way or not. (I'm a complete novice)
OR any other best way to do what I want to do?
You can compare the objects while setting parameters
stmt.setInt(2, obj.getAge() != 0 ? obj.getAge() : null);
stmt.setDouble(3, obj.getPrice() != 0 ? obj.getPrice() : null);
Now, as you stated using Double it works because class objects are by default assigned as null during initialization. However, primitive types gets assigned default values. e.g., int-0, double-0.0, bool-false etc. You can check more on it. Either approach works using wrapper classes or comparison while setting parameters. But the better would be comparison.

how to get Set data type from mysql to java

So here is my question. I create a table which contains a SET data type column in mysql DB.
I want to get the values of the of this (SET) column.
I have done all the connection configurations and everything is working well on my code.
How to get the Set dataType with resultSet in Set java object????
I've tried this.
Java bean code
public class Valeur {
private Long id;
private Set categoriesValues = new HashSet();
\\getters and setters for the id and the categoriesValues
}
ReultSet Code
private static Valeur map(ResultSet resultSet) throws SQLException {
Valeur valeur = new Valeur();
valeur.setId(resultSet.getLong("id"));
valeur.setCategoriesValues(resultSet.getString("categoriesValues"));
return valeur;
}
ResultSet is working for the id but not for the Set type.
Thanks
According to https://dev.mysql.com/doc/connector-j/en/connector-j-reference-type-conversions.html mysql set columns are mapped to Java strings.
Seems that you need to split the returned value yourself to turn it into a Java set.
In your example (untested):
String values = resultSet.getString("categoriesValues");
HashSet<String> valuesSet = new HashSet<>();
Collections.addAll(valuesSet , values.split(","));
valuer.setCategoriesValues(valuesSet );
Since it's not represented in java.sql.Types I'm guessing it's a little used, custom type that's not supported in many RDBMS'
That being said, to retrieve the value it's likely either:
ResultSet.getArray(...)
Or
ResultSet.getObject(...)
To get the object. I'm guessing you'll have to pack it into a java.util.Set manually (or maybe getObject() returns a java.util.Set?)

Resultset's getObject() method - how to use it properly?

I make a database query and store Account objects in the ResultSet. Here is the code:
try {
ResultSet rs = queryDatabase();
int i=0;
while (rs.next()) {
Account account= rs.getObject(i, Account); //ERROR
accounts.add(account);
i++;
}
} catch (Exception e) {
}
This code returns 3 objects and stores them in the rs. Then I want to get those objects in the ResultSet and put them into an ArrayList as you see in the code. But it gives an error in the specified line saying that ; expected. How can I use getObject method properly?
ResultSet.getObject (and the other getXxx methods) will retrieve the data from the current row of the ResultSet and starts in index 1. You have set your i variable with 0 value.
Just change this
int i=0;
To
int i=1;
Also, getObject needs a single param, but you're incorrectly sending two:
Account account= rs.getObject(i, Account);
Probably you were trying to use ResultSet#getObject(int, Class) (available from Java 7), but you have to take into account that your Account class can't be magically converted from a database column to an instance of this object.
Looks like it would be better to review JDBC trial first, then retry to solve your problem.
Here's another good source to review: Using Customized Type Mappings
Our object:
import java.io.Serializable;
...
class Account implements Serializable{
public String data;
}
How to get our object from bd:
while (rs.next()) {
Object accountJustObject = rs.getObject(i);
Account account = (Account)accountJustObject;
accounts.add(account);
i++;
}
How to save our object:
public void InsertAccount(int id, Account newaccount){
reparedStatement insertNew = conn.prepareStatement(
"INSERT INTO root(id,account) VALUES (?,?)";
insertNew.setInt(1, id); //INT field type
insertNew.setObject(2, newaccount); //OTHER field type
insertNew.executeUpdate();
)
}
Tested under H2 database.
Object Variables, are:
only REFERENCES to a space in memory.
any REFERENCE uses memory (just a little bit)
the way to get/use any object of a specific Type of Class from one reference is by simple Typecasting it.

ResultSet compare result object datatype to String

I'm trying to format a decimal before saving it within a hashmap of strings (compared to table names).
Can anyone tell me how I would compare the results set column name datatype with the datatype String.
The closet I can get is:
if(metaData.getColumnClassName(i).equals(String.class.getClass()))
My Code:
while(mResults.next())
{
for (int i = 1; i <= colCount; i++)
{
//ERROR HERE. Try to see if it's string for decimal format on float.
if(mResults.getObject(metaData.getColumnName(i)).equals(String.class))
{
System.out.println("Should be 3.");
}
SQLResults.put(metaData.getColumnName(i), mResults.getString(metaData.getColumnName(i)));
}
}
Use the ResultSet.getMetadata() method to obtain ResultSetMetaData which provides the column Type (and other information, such as numeric precision). You can then convert as necessary. The column type is returned as a java.sql.Types int constant, not a Class object.
if(mResults.getObject(metaData.getColumnName(i)).equals(String.class))
How could your object equal String class. you can get Object#getClass#getName what will return class Name of actaul Object Type that can be String or Integer. Something like -
if(mResults.getObject(metaData.getColumnName(i)).getClass().getName.equals("java.lang.String")){}
But still it does not make any sence, where it will be useful.
have you tried like:
if(metaData.getColumnType(i) == Types.VARCHAR)
where metadata is of type: ResultSetMetaData
if(metaData.getColumnClassName(i).equals("java.lang.Float"))
{
SQLResults.put(metaData.getColumnName(i),
mDF.format(mResults.getFloat(metaData.getColumnName(i))));
}

Categories

Resources