Spring JDBC query for count of a specific field - java

I would like to know how I would get the count of a specific column within my database. Each distinct value in my column I would like to store the returned column value and its count within a Java List. This is what I have so far:
public List<Sighting> getCountPest() {
return jdbc.query("select pest_name, count(pest_name) from sighting group by pest_name", new RowMapper<Sighting>() {
public Sighting mapRow(ResultSet rs, int rowNum) throws SQLException {
Sighting sighting = new Sighting();
sighting.setCount(rs.getInt("count")); // will not work as no column name in table
sighting.setPest_name(rs.getString("pest_name"));
return sighting;
}
});
}
Essentially I would like to use pest_name and returned count value for a chart.
This is my sightingRowMapper if it helps:
public Sighting mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setUsername(rs.getString("username")); // setting the username if logged in
Sighting sighting = new Sighting();
sighting.setId(rs.getInt("id"));
sighting.setTotal_pests(rs.getInt("total_pests"));
sighting.setDate(rs.getString("date"));
sighting.setInformation(rs.getString("information"));
sighting.setPest_name(rs.getString("pest_name"));
sighting.setPark(rs.getString("park"));
sighting.setLocation(rs.getString("location"));
sighting.set_Username(rs.getString("username"));
sighting.setUser(user);
return sighting;
}

Sighting I guess you would need another result mapper than, which will deal only with pest_name and count column. At least it would be cleaner.
If you don't like creating new class for that, you could create anonymous class :
jdbc.query(
"select pest_name, count(pest_name) from sighting group by pest_name",
new RowMapper<Sighting>() {
public Sighting mapRow(ResultSet rs, int rowNum) throws SQLException {
return sighting;
}
});
Or use existing, but changing the query a bit:
select pest_name, count(pest_name) as total_pests
but it's a hack :)

Related

How would I unit test jdbcTemplate.query that have overrides?

I have a class that uses multiple get methods the returns
public int getCurrNum(String Name) {
// query clearances table to return an int that represents the clearance level
String sql = "SELECT number FROM clearances WHERE '" + Name + "' = name;";
//String.format("SELECT number FROM clearances WHERE '%s' = name;",clearanceName);
return jdbcTemplate.queryForObject(sql, Integer.class);
}
which I understand I can use Mockito with a statement like Mockito.when(jdbcTemplate.queryForObject(Mockito.anyString(), Mockito.eq(Integer.class))).thenReturn(1);
But that is not really testing values that are being passed in because I am just telling it to return a value I want. I want to make sure all these methods return what the parameters are specially passing in. We have a user token with user details being sent in. We also have more JdbcTemplates such as
public List<String> getCurr(String currCountry) {
// query alliances table to return a list of alliance tags that countain the
// user's country tag
String sql = "SELECT * FROM user WHERE '" + currCountry + "' = ANY(access_tags) ;";
return jdbcTemplate.query(sql, new RowMapper<String>() {
#Override
public String mapRow(ResultSet rs, int rownumber) throws SQLException {
return rs.getString(1);
}
});
Then the last methods combines everything and has this return statement that uses all these setters from another class.
// return list of appropriately filtered missions
return jdbcTemplate.query(sql, new RowMapper<Mission>() {
#Override
public OtherClass mapRow(ResultSet rs, int rownumber) throws SQLException {
OtherClass m = new OtherClass();
m.setNumber(rs.getInt(1));
m.setName(rs.getString(2));
m.setLastCheckinDate(rs.getString(3));
m.setLocation(rs.getString(4));
m.setCurrLocation(rs.getString(5));
m.setFinalLocation(rs.getString(6));
m.setTags(rs.getString(7));
return m;
}
});
}
But I am not sure how to test these statements. Without using the Mockito.when commands, they always turn out null. We have this information in a database .xml file for the column and rows so it knows what information to grab to fill in the lists. Do I need to mock a mock db or something to test this?

Rowmapper vs ResultSetExtractor in spring

I'm facing weird issue with Spring jdbc RowMapper:-
Here is my code
public void test(){
String sql=" Query will fetch records where dateColumn<='2021-08-17' Limit 1";
jdbcTemplate.query(sql, new ModelRowMapper());
}
public class ModelRowMapper implements RowMapper<ModelRowMapper> {
#Override
public ModelRowMapper mapRow(ResultSet rs, int rowNum) throws SQLException {
ModelRowMapper model= new ModelRowMapper();
System.out.println(rs.getString("value"));
}
}
Example:-
db records:-
2021-08-21
2021-08-15
2021-08-13
Output I'm expecting is 2021-08-15
In the ModelRowMapper class observed resultSet prints two values(1st is valid:- 2021-08-15) then print the invalid value and in the response also I will be getting invalid value
But above query properly works when I use the ResultSetExtractor
jdbcTemplate.query(sql, new ResultSetExtractor<String>() {
#Override
public String extractData(ResultSet rs) throws SQLException, DataAccessException {
while (rs.next()) {
System.err.println(rs.getString("value"));
}
//prints only one value and returns the same value
return "";
}
});
What would be the issue with rowMapper?....
Any suggestions would be helpful.......
You are somehow misunderstood how rowmapper should be called! use the following syntax, that would give you the desired result.
public void test(){
String sql=" Query will fetch records where dateColumn<='2021-08-17' Limit 1";
jdbcTemplate.query(query, new RowMapper<ModelRowMapper>(){
#Override
public ModelRowMapper mapRow(ResultSet rs, int rowNum) throws
SQLException {
ModelRowMapper model= new ModelRowMapper();
System.out.println(rs.getString("value"));
}
});
}

Manipulating a String with substring inside a query builder

I have a Query Builder like this:
#Override
public List<ComplementoMaterial> findSomething(String codigoPrestador, String documentoPrestador, String numeroLote, String codDocumento, List<String> codigosServicos) {
return builder().query(sqlComplementos())
.set("codPrestador", codigoPrestador)
.set("docPrestador", documentoPrestador)
.set("numeroLote", numeroLote)
.set("codDocumento", codDocumento)
.set("codServicos", codigosServicos)
.mapper(new RowMapper<ComplementoMaterial>() {
#Override
public ComplementoMaterial mapRow(ResultSet rs, int rowNum) throws SQLException {
ComplementoMaterial c = new ComplementoMaterial();
c.setCodigoServico(rs.getLong("COD_SERVICO"));
c.setRegistroAnvisa(rs.getString("COD_MATERIAL"));
c.setReferencia(rs.getString("COD_REF_MATERIAL"));
c.setAutorizacaoFuncionamento(rs.getString("NUM_AUT_FAT"));
return c;
}
}).executeQuery();
}
When I set the codigosServicos, I wish to apply an substring to him, so for each index I need take just after the 4th char of that String. For example:
If in codigoServicos I have a List as follow ["Michael","Jackson","Lebron"], I need that the query take just ["ael", "son", "on"].
I already tried to add a just codigoServicos.substring(4), but as he is set as List, that is not possible. And I also cannot broke the set to add a for loop.
Any idea do help me?
Tks
Are you using Java 8+? You can do it in one line with streams, like this:
.set("codServicos", codigosServicos.stream().map(s -> s.substring(4)).collect(Collectors.toList()))
Otherwsie you have to use a loop, sorry. You can, of course do the loop before you do set:
#Override
public List<ComplementoMaterial> findSomething(String codigoPrestador, String documentoPrestador, String numeroLote, String codDocumento, List<String> codigosServicos) {
List<String> substrings = new List<>(codigosServicos.size());
for (String name : codigosServicos) {
substrings.add(name.substring(4));
}
return builder().query(sqlComplementos())
.set("codPrestador", codigoPrestador)
.set("docPrestador", documentoPrestador)
.set("numeroLote", numeroLote)
.set("codDocumento", codDocumento)
// add list of substrings instead of the original list
.set("codServicos", substrings)
.mapper(new RowMapper<ComplementoMaterial>() {
#Override
public ComplementoMaterial mapRow(ResultSet rs, int rowNum) throws SQLException {
ComplementoMaterial c = new ComplementoMaterial();
c.setCodigoServico(rs.getLong("COD_SERVICO"));
c.setRegistroAnvisa(rs.getString("COD_MATERIAL"));
c.setReferencia(rs.getString("COD_REF_MATERIAL"));
c.setAutorizacaoFuncionamento(rs.getString("NUM_AUT_FAT"));
return c;
}
}).executeQuery();
}

i have to do login form validation,if password match it will move forward

it is moving forward on any user name or password.let me know the correct solution for this.
this is my dao.java class
public List < Student > getLogin() {
return template.query("select * from auction", new RowMapper < Student > () {
#Override
public Student mapRow(ResultSet rs, int row) throws SQLException {
Student s = new Student();
s.setName(rs.getString(1))
s.setPassword(rs.getString(2));
return s;
}
});
}
this is my controller.java kindly correct my code....what kind of changes i need to do
#RequestMapping(value="/addLogin",method=RequestMethod.GET)
public String addLogin(#ModelAttribute("SpringWeb")Student s, Model model) {
List<Student> list=dao.getLogin();
List <Student> b=dao.getStudentRecord();
String name=s.getName();
String password=s.getPassword();
if(name.equals(list) && password.equals(list)) {
model.addAttribute("welcome",name);
model.addAttribute("record",b);
return "change";
} else {
model.addAttribute("login","Wrong Username or Password");
return "login";
}
}
You dont need to query all users to do a login. instead change the query to
"select * from auction where userName=? and password=?"
in the service check whether the query returned any row. if the query returned a row then login success otherwise login failed.
So the Spring Implementation becomes..
template.queryForList("select * from auction where userName=? and password=?", new Object[]{userName, password});

Storing Count value from query

How do I store the returned count value into a variable, so I can then set a attribute with it? This is my method so far:
public List<Sighting> total() {
return jdbc.query("select pest_name, count(pest_name) from sighting group by pest_name", new RowMapper<Sighting>() {
public Sighting mapRow(ResultSet rs, int rowNum) throws SQLException {
Sighting sighting = new Sighting();
sighting.setCount(????); // I need to pass a variable to setCount()
sighting.setPest_name(rs.getString("pest_name"));
return sighting;
}
});
}
That count value in a query..
You could either specify a name for the count, e.g.
return jdbc.query("select pest_name, count(pest_name) as pest_count from sighting group by pest_name", new RowMapper<Sighting>() {
public Sighting mapRow(ResultSet rs, int rowNum) throws SQLException {
Sighting sighting = new Sighting();
sighting.setCount(rs.getInt("pest_count"));
sighting.setPest_name(rs.getString("pest_name"));
return sighting;
}
});
... or just fetch it by column number:
return jdbc.query("select pest_name, count(pest_name) from sighting group by pest_name", new RowMapper<Sighting>() {
public Sighting mapRow(ResultSet rs, int rowNum) throws SQLException {
Sighting sighting = new Sighting();
sighting.setCount(rs.getInt(2));
sighting.setPest_name(rs.getString("pest_name"));
return sighting;
}
});
You may need to use getLong instead of getInt.
Try with :
Select pest_name, count(pest_name) as totalCount
and in the resultset try with
long count = rs.getLong("totalCount")
Name your count. Change
"select pest_name, count(pest_name) from sighting group by pest_name"
to
"select pest_name, count(pest_name) as pest_count from sighting group by pest_name"

Categories

Resources