JDBC ResultSet get column from different tables - jdbc

i wan to retrieve data from query involving many tables.
i have a query as follows
String sql = "SELECT "
+ "s.Food_ID AS 'Sales_FoodID', "
+ "f.Food_Name AS 'foodName' "
+ "FROM Ordering o, Sales s, Food f"
+ " WHERE o.Table_No = " + tableNo + ""
+ " AND o.Paid = '" + NOT_PAID + "'"
+ " AND s.Order_ID = o.Order_ID"
+ " AND f.Food_ID = s.Food_ID;";
resultSet = statement.executeQuery(sql);
no error were found when i run the program, but after i add this line to get a table's column data:
String orderID = resultSet.getString("foodName");
i'm given this error:
java.sql.SQLException: Column not found
anyone know why?

You have to use next() method.
You should know that ResultSet is implicitly positioned on position before first row so you need to call next to get current position and if is valid, it returns true, else returns false (cursor is positioned after the last row).
rs = statement.executeQuery(sql);
while (rs.next()) {
String orderID = rs.getString(2);
}
Note: You can use also rs.getString(<columnName>) but in case when you know how your statement looks i recommend to you use index instead of columnName.

After calling the resultSet.executeQuery() you need to call the next() to pulling the records from db
after that you can call setXxx() provided by Java API

Related

Would iteration over Cassandra rows with LIMIT and OFFSET have any unexpected side effects?

My Project has a huge Cassadra Table. My Cassadra running with 5 nodes in a kubernetes. As Backend I use Spring Boot 2.X.
I try to update values in my entire Table. Because of the size of the table I do not use a "SELECT * FROM TABLE" query.
Instead I think about to use "limit" with "offset"
String sql = "SELECT * FROM " + tableName + " LIMIT " + limit + " OFFSET " + offset;
With recursive call
private boolean migrateBookingTable(Database database, Statement statement, String tableName, int limit, int offset) throws SQLException, LiquibaseException {
String sql = "SELECT * FROM " + tableName + " LIMIT " + limit + " OFFSET " + offset;
try (ResultSet resultSet = statement.executeQuery(sql)) {
//if resultSet is empty, we are done
if (!resultSet.isBeforeFirst()) {
return false;
}
while (resultSet.next()) {
//some logic
}
database.execute...
}
return migrateBookingTable(database, statement, tableName, limit, offset+limit);
}
I tested it on a small test environment. Its worked. But because of cassandra peculiarities and the fact of 5 Nodes on production. Im not sure about side effects.
Is this an "ok" way to go?
OFFSET is not part of CQL language, not sure how you tested.
cqlsh:ks1> select * from user LIMIT 1 OFFSET 1;
SyntaxException: line 1:27 mismatched input 'OFFSET' expecting EOF (...* from user LIMIT 1 [OFFSET]...)
Because of the size of the table I do not use a "SELECT * FROM TABLE" query.
Without the awful findAll() allowed by Spring Data Cassandra every request is paged with Cassandra. Why not going with the default behaviour of Paging with the cassandra drivers.
SimpleStatement statement = QueryBuilder.selectFrom(USER_TABLENAME).all().build()
.setPageSize(10) // 10 per pages
.setTimeout(Duration.ofSeconds(1)) // 1s timeout
.setConsistencyLevel(ConsistencyLevel.ONE);
ResultSet page1 = session.execute(statement);
LOGGER.info("+ Page 1 has {} items",
page1.getAvailableWithoutFetching());
Iterator<Row> page1Iter = page1.iterator();
while (0 < page1.getAvailableWithoutFetching()) {
LOGGER.info("Page1: " + page1Iter.next().getString(USER_EMAIL));
}
// Getting ready for page2
ByteBuffer pagingStateAsBytes = page1.getExecutionInfo().getPagingState();
statement.setPagingState(pagingStateAsBytes);
ResultSet page2 = session.execute(statement);
Spring Data Also allow paging with Slice

Java 8 How to concat query condition based on a list of string

How can I write the following code in a more elegant way using java8?
String query = "select device, manufacturer, type from devices where username = ?";
boolean found = false;
if (deviceTypes.stream().filter(t -> "typeA".equals(t)).findFirst().isPresent()) {
query += " AND type like 'A%'";
found = true;
}
if (deviceTypes.stream().filter(t -> "typeB".equals(t)).findFirst().isPresent()) {
if (found) {
query += " OR ";
} else {
query += " AND ";
}
query += " type like 'B%'";
}
If in the device types there are both A and B, the query should contain both with OR.
Example:-
deviceTypes="A,B" --> query condition => AND type like 'A%' OR type like 'B%';
Example:-
deviceTypes="B" --> query condition => AND type like 'B%';
thanks a lot
You may store the association between the deviceTypes strings and the predicate expressions in a map like
final Map<String,String> typeToExpression
= Map.of("typeA", "type like 'A%'", "typeB", "type like 'B%'");
Or use static final. This factory method requires Java 9+ but constructing a map should be straight-forward.
Then, one solution would be
String query = "select device, manufacturer, type from devices where username = ?";
query += deviceTypes.stream()
.map(typeToExpression::get).filter(Objects::nonNull)
.reduce((a, b) -> a + " OR " + b)
.map(" AND "::concat).orElse("");
which produces a string similar to your approach. But considering the operator precedence, I suppose, you might rather want
String query = "select device, manufacturer, type from devices where username = ?";
query += deviceTypes.stream()
.map(typeToExpression::get).filter(Objects::nonNull)
.reduce((a, b) -> "(" + a + " OR " + b + ")")
.map(" AND "::concat).orElse("");
This is optimized for your described case of having a rather small number of possible conditions, especially for two or less. But we can still reduce some of the largest string concatenation steps with only slightly more code.
final String baseQ = "select device, manufacturer, type from devices where username = ?";
String query = deviceTypes.stream()
.map(typeToExpression::get).filter(Objects::nonNull)
.reduce((a, b) -> "(" + a + " OR " + b + ")")
.map(cond -> baseQ + " AND " + cond).orElse(baseQ);
Here, baseQ is a compile-time constant, which in turn makes baseQ + " AND " a compile-time constant too which is combined with the predicate(s) in one step. If there is only one matching predicate, only one string concatenation will be performed. Further, if no matching predicate has been found, this evaluates to the already existing constant baseQ string.
But if you expect large numbers of predicates, a different approach should be used, optimized for larger numbers of elements, at the expense of the small number cases:
final String baseQ = "select device, manufacturer, type from devices where username = ?";
String query = deviceTypes.stream()
.map(typeToExpression::get).filter(Objects::nonNull)
.collect(
() -> new StringJoiner(" OR ", baseQ + " AND (", ")").setEmptyValue(baseQ),
StringJoiner::add,
StringJoiner::merge)
.toString();
Unlike the other approaches this will always put brackets around the predicates, even if there is one, but it will still only use that single pair of brackets when there are three or more. It avoids performing multiple string concatenations in a row by letting the StringJoiner do the entire work.

How to query the database based on current day using Hibernate?

I would like to retrieve database items based on the current day.
For that purpose I am trying to use the day() function as explained there and mentioned there.
I have a 'created' date field that is automatically filled when a new item is created in the table. It's configured using a model, like that:
#Column(name = "created", nullable = false)
#CreationTimestamp
private Date created;
I created a couple of items and the date is filled in the database as expected.
Now I am trying to call those items using a HQL query:
String hql = "" +
"FROM Item as item " +
"WHERE item.itemId = ?1" +
"AND item.created = day(current_date())";
The problem is that this query is returning a NoResultException.
It's weird because I am using the current_date() function in other scenarios, e.g.:
String hql = "" +
"FROM Item as item " +
"WHERE item.itemId = ?1" +
"AND item.createdAt >= current_date - ?2";
And it is working pretty well!
So I assume the issue is related with day() function.
Try use this:
String hql = "" +
"FROM Item as item " +
"WHERE item.itemId = ?1" +
"AND date(item.created) = current_date()";

Pageable in spring for paging on List<Object> is not working

I have a list of object which contain 10000 records i am trying to split that records in each of 10,
But somehow it is not working.. can someone have a look
#Query("select a.applicantid,coalesce(to_char(a.createdon,'yyyy-MM-dd'),to_char(filing_date,'yyyy-MM-dd')) as dt1, \r\n" +
"coalesce(c.companyname,i.InstituteName,(u.firstname||' '||u.lastname),\r\n" +
"u.firstname) ,a.c_denomination,cc.crop_common_name,cs.crop_botanical_name,\r\n" +
"a.id,aps.status,a.cropid, \r\n" +
"(select mv.varietytype from VarietyType mv where mv.id= a.varirtytypeid),\r\n" +
"(select sv.subvarietytype from SubVarietyType sv,VarietyType mvr \r\n" +
" where a.subvarietytypeid = sv.id and mvr.id= sv.varietyid),a.formtype,mcg.crop_group \r\n" +
" from Applications a left join ApplicantRegistration ap on \r\n" +
" a.applicantid = ap.id left join CompanyRegistration c on ap.companyid = c.id \r\n" +
" left join InstitutionRegistration i on ap.institutionid = i.id \r\n" +
" left join Crops cc on a.cropid = cc.id left join CropSpecies cs \r\n" +
" on a.cropspeciesid =cs.id left join InternalUser u on ap.id = u.applicantid \r\n" +
" left join ApplicationStatus aps on a.application_current_status = aps.id "
+ "left join CropGroup mcg on cc.cropgroupid = mcg.id order by a.id desc")
List<Object[]> getapplication_adminview();
List<Object[]> admin_viewapplication=applicationrepository.getapplication_adminview();
int pageNumber = 0;
int size = 10;
Pageable pageable = PageRequest.of(pageNumber, size); // object of pageable
Page<Object> pages = new PageImpl(admin_viewapplication, pageable, admin_viewapplication.size());
List<Object> lpage = pages.getContent(); // here i am getting the lpage size as 10000 but as i enter pageable as of size 10 i am expecting 10 results only
where i am going wrong in this ?
if i am trying to add pagable object to query and run the code i will get the following error:
Cannot create TypedQuery for query with more than one return using requested result type [java.lang.Long]; nested exception is java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [java.lang.Long]
Page just represents one page of data . So page.getContent() only return all data in one page which is specified through constructor when you create this page instance . It has nothing to do with splitting the data in a page.
If you want to split a list , use Lists from Guava is the simplest way to go :
List<List<Object>> splittedList = Lists.partition(list, 10);
If you want to do pagination which split all the data stored in the database into different smaller pages , split it at the database level rather than getting the whole list to the memory to split which will be very inefficient when the entire list is large. See this for how to split it at the database level by declaring Pageable in the query method.
We can use PagedListHolder which can change the list in pages and we can than fetch a page by setting it's page size and page.
PagedListHolder<Object> page = new PagedListHolder(admin_viewapplicationpage);
page.setPageSize(50); // number of items per page
page.setPage(0); // set to first page
int totalPages = page.getPageCount(); // gives the totalpages according to the main list
List<Object> admin_viewapplication = page.getPageList(); // a List which represents the current page which is the sublist
the following tutorial helped me
-> https://www.baeldung.com/spring-data-jpa-query
At this point 4.3. Spring Data JPA Versions Prior to 2.0.4
VERY IMPORTANT to add \ n-- #pageable \ n
Without this I was wrong
Also the pagination setting must be without ordering
PageRequest paginaConf = new PageRequest ((param1 - 1)
, param2);
Finally to convert the Page <Object []>
Page <Object []> list = myQueryofRepo ();
List <XXXModel> lstReturn = myConversor (list.getContent ());
Page <XXXModel> ret = new PageImpl <XXXModel> (lstReturn, pageConf, param2);

Bind parameters for ORDER BY in NamedParameterJDBCTemplate

I am trying to use NamedParameterJdbTemplate in a Spring MVC application. The issue is that the bind parameters do not seem to work (no sorting happens) when I include one of ORDER BY clauses listed below. However, a hard coded order by column name in the sql works.
ORDER BY column1
ORDER BY column1
ORDER BY column1 asc
ORDER BY column1 desc
For example, the below listed query does not work.
private static final String SEARCH_ALL_BY_SORT_ORDER=
" select FIRST_NM, MIDDLE_NM, LAST_NM, CUSTOMER_IDENTIFIER, EMAIL_ADDRESS, ACCOUNT_ID" +
" from VIEW " +
" where CUSTOMER_IDENTIFIER= :customerIdentifier " +
" and ( REGEXP_LIKE(FIRST_NM, :firstName, 'i') " +
" or REGEXP_LIKE(LAST_NM, :lastName, 'i') " +
" or REGEXP_LIKE(EMAIL_ADDRESS, :emailAddress, 'i') )" +
" order by :sortColumns";
The same query with a hard coded order by column works:
private static final String SEARCH_ALL_BY_SORT_ORDER=
" select FIRST_NM, MIDDLE_NM, LAST_NM, CUSTOMER_IDENTIFIER, EMAIL_ADDRESS, ACCOUNT_ID" +
" from VIEW " +
" where CUSTOMER_IDENTIFIER= :customerIdentifier " +
" and ( REGEXP_LIKE(FIRST_NM, :firstName, 'i') " +
" or REGEXP_LIKE(LAST_NM, :lastName, 'i') " +
" or REGEXP_LIKE(EMAIL_ADDRESS, :emailAddress, 'i') )" +
" order by LAST_NM";
Here's the relevant jdbctemplate code
Map <String, Object> params = new HashMap <String, Object>();
params.put("customerIdentifier", customerIdentifier);
params.put("firstName", searchCriteria );
params.put("lastName", searchCriteria );
params.put("emailAddress",searchCriteria);
// sortBy is COLUMN name
// sortOrder is either 'asc' or 'desc'
params.put("sortColumns", sortBy + " " + sortOrder);
// Using just the column name does not work either
//params.put("sortColumns", sortBy);
namedParameterJdbcTemplate.query(SEARCH_ALL_BY_SORT_ORDER, params, new MemberMapper());
Only values can be bound as parameters. Not parts of the query itself.
In the end, a prepared statement is generated and the parameters are bound to the prepared statement. The principle of a prepared statement is to prepare the execution plan of the query (of which the order by clause is a part), and to execute the query one or several times after, with varying parameters.
If the query is not complete, the execution plan can't be prepared and reused. So, for this part of the query, you'll need to generate the query dynamically using string concatenation, and not parameters.
As JB Nizet has already explained that parts of query cannot be used as bind keys (orderby :age). Therefore we will need to use concatenation here instead.
" order by "+ sortBy + " " + sortOrder;

Resources