how do I add items to a list that match? - java

As I process each country, how do I add only the languages with matching country id for that country?
private List<String> readCountryLanguages(Statement sqlStatement, List<Country>countries) throws SQLException {
List<String> languages = new ArrayList<>();
for (Country country : countries ) {
ResultSet resultSet = sqlStatement.executeQuery("SELECT language FROM COUNTRY_LANGUAGE");
while (resultSet.next()) {
String language = new String(resultSet.getString("Languages"));
Country obj = new Country(0, language, 0, 0);
obj.getId();
}
}
return languages;
}

Not sure about your table structure of COUNTRY_LANGUAGE but you can update the sql query to something like.
SELECT language FROM COUNTRY_LANGUAGE WHERE country='" + country.getName() + "'
Here I am assuming you have a column "country" in your COUNTRY_LANGUAGE table and country name can be retrieve from Country object by calling Country.getName(). But you can use the exact method from your actual implementation.

return the Country id in a variable when you iterate; you should have something like country.getId();
ResultSet resultSet = sqlStatement.executeQuery("SELECT language FROM COUNTRY_LANGUAGE where id='countryIdVariable'");
change your sql query to be parametized/prepared statement so you can prevent sql injection and also add variable easier instead of having to write variable within single quote in your sql string.

AS menthion by Asura, First of all change your sql query that returns language where contryId is 'something'
then in while loop add each language to languages list object by using add() method like this :
while (resultSet.next()) {
String language = resultSet.getString("Languages");
// add to list
languages.add(language);
}
}

Related

how to return a cursor along with new variable added to each row?

I want to call a procedure from java.
Example:
CREATE OR REPLACE PROCEDURE helloworld
AS
cursor data_test is
with required_data as( select *
from EMPLOYEES) select * from required_data rd join DEPARTMENTS d on d.department_id=rd.DEPARTMENT_ID ;
emp_rec data_test%ROWTYPE;
more_detail varchar2(50);
BEGIN
open data_test;
LOOP
FETCH data_test INTO emp_rec;
exit when data_test%NOTFOUND;
more_detail =BLA.GET_MORE_DATA(data_test.empid);// Lets say the fuction return varchar2 I've total of 4 similar fields to be added in total
END LOOP;
END;
/
Now how do I return all the data in the cursor(data_test ) along with more_detail in each row?? i.e I want my ResultSet in java to have all the values from the select statement as well as the value of more_detail.Also will my helloworld have out parameter as SYS_REFCURSOR or something else?? and when calling from java all I've to do is create a callable statement and register out parameter as Cursor to use this?
Well, when I look at it today, How could I ask this question. This so wrong.
I didn't have much understanding of PLSQL then and asked the question without reading much. Anyway, there are many ways to solve it as I mentioned in the comment one can send back an associative array but that is a pain on the java side if you don't know the number of expected result. or one can create a nested array with an user with defined object something like this:
CREATE OR REPLACE TYPE keyvalue AS object (col Number(10), col2 VARCHAR2(30));
CREATE OR replace TYPE map IS TABLE OF keyvalue ;
hear's how I did it. You cannot add a column to cursor but you can create you own custom defined data type.
CREATE OR REPLACE TYPE dbObject AS OBJECT
(
empId NUMBER (6),// here add as many fields you want to return or want your object to have
emailId VARCHAR2 (25),
hiredate DATE
);
CREATE OR REPLACE TYPE datalist IS TABLE OF DBOBJECT;
PROCEDURE get_emp_data (list OUT datalist)
AS
CURSOR emp_cursor
IS
SELECT employee_id AS empId,
EMPLOYEES.EMAIL AS emailId,
EMPLOYEES.HIRE_DATE AS hiring
FROM EMPLOYEES;
c_datatype emp_cursor%rowtype;
BEGIN
OPEN emp_cursor();
list := datalist();
LOOP
fetch emp_cursor into c_datatype;
EXIT WHEN emp_cursor%NOTFOUND;
list.extend;
list(emp_cursor%ROWCOUNT):=DBOBJECT(c_datatype.empId,c_datatype.emailId,c_datatype.hiring);
END LOOP;
END get_emp_data;
Now you want to call this from java: here is the code:
String dataTypeName = "DBOBJECT";
String dataTypeListName = "datalist";
StructDescriptor structDescriptor = StructDescriptor.createDescriptor(dataTypeName.toUpperCase(), connection);
ResultSetMetaData metaData = structDescriptor.getMetaData();
CallableStatement cs = connection.prepareCall("{call TEST_PACKAGE.get_emp_data(?)}");
cs.registerOutParameter(1, OracleTypes.ARRAY, dataTypeListName.toUpperCase());
cs.execute();
Object[] data = (Object[]) ((Array)cs.getObject(1)).getArray();
for(Object tmp : data) {
Struct row = (Struct) tmp;
int index = 1;
for(Object attribute : row.getAttributes()) {
System.out.println(metaData.getColumnName(index) + " : " + attribute);
++index ;
}
}
cs.close();

SQL query to select tablename

I want to get all database table names that ends with _tbl like xyz_tbl, pqr_tbl,etc..
in mysql using java.pls help me.. currently my query retreives all tablename but i jst want table names that ends with _tbl.
My code is...
public List selectTable() {
List tableNameList= new ArrayList();
try {
DatabaseMetaData dbm = c.conn.getMetaData();
String[] types = {"TABLE"};
c.rs = dbm.getTables(null, null, "%", types);
while (c.rs.next()) {
tableNameList.add(c.rs.getString("TABLE_NAME"));
}
} catch(Exception e) {
System.out.println(e.toString());
}
return tableNameList;
}
Did you try using a different table name pattern?
You can try this: -
c.rs = dbm.getTables(null, null, "%_tbl", types);
You can use mysql query
show tables from tablename like '%_tbl';
I am unable to reply to Rohit's post. his answer looks correct.
If you do to JDK documentation for DatabaseMetaData's getTables method following is the signature and documentation comment.
ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern,
String[] types) throws SQLException
Parameters:
catalog - a catalog name; must match the catalog name as it is stored
in the database; "" retrieves those without a catalog; null means that
the catalog name should not be used to narrow the search
schemaPattern
- a schema name pattern; must match the schema name as it is stored in the database; "" retrieves those without a schema; null means that the
schema name should not be used to narrow the search tableNamePattern -
a table name pattern; must match the table name as it is stored in the
database types - a list of table types, which must be from the list of
table types returned from getTableTypes(),to include; null returns all
types
In this case using %_tbl should work.
Use the String.endsWith() method to check if the table name ends with "_tbl".
For example inside your while loop:
while (c.rs.next())
{
String tableName = c.rs.getString("TABLE_NAME");
if(tableName.endsWith("_tbl"))
{
tableNameList.add(c.rs.getString("TABLE_NAME"));
}
}

Resultset to list

I want to create a list with my database field values.
There are 2 columns, name and surname.
I want to create a list that stores all names in name column in a field and then add to my DTO.
Is this possible?
Steps you can follow: -
First you need to have a List<String> that will store all your names. Declare it like this: -
List<String> nameList = new ArrayList<String>();
Now, you have all the records fetched and stored in ResultSet. So I assume that you can iterate over ResultSet and get each values from it. You need to use ResultSet#getString to fetch the name.
Now, each time you fetch one record, get the name field and add it to your list.
while(resultSet.next()) {
nameList.add(resultSet.getString("name"));
}
Now, since you haven't given enough information about your DTO, so that part you need to find out, how to add this ArrayList to your DTO.
The above list only contains name and not surname as you wanted only name. But if you want both, you need to create a custom DTO (FullName), that
contains name and surname as fields. And instantiate it from
every ResultSet and add it to the List<FullName>
JDBC unfortunately doesn't offer any ways to conveniently do this in a one-liner. But there are other APIs, such as jOOQ (disclaimer: I work for the company behind jOOQ):
List<DTO> list =
DSL.using(connection)
.fetch("SELECT first_name, last_name FROM table")
.into(DTO.class);
Or Spring JDBC
List<DTO> list =
new JdbcTemplate(new SingleConnectionDataSource(connection, true))
.query("SELECT first_name, last_name FROM table", (rs, rowNum) ->
new DTO(rs.getString(1), rs.getString(2));
Or Apache DbUtils:
List<DTO> list =
new QueryRunner()
.query(connection,
"SELECT first_name, last_name FROM table",
new ArrayListHandler())
.stream()
.map(array -> new DTO((String) array[0], (String) array[1]))
.collect(Collectors.toList());
I've used Java 8 for the Spring JDBC / Apache DbUtils examples, but it can be done with older versions of Java as well.
It is. What have you tried ?
To access the database, you need to use JDBC and execute a query, giving you a ResultSet.
I would create an class called FullName with 2 String fields name and surname. Just populate these in a loop using
rs.getString("NAME"); // column name
rs.getString("SURNAME");
e.g.
List<FullName> fullnames = new ArrayList<FullName>();
while (rs.next()) {
fullnames.add(new FullName(rs));
}
Note that I'm populating the object via the ResultSet object directly. You may choose instead to implement a constructor taking the 2 name fields.
Note also that I'm creating a Fullname object. So the firstname/surname are kept separate and you have the freedom to add initials etc. later. You may prefer to rename this Person and that will give you the freedom to add additional attributes going forwards.
What worked for me is:
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
ArrayList<String> resultList= new ArrayList<>(columnCount);
while (rs.next()) {
int i = 1;
while(i <= columnCount) {
resultList.add(rs.getString(i++));
}
}
return resultList;
This worked for me->
private List<Object[]> convertResultsetToObject(ResultSet rs) throws SQLException {
List<Object[]> results = new ArrayList<Object[]>();
int count = 0;
if(rs != null) {
ResultSetMetaData rsm = rs.getMetaData();
count = rsm.getColumnCount();
}
while(rs != null && rs.next()) {
Object [] obj = new Object[count];
int temp = 1;
while(temp <= count) {
obj[temp - 1] = rs.getObject(temp);
temp++;
}
results.add(obj);
}
return results;
}

java - how to inject custom PreparedStatement's paramters

I am trying to implement PreparedStatement, which won't work with sql DB.
Suppose I have the following sql query:
String selectSqlQuery = "SELECT * FROM customer WHERE f1 = ? AND f2 =? AND f3 > ?";
and the following code:
//----
prest = con.prepareStatement(selectSqlQuery );
prest.setString(1, "val1");
prest.setString(2, "val2");
prest.setInt(3, 108);
ResultSet rs = prest.executeQuery();
//---
My question is how to implement setString and setInt methods for injecting params?
For now I save parameters' indexes and values into HashMap, but after it I can't make injection into sql query string.
implementation of sql's java interfaces are part of vendor specific jdbc driver. You probably just need to get the proper jdbc jar file for you database. writing implementations of such stuff is usually just needed if you intend to write your own database driver...
Since you're writing your own driver, you can play with your class a little. Let's change the approach. If you have a query like this one:
"SELECT * FROM table WHERE id = ? AND name = ?"
Replace the ? to turn it into
"SELECT * FROM table WHERE id = {0} AND name = {1}"
About your set methods, those will have to save your new parameters in an Object array, again matching against the index.
Object parameterArray = new Object[1];
public boolean setString(int paramIndex, String param) {
if(paramIndex < 0 || paramIndex > parameterArray.length)
throw new IllegalArgumentException("Can't set parameter " + paramIndex + ", The query only has " + parameterArray.length + " parameters.");
parameterArray[paramIndex - 1] = param;
}
Before executing the query, take advantage of your formatted string and set the parameters:
MessageFormat messageFormat = new MessageFormat(query);
String newQuery = messageFormat.format(parameterArray);
The format method will replace the {number} substrings for the corresponding element in the index represented by the number between brackets.

PreparedStatement not returning ordered ResultSet

I am having some problems and I'm sure it's something stupid.
So I have a query like
SELECT name, id, xyz FROM table ORDER BY ?
then later down the road setting the ? doing a
ps.setString(1, "xyz");
I am outputting the query and the value of xyz in the console. When I loop through the ResultSet returned from the PreparedStatement the values are not in the correct order. They are in the returned order as if I had left the ORDER BY clause off. When I copy/paste the query and the value into TOAD it runs and comes back correctly.
Any ideas to why the ResultSet is not coming back in the correct order?
The database will see the query as
SELECT name, id, xyz FROM table ORDER BY 'xyz'
That is to say, order by a constant expression (the string 'xyz' in this case). Any order will satisfy that.
? is for parameters, you can't use it to insert column names. The generated statements will look something like
SELECT name, id, xyz FROM table ORDER BY 'xyz'
so that your entries are sorted by the string 'xyz', not by the content of column xyz.
Why not run:
ps.setInteger(1, 3);
Regards.
EDIT: AFAIK Oracle 10g supports it.
PreparedStatement placeholders are not intend for tablenames nor columnnames. They are only intented for actual column values.
You can however use String#format() for this, that's also the way I often do. For example:
private static final String SQL_SELECT_ORDER = "SELECT name, id, xyz FROM table ORDER BY %s";
...
public List<Data> list(boolean ascending) {
String order = ascending ? "ASC" : "DESC";
String sql = String.format(SQL_SELECT_ORDER, order);
...
Another example:
private static final String SQL_SELECT_IN = "SELECT name, id, xyz FROM table WHERE id IN (%s)";
...
public List<Data> list(Set<Long> ids) {
String placeHolders = generatePlaceHolders(ids.size()); // Should return "?,?,?..."
String sql = String.format(SQL_SELECT_IN, placeHolders);
...
DAOUtil.setValues(preparedStatement, ids.toArray());
...
The database will see the query like this
SELECT name, id, xyz FROM table ORDER BY 'xyz'
I think you should add more variable like order_field and order_direction
I assume you have a method like below and I give you an example to solve it
pulbic List<Object> getAllTableWithOrder(String order_field, String order_direction) {
String sql = "select * from table order by ? ?";
//add connection here
PreparedStatement ps = (PreparedStatement) conn.prepareStatement(sql);
ps.setString(1,order_field);
ps.setString(2,order_direction);
logger.info(String.valueOf(ps)); //returns something like: com.mysql.jdbc.JDBC4PreparedStatement#a0ff86: select * from table order by 'id' 'desc'
String sqlb = String.valueOf(ps);
String sqlc = sqlb.replace("'"+order_field+"'", order_field);
String sqld = sqlc.replace("'"+order_direction+"'", order_direction);
String[] normQuery = sqld.split(":");
ResultSet result = conn.createStatement().executeQuery(normQuery[1]);
while(result.next()) {
//iteration
}
}

Categories

Resources