Create ArrayList from Postgresql query - java

I have following class:
public class Person {
private String firstName;
private String lastName;
private List<String> habits;
}
I have Postgres query which returns me following result using inner join from 2 tables
name | lastname| habits
--------------------------------------
John | Smith | ["walking", "eating"]
I am trying to write RowMapper as following:
private final RowMapper<Person> rowMapper = (rs, rowNum) -> {
String firstName = rs.getString("name");
String lastName = rs.getString("lastName");
}
I am not sure how to create List habits from "habits column in my result table"
Please advise
Thanks

Found an answer
The code below is working fine
String[] habits;
try {
habits = objectMapper.readValue(rs.getString("habits"), String[].class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
List<String> habitsList = Arrays.stream(habits).toList();

I have tried it and working fine. You can try the below code what I have understand from your description.
String firstName = rs.getString("name");
String lastName = rs.getString("lastName");
List<String> list = rs.getObject("habits");
if you get compilation error, it will work definitly
List stringList = new ArrayList;
List objectList = stringList;// this does compile only if List where subtypes of List
objectList.add(new Object());
String s = stringList.get(0);
it should work.
Let me know if you facing still issue

Related

Room database RawQuery() is not work on "IN" and "NOT IN" clause

I have my one table like UserTable.
#Entity
public class UserTable{
#PrimaryKey(autoGenerate = true)
private int userId;
private String userName;
private String userEmailId;
// Below code is getter and setter of this class.
}
#Dao
public interface UserDao {
#Query("SELECT * FROM userTable")
public List<UserTable> loadAllUsers();
#Insert
public long insertUserTable(UserTable userTable);
#Insert
public long[] insertUserTables(UserTable... userTables);
#Update
public int updateUserTable(UserTable userTable);
#Delete
public int deleteUserTable(UserTable userTable);
#RawQuery
public abstract List<UserTable> loadAllUserListByGivenIds
(SupportSQLiteQuery query);
public default List<UserTable> loadAllUserListByIds(long[] userIds) {
List<UserTable> list;
ArrayList<Object> argsList = new ArrayList<>();
String selectQuery = "SELECT * FROM UserTable WHERE userId IN (?);";
argsList.add(userIds);
SimpleSQLiteQuery simpleSQLiteQuery = new SimpleSQLiteQuery(selectQuery, argsList.toArray());
list = loadAllUserListByGivenIds(simpleSQLiteQuery);
return list;
}
}
// Now in My MainActivity.class file, I have use following code:
List<UserTable> userList= databaseClient
.getAppDatabase()
.userDao()
.loadAllUserListByIds(new long[]{1L,2L});
My query is running in normal database, but when I was pass array of user ids then, in #RawQuery() method of dao class is not supported for "IN" clause used in where condition "WHERE userId IN (?)".
How, I will use "IN" clause in #RawQuery() of room database.
Much easier to use an #Query it's as simple as:-
#Query("SELECT * FROM UserTable WHERE userId IN (:idList)")
public List<UserTable> getWhatever(long[] idList);
You'd then use getWhatever(new long[]{1L,2L})
If you need it an #rawQuery though you could do it like (used previous answer code for my convenience) :-
private List<TableXEntity> loadAllUserListByIds(int order,long[] idList) {
StringBuilder idListAsCSV = new StringBuilder(); //<<<<<<<<<<
boolean afterFirst = false; //<<<<<<<<<<
//<<<<<<<<<< all of the loop to create the CSV
for (Long l: idList) {
if (afterFirst) {
idListAsCSV.append(",");
}
afterFirst = true;
idListAsCSV.append(String.valueOf(l));
}
StringBuilder sb = new StringBuilder("SELECT * FROM ").append(DBHelper.TableX.NAME);
sb.append(" WHERE " + DBHelper.TableX.COLUMN_ID + " IN(").append(idListAsCSV).append(") "); //<<<<<<<<<<
switch (order) {
case DBHelper.TableX.FIRSTNAME_DESCENDING:
sb.append(DBHelper.TableX.ORDER_BY_FIRSTNAME_DESC);
break;
case DBHelper.TableX.FIRSTNAME_ASCENDING:
sb.append(DBHelper.TableX.ORDER_BY_FIRSTNAME_ASC);
break;
case DBHelper.TableX.LASTNAME_DESCENDING:
sb.append(DBHelper.TableX.ORDER_BY_LASTNAME_DESC);
break;
case DBHelper.TableX.LASTNAME_ASCENDING:
sb.append(DBHelper.TableX.ORDER_BY_LASTNAME_ASC);
break;
default:
break;
}
sb.append(";");
return roomDao.rawq(new SimpleSQLiteQuery(sb.toString(),null));
}
i.e. provide a CSV (although I vaguely recall being able to pass an array)
To use bind arguments (the recommended way as binding arguments protects against SQL injection) then you need a ? for each value and a corresponding array of objects.
So for 3 id's you need IN(?,?,?) and the actual values, the bind arguments, in an Object[]. The following is an example that does this noting that it shows 2 ways of building the Object[] (the bind arguments/values):-
private List<TableXEntity> loadByidList(long[] idlist) {
List<Object> bindargs = new ArrayList<>(); // way 1
Object[] args4Bind = new Object[idlist.length]; // way 2
StringBuilder placeholders = new StringBuilder(); // for the ? placeholders
/* Build the sql before the place holders */
StringBuilder sql = new StringBuilder("SELECT * FROM ")
.append(DBHelper.TableX.NAME)
.append(" WHERE ")
.append(DBHelper.TableX.COLUMN_ID)
.append(" IN (");
boolean afterfirst = false;
int i = 0; /* using for each so have index counter (as opposed to for(int i=0 ....) */
for (long l: idlist) {
bindargs.add(l); // for way 1
args4Bind[i++] = String.valueOf(l); // for way 2
if (afterfirst) {
placeholders.append(",");
}
afterfirst = true;
placeholders.append("?");
}
/* finalise the SQL */
sql.append(placeholders.toString())
.append(");");
//return roomDao.rawq(new SimpleSQLiteQuery(sql.toString(),bindargs.toArray())); // way 1
return roomDao.rawq(new SimpleSQLiteQuery(sql.toString(),args4Bind)); // way 2
}
Please try this, here it has working!
Try this simple trick to pass the arguments for IN operator-
List<Object> argList = new ArrayList<>();
argList.add("3");
argList.add("6");
Then prepare your raw query string:
Note- Match your argument list size with '?' size
String selectQuery = "SELECT * FROM task WHERE id IN (?,?)";
After this pass the raw query string to SimpleSQLiteQuery-
SimpleSQLiteQuery rawQuery = new SimpleSQLiteQuery(selectQuery, args.toArray());
Then fetch the List using DAO:
List<UserTable> taskList1=DatabaseClient
.getInstance(getApplicationContext())
.getAppDatabase()
.userTableDAO()
.getAllList(query);
We can do it in kotlin in the more simpler way.
Let's create two helper methos
object Helper {
fun sqlIn(list: List<Any>, bindArgs: MutableList<Any>): String {
bindArgs.apply { this.addAll(list) }
return "IN (${list.joinToString(",") { "?" }})"
}
fun sqlNotIn(list: List<Any>, bindArgs: MutableList<Any>): String = "NOT ${sqlIn(list, bindArgs)}"
}
Then you can use it in anywhere else
val ids = listOf(1, 2, 3)
val ownerId = 10
val bindArgs = mutableListOf<Any>()
val query = "SELECT * FROM posts WHERE id ${Helper.sqlIn(ids, bindArgs)} AND owner_id = ?"
bindArgs.add(ownerId)
dao.query(
SimpleSQLiteQuery(query, bindArgs.toTypedArray())
)

How to do this using collections/ stream api

I have this Requirement :
Construct each Doctor with their respective Appointments and return a doctorList. Input is Appointment List for whole Hospital.
What I have is the followings:
Two classes given with the following variables.
Class Appointment{
String doctorName;
DateTime startTime;
DateTime endTime;
String speciality;
//Getters-Setters
}
Another Class :
Class Doctor{
String name;
String speciality;
List <Appointment> appointments;
//Getters-Setters
}
Requirement is :
Construct each Doctor with their respective Appointments and return a doctorList.
Input is Appointment List for whole Hospital.
Can some body tell what should be my approach?
I hope this will help you. Use Map to maintain the appointments of each doctor. In the below code you can get the appointment details using the doctor's name.
`//appointments - input list
Map<String, List<Appointment>> map = new HashMap<>();
for(Appointment app : appointments) {
if(!map.containsKey(app.getDoctorName())) {
List<Appointment> li = new ArrayList<>();
li.add(app);
map.put(app.getDoctorName(),li);
} else {
map.get(app.getDoctorName()).add(app);
}
}`
You can use HashMap.
HashMap<Doctor, ArrayList> doctorList = new HashMap<>();
Might not be a good idea in your case mainly because I do not understand what you are trying to achieve.
If you need match doctors with Appointment by both Speciality and Name, then:
Map<String, List<Appointment>> map = appointmentList
.stream()
.collect(Collectors.groupingBy(e -> e.getDoctorName() + e.getSpeciality()));
List<Doctor> doctors = new ArrayList<>();
for (String doctorNameAndSpeciality : map.keySet()) {
List<Appointment> appointments = map.get(doctorNameAndSpeciality);
if (!appointments.isEmpty()) {
Doctor doctor = new Doctor();
Appointment appointment = appointments.get(0);
doctor.setName(appointment.getDoctorName());
doctor.setSpeciality(appointment.getSpeciality());
doctor.addAllAppointments(appointments);
}
}
return doctors;
if you need use only 'name', then just remove 'speciality'

Read data from a CSV file, compare and display in Java

I have 3 csv files as follows:
Author file with columns: emailID | firstname | lastname
Books file with columns: title | isbn | author_email | description
Magazine with file Columns: title | isbn | author_email | releasedate
I need to display:
Based on the ISBN display all books and magazines
All books and magazines by an author
All books and magazines by title
I am using BufferedReader as of now:
String csvFileToRead = "csvFiles/authors.csv";
BufferedReader br = null;
String line = "";
String splitBy = ";";
try {
br = new BufferedReader(new FileReader(csvFileToRead));
while ((line = br.readLine()) != null) {
String[] book = line.split(splitBy);
System.out.println("BOOKS [Email Address= " + book[0] + " , firstname="
+ book[1] + " , lastname=" + book[2] + "]");
}
}
I am confused about how to proceed with multiple files. Here are the approaches that i have considered:
Change
String csvFileToRead
to a String array
String[] csvFileToRead = {"data/authors.csv", "data/books.csv", "data/magazines.csv"};
Then pass each index each time to a method returning all rows but getting stuck with DS to use. I think ArrayList won't suffice since i need separated data.
Should I use a 2D array?
Do I need to read and store data in a DS in order to achieve the goal?
Should I make 3 different classes with getters and setters for authors, book and magazine?
What is the ideal way to do this? Please suggest.
I would create 3 List<String[]> each containing the matrix from one CSV file with a method like:
public List<string[]> csvToList(String csvFileToRead){
BufferedReader br = null;
String line = "";
String splitBy = ";";
try {
br = new BufferedReader(new FileReader(csvFileToRead));
List<string[]> list_csv = new ArrayList<string[]>();
while ((line = br.readLine()) != null) {
String[] book = line.split(splitBy);
authors.add(book);
}
catch(Exception ex) {}
return list_csv;
}
And after that you can use it as :
List<String[]> authors = csvToList("csvFiles/authors.csv");
List<String[]> books = csvToList("csvFiles/books.csv");
List<String[]> magazine = csvToList("csvFiles/magazine.csv");
You can now print all what you want, for example the first case : Based on the ISBN display all books and magazines :
public void printISBN(string ISBN){
for(String[] s_tab in books)
if(s_tab[1].equals(ISBN))
System.out.println(s_tab[0]);
for(String[] s_tab in magazine)
if(s_tab[1].equals(ISBN))
System.out.println(s_tab[0]);
}
Hope I helped.
Edit
You could also create 3 classes for each files and do the same with Lists of thoses classes : List<Authors> List<Books> List<Magazine> but it is not necessary if you just have to answer those 3 questions.
One simple solution is to create three classes corresponding to your entities:
public class Author {
private String email;
private String firstName;
private String lastName;
// ...
}
public class Book {
private String title;
private String isbn;
private String authorEmail;
private String description;
// ...
}
public class Magazine {
private String title;
private String isbn;
private String authorEmail;
private Date releaseDate;
// ...
}
In your main code, when reading your CSV files you can fill a HashMap that maps an ISBN to a book, and a similar one for magazines, which you can use to retrieve a book or magazine by ISBN:
Map<String, Book> isbnBookMap = new HashMap<String, Book>();
Book book = isbnBookMap.get(isbn);
Map<String, Magazime> isbnMagazineMap = new HashMap<String, Magazime>();
Magazime magazine = isbnMagazineMap.get(isbn);
Similarly for getting a book or magazine by title.
As for getting books by author, you would need to map the author mail address to a List of Books since an author can have multiple books:
Map<String, List<Book>> authorBookMap = new HashMap<String, List<Book>>();
List<Book> books = authorBookMap.get(authorAddress);
You could use a Java CSV API
like OpenCSV

How to generate a sql from the inputs to the method

I have my below method which will accept two parameters-
final String userId- Primary Key for the database
final Collection<String> attributeNames- list of column names that I
want to retrieve
Below is the code
public Map<String, String> getAttributes(final String userId, final Collection<String> attributeNames) {
//Below line doesn't works out the way I wanted
String query="SELECT" +attributeNames.toString()+ ", * from test where id = "+userId+ ";";
ResultSet result = CassandraDatastaxConnection.getInstance().getSession().execute(query);
for (Row rows: result){
System.out.println(rows.getString("key"));
}
return attributes;
}
let's take an example, userId as 40
Sample attributeNames will look like this-
[account, behavior, segmentation]
Now I need to generate a SQL corresponding to the inputs. So for above example, sql should look like this-
SELECT account, behavior, segmentation from test where id = "40";
How can I generate a SQL like this from the above inputs? Thanks for the help.
You can use something like attributeNames.toString().substring(1, attributeNames.toString().length()-1)
Change this function
public Map<String, String> getAttributes(final String userId, final Collection<String> attributeNames) {
//Below line doesn't works out the way I wanted
String query="SELECT" +attributeNames.toString()+ ", * from test where id = "+userId+ ";";
ResultSet result = CassandraDatastaxConnection.getInstance().getSession().execute(query);
for (Row rows: result){
System.out.println(rows.getString("key"));
}
return attributes;
}
to this
public Map<String, String> getAttributes(final String userId, final Collection<String> attributeNames) {
//Below line doesn't works out the way I wanted
StringBuilder sb = new StringBuilder(attributeNames.size());
for(int i = 0; i<attributeNames.size();i++)
{
sb.append(attributeNames.get(i));
if(i != attributeNames.size() - 1)
sb.append(",");
}
String query="SELECT" +sb.toString()+ " from test where id = "+userId+ ";";
ResultSet result = CassandraDatastaxConnection.getInstance().getSession().execute(query);
for (Row rows: result){
System.out.println(rows.getString("key"));
}
return attributes;
}
The modified function runs a loop through the attribute names and constructs the query part as name1, name2, name3, etc and then adds it to the query body. Hope this solves your problem.

Iterartor - How to traverse for specific records

I have executed a query using JDBC and traversing the resultset I have stored all fields in List in java.
List<String> dataList=new ArrayList<String>();
while(res.next())
{
dataList.add(res.getString(1));
dataList.add(res.getString(2));
dataList.add(res.getString(3));
dataList.add(res.getString(4));
dataList.add(res.getString(5));
dataList.add(res.getString(6));
dataList.add(res.getString(7));
}
Iterator<String> it= dataList.iterator();
As I have added directly into list so how can I get this 7 fields while traversing the iterator.
Means:
while(it.hasNext())
{
String f1=it.next();
}
Like wise everytime I want 7 fields at a time
and next 7, next 7....... so on
Using this while loop how can I get those 7 fields (one row in table having 7 field) at a time.
I get little bit confuse here. Please help me.
Thanks
What you want to do is actually create another object that stores all seven of the values.
Then create a list of these entries so that you can access one row at a time, which is what I think you are asking.
First create a class for the row.
private static class Entry {
String[] row;
public Entry ( ResultSet r ) {
row = new String [ 7 ];
for (int i = 1; i <= 7; i++) {
row[i] = r.getString(i);
}
}
}
Using that, you can then create a list of Entry objects.
List<Entry> entryList = new ArrayList <Entry> ();
while(res.next())
{
entryList.add ( new Entry ( res ) );
}
Then, you can go ahead and loop through entryList and get any specific entry you would want.
Of course, if you have specific values, it might be wise to create instance variables of type String for Entry rather than an array of Strings.
By that I mean you could do this:
private static class Entry {
String column1; // rather than name column1 use what the column semantically represents
String column2;
// ...
public Entry ( ResultSet r ) {
column1 = r.getString(1);
// ...
}
This way, you can also calls like r.getInt(i) for certain columns which have an different type other than String.
Good luck!
I think your List declaration should be
List<Any DAO Object> instead of List<String>
While fetching from resultset, create a DAO object, add all fetched data into that object and then add that object into the list.
Then you can iterate and get each DAO object at each iteration.
You can use DatabaseMetaData class,
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost/testdb";
private static final String USERNAME = "root";
private static final String PASSWORD = "";
public static void main(String[] args) throws Exception {
Class.forName(DRIVER);
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
DatabaseMetaData metadata = connection.getMetaData();
ResultSet resultSet = metadata.getColumns(null, null, "users", null);
while (resultSet.next()) {
String name = resultSet.getString("COLUMN_NAME");
String type = resultSet.getString("TYPE_NAME");
int size = resultSet.getInt("COLUMN_SIZE");
System.out.println("Column name: [" + name + "]; type: [" + type + "]; size: [" + size + "]");
}
connection.close();
}

Categories

Resources