Row from a database as string (JDBC) - java

Is there a direct method to get the all the elements in a row from the ResultSet as String? JDBC

You may use BasicRowProcessor from Apache commons, Dbutils
ResultSet rs = ....
RowProcessor rp = new BasicRowProcessor();
Map m = rp.toMap( rs );
String s = m.toString();
And you'll have then as:
{ id = 1, name = Oscar, lastName = Reyes }
etc.
If you want to get rid of the columNames:
String s = m.values().toString();

There's not a single method call to do it, but you can use something like this to build a String:
StringBuilder sb = new StringBuilder();
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
for (int i = 1; i <= numberOfColumns; i++) {
sb.append(rs.getString(i));
if (i < numberOfColumns) {
sb.append(", ");
}
}
String data = sb.toString();

I've got to ask - why would you need something like that?
And no, it's not possible - you would need to call getString() at least once no matter what. The best you can do is to concatenate your fields in SQL, e.g.
SELECT col1 || ', ' || col2 || ', ' || col3 ... FROM my_table
and call resultSet.next().getString(1) to get that.
Update (based on comment)
I don't think (that depends on your JDBC driver and database, really - you'll have to measure to find out) that there is a big difference in data volume between sending data (from DB to your app) by columns vs one concatenated string. In fact, the latter may even be more expensive if you have numbers / dates because they'll likely occupy more bytes formatted as text.

Related

How to create a dynamic WHERE clause for a query using an array list

I have a List<String> of categories and for each category, I want to add them to my WHERE clause by combining with AND operator like: SELECT question_id FROM question WHERE category = categ1 AND category = categ2 AND category = ...
Since the size of the categories list is changing, I cannot do something like this:
String sql = "SELECT question_id FROM question WHERE category = ? AND category = ?";
jdbcTemplate.query(sql, stringMapper, "categ1", "categ2");
How can I achieve what I want?
Either check if JDBC Template from Spring handle that for you using a syntax which could be something like (from the doc, I don't think it does)
SELECT question_id FROM question WHERE category in (?...)
Or write your own query with the problems that may arise:
List<Object> parameters = new ArrayList<>(categories.size());
StringBuilder sb = new StringBuilde("SELECT question_id FROM question WHERE 1=1");
if (!categories.isEmpty()) {
if (categories.size() == 1) {
sb.append(" and category = ?");
} else {
sb.append(" and category in ");
sb.append(categories.stream()
.map(ignored -> "?")
.collect(joining(", ", "(", ")")));
sb.append(")");
}
parameters.addAll(categories);
}
Object[] paramArray = parameters.toArray();
jdbcTemplate.query(sb.toString(), stringMapper, paramArray);
Notes:
some security/quality tool may report SQL issues because you are writing a dynamic SQL.
Oracle put a limit on 1000 elements per IN. You would have to partition categories per group of 1000 (or less).
I used a stream() in a more or less strange fashion in order to generate the "?". If you use commons-lang3, you can replace it by "(" + StringUtils.repeat("?", ", ", categories.size()) + ")" (the example in the javadoc was probably done with this kind of use).
if you only have category as single criteria, you may probably remove the 1=1 as well as the and.
I believe this may work for you:
// The SQL Query
String sql = "SELECT question_id FROM question";
// Create the WHERE clause based on the number of items in List...
StringBuilder whereClause = new StringBuilder(" WHERE ");
StringBuilder ps = new StringBuilder("");
for (int i = 0; i < categories.size(); i++) {
if (!ps.toString().isEmpty()) {
ps.append(" AND ");
}
ps.append("category = ?");
}
whereClause.append(ps.toString()).append(";");
//Append the WHERE clause string to the SQL query string
sql = sql + whereClause.toString();
//System.out.println(sql);
/* Convert the categories List to an Object[] Array so as to
pass in as varArgs to the jdbcTemplate.query() method. */
Object[] psArgs = categories.toArray(new Object[categories.size()]);
jdbcTemplate.query(sql, stringMapper, psArgs);

How to convert database result set as JSON format in java?

I want to convert the result set from the db into json format, the problem is when the result set returned as multiple rows for the same id with some duplicates data.
DB example:
===========================================================
USER_ID NAME PHONE_NUMBER CITY
===========================================================
1 JACK 079999999999 New York
1 JACK 078888888888 Las Vegas
I want to make my json body looks like:
{ "USER_ID": 1,"NAME": JACK,"PHONE_NUMBER":[ 079999999999, 078888888888 ], "CITY": [ New York, Las Vegas ]}
this is my code:
Statement stmt = con.createStatement();
// Execute the SQL Query. Store results in ResultSet
ResultSet rs = stmt.executeQuery(Query);
System.err.println("Executing the query please wait ...");
ResultSetMetaData rsmd=null;
rsmd=(ResultSetMetaData) rs.getMetaData();
int columnsCount=rsmd.getColumnCount();
for (int j = 1; j <= columnsCount; j++) {
System.err.print(rsmd.getColumnName(j) + " || ");
}
JSONArray jsonArray = new JSONArray();
while (rs.next()) {
int total_rows = rs.getMetaData().getColumnCount();
JSONObject obj = new JSONObject();
for (int i = 0; i < total_rows; i++) {
String columnName = rs.getMetaData().getColumnLabel(i + 1).toLowerCase();
Object columnValue = rs.getObject(i + 1);
// if value in DB is null, then we set it to default value
if (columnValue == null){
columnValue = "null";
}
if (obj.has(columnName)){
columnName += "1";
}
obj.put(columnName, columnValue);
}
jsonArray.put(obj);
System.out.print("\n");
System.out.print("\n");
String gsonBody = gson.toJson(jsonArray);
System.err.println(gsonBody);
}
return jsonArray;
How can i make this general for all possible scenarios with different result set.
which RDBMS are you using? if Postgres/db2 is your database than you could return the resultset directly as JSON.
Using SQL/JSON
In many modern RDBMS, you don't have to implement any Java logic for that. The standard SQL way to do this is by using the SQL/JSON extensions. In your specific case, you could write
SELECT
user_id,
name,
JSON_ARRAYAGG(phone_number) AS phone_number,
JSON_ARRAYAGG(city) AS city
FROM t
GROUP BY user_id, name
Other dialects have different syntax for the same thing
Doing this in Java
Since you're asking how to do this specifically in Java, you could use jOOQ, which has extensive SQL/JSON support and would allow you to write the above query in a type safe way:
String json =
ctx.select(
T.USER_ID,
T.NAME,
jsonArrayAgg(T.PHONE_NUMBER).as(T.PHONE_NUMBER),
jsonArrayAgg(T.CITY).as(T.CITY))
.from(T)
.groupBy(T.USER_ID, T.NAME)
.fetch()
.formatJSON();
The benefit would be that this would take care of emulating the JSON array aggregation for your specific dialect and version, in case you have to work around some caveats.
(Disclaimer: I work for the company behind jOOQ)
A side note on normalisation
In the long term, you should think about normalising your data. You shouldn't have duplicate entries for USER_ID and NAME in this table, as it would allow for data anomalies (e.g. different NAME for the same USER_ID)

Retrieve database in java using JTextField to search

So, i would like to retrieve database information where a user will search certain columns using text fields, like this:
column1 find userinput,
column2 find userinput,
column3 find userinput,
The problem im having is the sql statement:
String sql = "select * from table where column = '" + textfield1.getText() + "'";
If textfield1 is empty, it will only retrieve entries that contain nothing.
What im trying to retrieve will have 6 text field, meaning 6 columns in the database. Using java i would need alot of if statements.
Is there any other way to shorten this?
EDIT
-- MORE INFO --
The if statements will start from:
if (!(t1.getText().equals("")) && !(t2.getText().equals("")) && !(t3.getText().equals(""))
&& !(t4.getText().equals("")) && !(t5.getText().equals("")) && (t6.getText().equals("")))
all the way down to
if (t1.getText().equals("") && t2.getText().equals("") && t3.getText().equals("")
&& t4.getText().equals("") && t5.getText().equals("") && t6.getText().equals("")
covering all possible combinations of the 6 input fields, the point of all these statements is to ignore empty text fields but provide the corresponding sql statement.
I don't know how to calculate the possible combinations other than writing them all down(i started, there was too many).
I didn't really understand why those ifs, you should elaborate more your question but i will try to help as i can.
Well, if you want to retrieve everything from the database you could use LIKE:
String sql = "select * from table where column like '%" + textfield1.getText() + "%'";
This way you'll get everything with the containing text, it means, if the field is empty it will bring all results, i guess this is the best way to do, to avoid unnecessa if clauses.
Another thing, to check for empty fields you should use:
t1.getText().trim().isEmpty()
BUT if you let they write white spaces the LIKE won't help you then you need to .trim() all your texts then your white spaces will be ignored.
The following can be formulated much neater, but to make the point:
JTextField ts = new JTextField[6];
Set<String> values = new HashSet<>(); // Removes duplicates too.
for (JTextField t : ts) {
String text = ts.getText().trim();
if (!text.isEmpty()) {
values.add(text);
}
}
// Build the WHERE condition of a PreparedStatement
String condition = "";
for (String value : values) {
condition += condition.isEmpty() ? "WHERE" : " OR";
condition += " column = ?";
}
String sql = "select * from table " + condition;
PreparedStatement stm = connection.prepareStatement(sql);
int index = 1; // SQL counts from 1
for (String value : values) {
stm.setString(index, value);
++index;
}
ResultSet rs = stm.executeQuery();
The usage of a PreparedStatement makes escaping ' (and backslash and such) no longer needed and also prevents SQL injection (see wikipedia).
i have a problem i want to search data based on multiple jtext fields where did i go wrong coz this displays only one row which has the first id
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String sql="SELECT Employee.EmpID,Employee.Fname,Employee.Mname,Employee.Sname,Employee.DoB,Employee.Phone,"
+ "Employee.Email,Employee.Nationality,Employee.Desegnition,Employee.NSSF,Employee.WCF,"
+ "Employee.BSalary,Allowance.medical,Allowance.Bonus,Allowance.others,Allowance.tov,Allowance.TA,"
+ "Attendece.Hrs from Employee,Allowance,Attendece WHERE "
+ "Employee.EmpID=Allowance.EmpID and Attendece.EmpID=Allowance.EmpID AND Employee.EmpID=? AND Attendece.Dt=?";
try{
pd=conn.prepareStatement(sql);
pd.setString(1,id.getText());
pd.setString(2,Date1.getText());
r=pd.executeQuery();
//setting the text fields
if(r.next())
{
String a=r.getString("EmpID");
eid.setText(a);
String b=r.getString("Fname");
fname.setText(b);
String c=r.getString("Mname");
mname.setText(c);
String d=r.getString("Sname");
sname.setText(d);
String e=r.getString("DoB");
dob.setText(e);
String f=r.getString("Desegnition");
Des.setText(f);
String g=r.getString("Bsalary");
bsal.setText(g);
String h=r.getString("Phone");
phone.setText(h);
String i=r.getString("Email");
email.setText(i);
String j=r.getString("Nationality");
nationality.setText(j);
String k=r.getString("Desegnition");
Des.setText(k);
String l=r.getString("NSSf");
nssf.setText(l);
String m=r.getString("WCF");
wcf.setText(m);
String n=r.getString("tov");
oh.setText(n);
String o=r.getString("Bonus");
bn.setText(o);
String p=r.getString("medical");
md.setText(p);
String q=r.getString("others");
ot.setText(q);
String s=r.getString("TA");
ta.setText(s);
String t=r.getString("Hrs");
hrs.setText(t);
int day;
day=Integer.parseInt(t)/8;
days.setText(Integer.toString(day));
double week=day/7;
weeks.setText(Double.toString(week));
}
r.close();
pd.close();
}catch(Exception e)
{
}

Error: Before start of result set in Java

I know this would be a foolish question to ask but still i need to do this.
This is a basic program in java application where I want to use 3 queries simultaneously to print the table.
(I'm not using any Primary key in this case so please help me to resolve this without making my attributes as primary keys - I know this is not a good practice but for now i need to complete it.)
my code:
Connection con = null;
Statement stat1 = null, stat2 = null, stat3 = null;
ResultSet rs1, rs2, rs3;
stat1 = con.createStatement();
stat2 = con.createStatement();
stat3 = con.createStatement();
String str = "\nProduct\tC.P\tS.P.\tStock\tExpenditure\tSales";
info.setText(str);
String s1 = "SELECT type, cp, sp, stock FROM ts_items GROUP BY type ORDER BY type";
String s2 = "SELECT expenditure FROM ts_expenditure GROUP BY type ORDER BY type";
String s3 = "SELECT sales FROM ts_sales GROUP BY type ORDER BY type";
rs1 = stat1.executeQuery(s1);
rs2 = stat2.executeQuery(s2);
rs3 = stat3.executeQuery(s3);
String type;
int cp, sp, stock, expenditure, sales;
while( rs1.next() || rs2.next() || rs3.next() )
{
type = rs1.getString("type");
cp = rs1.getInt("cp");
sp = rs1.getInt("sp");
stock = rs1.getInt("stock");
expenditure = rs2.getInt("expenditure");
sales = rs3.getInt("sales");
info.append("\n" + type + "\t" + cp + "\t" + sp + "\t" + stock + "\t" + expenditure + "\t" + sales);
}
Output:
Runtime Exception: Before start of result set
This is the problem:
while( rs1.next() || rs2.next() || rs3.next() )
If rs1.next() returns true, rs2.next() and rs3.next() won't be called due to short-circuiting. So rs2 and rs3 will both be before the first row. And if rs1.next() returns false, then you couldn't read from that anyway...
I suspect you actually want:
while (rs1.next() && rs2.next() && rs3.next())
After all, you only want to keep going while all three result sets have more information, right?
It's not clear why you're not doing an appropriate join, to be honest. That would make a lot more sense to me... Then you wouldn't be trying to use multiple result sets on a single connection, and you wouldn't be relying on there being the exact same type values in all the different tables.
You do an OR so imagine only one ResultSet has a result.
What you end up with is trying to read from empty result sets.
Suppose rs1 has one result and rs3 has 3 results. Now as per your code it will fail for rs1.getString("type"); during second iteration.
Better to loop over each resultSet separately.
This is going to go badly wrong, in the event that there is a type value that's missing from one of your three tables. Your code just assumes you'll get all of the types from all of the tables. It may be the case for your current data set, but it means that your code is not at all robust.
I would seriously recommend having just one SQL statement, that has each of your three selects as subselects, then joins them all together. Your java can just iterate over the result from this one SQL statement.

arraylist in insert query

i am trying to insert data from excel sheet into database in java. for that i have connected both the database using ODBC. excelsheet has 2 columns cname and title.
after querying the Excel spreadsheet i stored the resultSet values of cname and title into arraylist.
List Cname = new ArrayList();
List Title=new ArrayList();
Cname.add(rs.getString("Cname"));
Title.add(rs.getString("Title"));
this will result like this
[aaa, bbb,cccc, dddd]
[tree,human,animal,bird]
when i try to insert this into SQL database using insert query it is getting stored like this.
statement1.executeUpdate("INSERT INTO dbo.company (Cname,Title) SELECT
'"+Cname+"','"+Title+"'");
Cname Title
[aaa, bbb,cccc, dddd] [tree,human,animal,bird]
but i want to store this as
Cname Title
___________________________
aaa tree
bbb human
cccc animal
ddd bird
how do i do this???pls help to solve in this.
You'll have to insert/update the list values, actually you're inserting the string representations of the entire lists..
Assuming, both lists do exist (not null) and have the same length, then this is a trivial solution:
for (int i = 0; i < Cname.size(); i++ {
statement1.executeUpdate("INSERT INTO dbo.company (Cname,Title) SELECT
'"+Cname.get(i)+"','"+Title.get(i)+"'");
}
Note - every java class has an implementation of the toString() method, and that method is called, when you "use an object as a string", like in the expression to create the SQL statement. For lists, the method returns a String that simply includes the (String-representations of) the list element in brackets.
Put a for loop around your insert statement:
for(int i = 0; i < Cname.size(); i++)
statement1.executeUpdate("INSERT INTO dbo.company (Cname,Title) values ( '"+Cname.get(i)+"','"+Title.get(i)+"')");
If your db is SQL Server, you can reference the followng Q & A. Just prepare xml data and pass to Stored Procedure.
How to Update SQL Server Table With Data From Other Source (DataTable)
You can create a single SQL statement of this form:
INSERT INTO dbo.company (Cname, Title)
VALUES ('aaa', 'tree'),
('bbb', 'human'),
('cccc', 'animal'),
('dddd', 'bird')
With JDBC:
StringBuilder sql = new StringBuilder();
sql.append("INSERT INTO dbo.company (Cname,Title) VALUES ");
String glue = "";
for (int i = 0; i < Cname.size(); i++) {
sql.append(glue);
sql.append("('");
sql.append(Cname.get(i).toString().replace("'", "''"));
sql.append("', '");
sql.append(Title.get(i).toString().replace("'", "''"));
sql.append("')");
glue = ", ";
}
statement1.executeUpdate(sql.toString());
An alternative syntax (if the above doesn't work for Excel spreadsheets) is this:
INSERT INTO dbo.company (Cname, Title)
SELECT 'aaa', 'tree' UNION ALL
SELECT 'bbb', 'human' UNION ALL
SELECT 'cccc', 'animal' UNION ALL
SELECT 'dddd', 'bird'
Or with JDBC
StringBuilder sql = new StringBuilder();
sql.append("INSERT INTO dbo.company (Cname,Title) ");
String glue = "";
for (int i = 0; i < Cname.size(); i++) {
sql.append(glue);
sql.append("SELECT '");
sql.append(Cname.get(i).toString().replace("'", "''"));
sql.append("', '");
sql.append(Title.get(i).toString().replace("'", "''"));
sql.append("'");
glue = " UNION ALL ";
}
statement1.executeUpdate(sql.toString());

Categories