Storing Count value from query - java

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"

Related

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();
}

Parsing excel sheet to database in java - passing arguments issue

I am reading data from excel table and using java trying to set those values into database. My excel table has 6 columns and 170 rows. I have made class ExcelDataModel and mathod in which I go through excell table, but now I am stuck on how to pass arguments to BatchPreparedStatement. This is my code:
#Override
public void getExcell2() {
final String PATH = "C:\\Workspace\\zaposlenici.xlsx";
try {
Workbook workbook = WorkbookFactory.create(new File(PATH));
Sheet sh = workbook.getSheetAt(0);
Iterator<Row> rowIterator = sh.iterator();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
//how to pass arguments from one row to preparedStatement?
jdbcTemplate.batchUpdate("INSERT INTO INS_RAZNO.ZAPOSLENICI_TEST VALUES (?, ?, ?, ?, ?, ?)", new BatchPreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ExcelDataModel ex = new ExcelDataModel();
ps.setString(1, ex.getIme());
ps.setString(2, ex.getPrezime());
ps.setString(3, ex.getOdjel());
ps.setString(4, ex.getSlozenostPosla());
ps.setString(5, ex.getStarost());
ps.setString(6, ex.getMjesecniOD());
}
#Override
public int getBatchSize() {
return 0;
}
});
}}
} catch (EncryptedDocumentException | InvalidFormatException | IOException e) {
e.printStackTrace();
}
}
And here is my ExcelDataModel code:
public class ExcelDataModel {
private String ime;
private String prezime;
private String odjel;
private String slozenostPosla;
private String starost;
private String mjesecniOD;
public String getIme() {
return ime;
}
public void setIme(String ime) {
this.ime = ime;
}
public String getPrezime() {
return prezime;
}
public void setPrezime(String prezime) {
this.prezime = prezime;
}
public String getOdjel() {
return odjel;
}
public void setOdjel(String odjel) {
this.odjel = odjel;
}
public String getSlozenostPosla() {
return slozenostPosla;
}
public void setSlozenostPosla(String slozenostPosla) {
this.slozenostPosla = slozenostPosla;
}
public String getStarost() {
return starost;
}
public void setStarost(String starost) {
this.starost = starost;
}
public String getMjesecniOD() {
return mjesecniOD;
}
public void setMjesecniOD(String mjesecniOD) {
this.mjesecniOD = mjesecniOD;
}
}
I dont know how to pass those arguments into preparedStatement. Basicaly, how to form data to become arguments?
Any ideas? Thank you!
First of all lets understand the functioning of the BatchPreparedStatementSetter, it contains two methods:
getBatchSize(): Will define the quantity of records will be iterating over in the setValues method, the index will be passed as the second argument.
setValues(java.sql.PreparedStatement ps, int i): Will iterate the number of times defined in the getBatchSize() method.
So what is the point of this, you can access the elements of your collection using the index, like the example below:
jdbcTemplate.batchUpdate("INSERT INTO INS_RAZNO.ZAPOSLENICI_TEST VALUES (?, ?, ?, ?, ?, ?)", new BatchPreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, sh.getCell(i,1)); // Iterating over row, getting the first cell
}
#Override
public int getBatchSize() {
return sheet.getPhysicalNumberOfRows(); // Total rows in the Excel for example
}
});
PS: I used the Apache POI Documentation to suggest the methods to use
BatchPreparedStatementSetter Documentation
You have to choose between two options:
Call update in cell iterate loop and use JdbcTemplate#update function instead of batchUpdate.
If you want batchUpdate then first you iterate Excel cells, collect data to List. And then outside of loop you can use JdbcTemplate#batchUpdate.
but not both.

H2 - How to create a database trigger that log a row change to another table?

How to create a database trigger that log a row change to another table in H2?
In MySQL, this can be done easily:
CREATE TRIGGER `trigger` BEFORE UPDATE ON `table`
FOR EACH ROW BEGIN
INSERT INTO `log`
(
`field1`
`field2`,
...
)
VALUES
(
NEW.`field1`,
NEW.`field2`,
...
) ;
END;
Declare this trigger:
CREATE TRIGGER my_trigger
BEFORE UPDATE
ON my_table
FOR EACH ROW
CALL "com.example.MyTrigger"
Implementing the trigger with Java/JDBC:
public class MyTrigger implements Trigger {
#Override
public void init(Connection conn, String schemaName,
String triggerName, String tableName, boolean before, int type)
throws SQLException {}
#Override
public void fire(Connection conn, Object[] oldRow, Object[] newRow)
throws SQLException {
try (PreparedStatement stmt = conn.prepareStatement(
"INSERT INTO log (field1, field2, ...) " +
"VALUES (?, ?, ...)")
) {
stmt.setObject(1, newRow[0]);
stmt.setObject(2, newRow[1]);
...
stmt.executeUpdate();
}
}
#Override
public void close() throws SQLException {}
#Override
public void remove() throws SQLException {}
}
Implementing the trigger with jOOQ:
Since you added the jOOQ tag to the question, I suspect this alternative might be relevant, too. You can of course use jOOQ inside of an H2 trigger:
#Override
public void fire(Connection conn, Object[] oldRow, Object[] newRow)
throws SQLException {
DSL.using(conn)
.insertInto(LOG, LOG.FIELD1, LOG.FIELD2, ...)
.values(LOG.FIELD1.getDataType().convert(newRow[0]),
LOG.FIELD2.getDataType().convert(newRow[1]), ...)
.execute();
}
Shorter version of Lukas Eder's answer:
CREATE TRIGGER my_trigger
BEFORE UPDATE
ON my_table
FOR EACH ROW
CALL "com.example.MyTrigger"
public class MyTrigger extends TriggerAdapter {
#Override
public void fire(Connection conn, ResultSet oldRow, ResultSet newRow) throws SQLException {
// mannipulate the rows here by using the methods on the oldRow and newRow objects
}
}

Spring JDBC query for count of a specific field

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 :)

Categories

Resources