I have the following SQL query:
SELECT CONNECTIONDATE AS UNLOAD,
SUBSTR(ROUTECODE,1,(LENGTH(ROUTECODE)-2)) AS ROUTE,
COUNT(SUBSTR(ROUTECODE,1,(LENGTH(ROUTECODE)-2))) AS FREQUENCY
FROM RouteTableSynonym RC1
WHERE RC1.ROUTECONNECTIONTYPE = 'INBOUND'
and RC1.CONNECTIONTIME >= TO_TIMESTAMP('<sdate>', 'DD-MM-YYYY HH24:MI:SS')
and RC1.CONNECTIONTIME <= TO_TIMESTAMP('<edate>', 'DD-MM-YYYY HH24:MI:SS')
and RC1.LOGISTICSPOINTID in (SELECT DISTINCT RCO1.LOGISTICSPOINTID
FROM RouteOrderTableSynonym RCO1
WHERE RCO1.NAMC = '<namc>')
GROUP BY CONNECTIONDATE, SUBSTR(ROUTECODE,1,(LENGTH(ROUTECODE)-2))
ORDER BY CONNECTIONDATE, ROUTE;
All values designated by '<var_name>' are replace with the values that being queried. I also have this entity class that will store the result of this query:
import java.util.Date;
public class DD_BlackoutRouteFrequencies {
private Date rte_day;
private String route;
private int freq;
private int delayedFreq;
public Date getRte_day() {
return rte_day;
}
public void setRte_day(Date rte_day) {
this.rte_day = rte_day;
}
public String getRoute() {
return route;
}
public void setRoute(String route) {
this.route = route;
}
public int getFreq() {
return freq;
}
public void setFreq(int freq) {
this.freq = freq;
}
public int getDelayedFreq() {
return delayedFreq;
}
public void setDelayedFreq(int delayedFreq) {
this.delayedFreq = delayedFreq;
}
}
I execute the query like this :
try{
SQLQuery sqlquery = session.createSQLQuery(query);
sqlquery.addEntity(DD_BlackoutRouteFrequencies.class);
results = sqlquery.list();
logger.debug(results.size());
System.out.println("Frequnecy Results size: "+results.size());
}catch(Exception e){
logger.error("Exception ", e);
throw new RuntimeException("SQL Exception getting Blackout Route Frequencies: "+ e.getMessage());
}
The problem I am having is that I cannot figure out how to do the hibernate mapping for this entity to receive the results of this query which draws its results from two different tables.
Do I have to do the hibernate mapping for both table used in the query and then map the entity?
You can also get an instance of a map. e.g.:
SQLQuery sqlQuery = session.createSQLQuery(sql);
// positional parameters (using ?)
sqlQuery.setString(0, sdate);
sqlQuery.setString(1, edate);
sqlQuery.setString(2, namc);
// scalar values for each column
sqlQuery.addScalar("UNLOAD", Hibernate.STRING);
sqlQuery.addScalar("ROUTE", Hibernate.STRING);
sqlQuery.addScalar("FREQUENCY ", Hibernate.INTEGER);
sqlQuery.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
List<Map<String, Object>> list = sqlQuery.list();
for (Map<String, Object> map : list) {
System.out.println(map.get("UNLOAD"));
System.out.println(map.get("ROUTE"));
System.out.println(map.get("FREQUENCY"));
}
Related
I have a query that when I execute it on database, it gives me decimals, but when I execute the same query on my app, it gives me the numbers without decimals.
I have my variables setted as "double" and they are correctly "linked" to the database, I put the code below.
Here is where I call the method:
List<DatosEstadistica> listaDatosEstadistica = facade.obtenerDatosIngresos(filtro);
The facade:
public List<DatosEstadistica> obtenerDatosIngresos(FiltroInformes filtro)
throws ServiceException {
return this.modeloService.obtenerDatosIngresos(filtro);
}
The service implement:
public List<DatosEstadistica> obtenerDatosIngresos(FiltroInformes filtro)
throws ServiceException {
try {
return this.getDao().obtenerDatosIngresos(filtro);
} catch (HibernateException he) {
throw new ServiceException(he);
}
}
And the query instructions:
public List<DatosEstadistica> obtenerDatosIngresos(FiltroInformes filtro) {
try {
StringBuffer query = new StringBuffer();
query.append("sum( decode ( a.indingdev,'R',0, "
+ "nvl(a.impingdev,0) + "
+ "nvl(a.imprecargo_ing,0) "
+ ") "
+ ") as total_recaudado, "
+ "from tableM m, table_f f, table_a a "
+ "where m.reg = f.reg");
SQLQuery querySQL = getHibernateTemplate().getSessionFactory().getCurrentSession()
.createSQLQuery(query.toString());
querySQL.setResultTransformer(Transformers.aliasToBean(DatosEstadistica.class));
return querySQL.list();
} catch (HibernateException qe) {
throw qe;
}
}
And datosEstadistica.class:
public class DatosEstadistica implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 88592689034562323954L;
private double TOTAL_RECAUDADO;
/**
* Instantiates a new datos estadistica.
*/
public DatosEstadistica() {
}
public double getTOTAL_RECAUDADO() {
return TOTAL_RECAUDADO;
}
public void setTOTAL_RECAUDADO(double tOTAL_RECAUDADO) {
TOTAL_RECAUDADO = tOTAL_RECAUDADO;
}
}
But I don't know why it doesn't give me decimals as in the same query executed on the database. Anyone can helps me, please?
EDIT:
Here is where I printed out the results, but it doesn't print the decimals, because the query List "listDatosEstadistica" return numbers without decimals:
celdaDatos.setCellValue((listaDatosEstadistica.get(i).getTOTAL_RECAUDADO()));
I need to have dynamic SQL which accepts table and column names from users and uses those in queries. Right now I do this with
public Object doSearch(String table, List<String> columns) {
//... some logic
String.format("SELECT %s from %s", String.join(", ", columns), table");
//... some execution and return
}
The source is NOT trusted, so I want to do a whitelist of table and column names, but that list changes. The list of valid tables is strictly the list of tables on my_schema and the list of valid columns is strictly the columns on that particular table.
I've searched around SO and gotten a solution that looks something like:
private boolean validate(String tableName, List<String> columnNames) throws SQLException {
return tableExist(tableName) && columnNames.stream().allMatch(cn -> columnExistsOnTable(tableName, cn));
}
private boolean tableExist(String tableName) throws SQLException {
try (ResultSet rs = connection.getMetaData().getTables(null, schema, tableName, null)) {
while (rs.next()) {
String tName = rs.getString("TABLE_NAME");
if (tName != null && tName.equals(tableName)) {
return true;
}
}
}
return false;
}
private boolean columnExistsOnTable(String tableName, String columnName) {
try (ResultSet rs = connection.getMetaData().getColumns(null, schema, tableName, columnName)) {
while (rs.next()) {
String tName = rs.getString("COLUMN_NAME");
if (tName != null && tName.equals(tableName)) {
return true;
}
}
} catch (SQLException sqle) {
return false;
}
return false;
}
Is this safe and correct?
For each of those methods, you could do this one time in an initialization method and cache the table/column names so you don't have to do a database check every time... something like this:
private Map<String, Set<String>> tableColNames = new HashMap();
private void initCache(){
// build the cache
// get all tables
// get all columns
// add tables and columns to the map
}
private boolean tableExist(String tableName) throws SQLException {
return tableColNames.containsKey(tableName);
}
private boolean columnExistsOnTable(String tableName, String columnName) {
if(tableExist(tableName)){
return tableColNames.get(tableName).contains(columnName);
} else {
return false;
}
}
// could make a method for checking a list of Strings too...
// return tableColNames.get(tableName).containsAll(columnName);
https://docs.oracle.com/javase/7/docs/api/index.html?java/sql/ResultSetMetaData.html
Hello am trying to fetch 10 rows of data from Cassandra table. But on each request same 10 row is returning. Please see my logic here. and advise me where am doing wrong here-
public class CustomerRequestDaoImpl implements CustomerRequestDao
{
private static Cluster cluster;
#Resource
private CassandraSessionFactory cassandraSessionFactory;
/** The ProductsByTagDaoImpl session. */
private Session session;
#Override
public List<CustomerRequest> getCustomerRequestData(final String productId, final String receiptPeriod)
{
final int RESULTS_PER_PAGE = 10;
session = cassandraSessionFactory.getSession();
final List<CustomerRequest> customerRequestdata = new ArrayList<CustomerRequest>();
try
{
final PreparedStatement statement =
session.prepare("select * from customer_request where product_id = :id and receipt_period = :receiptPeriod");
final BoundStatement boundStatement = new BoundStatement(statement);
boundStatement.setFetchSize(RESULTS_PER_PAGE);
boundStatement.setString("id", productId);
boundStatement.setString("receiptPeriod", receiptPeriod);
final ResultSet resultSet = session.execute(boundStatement);
final Iterator<Row> iter = resultSet.iterator();
final PagingState nextPage = resultSet.getExecutionInfo().getPagingState();
int remaining = resultSet.getAvailableWithoutFetching();
for (final Row rowdt : resultSet)
{
customerRequestdata.add(constructCustomerReq(rowdt));
if (--remaining == 0)
{
break;
}
}
}
catch (final Exception e)
{
e.printStackTrace();
}
return customerRequestdata;
}
#PostConstruct
public void init()
{
session = cassandraSessionFactory.getSession();
cluster = session.getCluster();
}
}
My Table-
My Table structure:-
CREATE TABLE customer_request (
product_id varchar PRIMARY KEY,
id varchar,
receipt_period varchar,
delivery_method_status varchar,
first_name varchar
);
return Response-
<e>
<deliveryMethodStatus null="true"/>
<firstName null="true"/>
<id>0b0352f6b3904</id>
<lastName Adkin="true"/>
<orderId>FORMS8a04e</orderId>
<orderItemId>FORMS8a04e-1</orderItemId>
<productId>PI_NAME_CHANGE</productId>
<receiptPeriod>2016-02-06</receiptPeriod>
<receivedDate null="true"/>
<requestData null="true"/>
Several remarks:
You should not re-prepare the query each time, it's an
anti-pattern. Prepare the statement only once and re-use it for each method call
The source code you show will always return the first page of
data because you break out of the for loop once remaining
variable counts down to 0. The PagingState object is not used
anywhere ...
You question is not clear either Hello am trying to fetch 10 rows of
data from Cassandra table. But on each request same 10 row is
returning. Which 10 rows do you want ? The first 10 rows ? The
10 rows after a threshold ?
Sample code for paging:
Note: prepared the following query only once: select * from customer_request where product_id = :id and receipt_period = :receiptPeriod LIMIT :lim and pass it along with the method
#Override
public List<Tuple2<String,CustomerRequest>> getCustomerRequestData(final String productId, PreparedStatement ps, final String receiptPeriod, String pagingState)
{
final int PAGE_SIZE = 10;
session = cassandraSessionFactory.getSession();
final List<CustomerRequest> customerRequestdata = new ArrayList<CustomerRequest>();
try
{
final BoundStatement boundStatement = ps.bind(productId, receiptPeriod, PAGE_SIZE);
boundStatement.setPagingState(PagingState.fromString(pagingState));
final ResultSet resultSet = session.execute(boundStatement);
final Iterator<Row> iter = resultSet.iterator();
final PagingState nextPage = resultSet.getExecutionInfo().getPagingState();
int remaining = resultSet.getAvailableWithoutFetching();
for (final Row rowdt : resultSet)
{
customerRequestdata.add(constructCustomerReq(rowdt));
if (--remaining == 0)
{
break;
}
}
}
catch (final Exception e)
{
e.printStackTrace();
}
return new Tuple2<>(nextPage.toString(), customerRe);
Please note the use of Tuple2 class to return the list of results as well as the paging state, serialized as a String to be passed easily to the front-end
i am trying to iterate records from a table using the list iterator but it is returning zero records . i have used a setter getter class and trying to fetch records into a jsp page
code is as follows :
java function :
public List<product> getProducts()
{
List<product> prod=new ArrayList<product>();
try
{
conn = obj.connect();
String sql="select product.product_name , product.price , product.image_url "
+ "from category , product "
+ "where product.category_id=category.category_id and product.product_brand like 'LG%'";
rs=cs.executeQuery(sql);
while(rs.next())
{
p.setPname(rs.getString(1));
p.setPrice(rs.getString(2));
p.setImg(rs.getString(3));
}
prod.add(p);
}
catch(SQLException e)
{
e.printStackTrace();
}
catch(Exception k)
{
k.printStackTrace();
}
return prod;
}
jsp code :
operations op=new operations();
product p=new product();
List<product> list=op.getProducts();
%>
<title>LG Mobiles</title>
</head>
<body>
<b><font color="blue">Total Records Fetched : <strong><%=list.size()%></strong></font></b>
QUERY is running fine in sql , i checked and confirmed
below is the small segment from setter getter class product.java
public void setPname(String pname)
{
this.pname=pname;
}
public String getPname()
{
return pname;
}
public void setPrice(String price)
{
this.price=price;
}
public String getPrice()
{
return price;
}
Move prod.add(p); inside the while loop. As you are not adding object everytime. Also you need to create new object of p in loop everytime.
while(rs.next())
{
product p = new product();
p.setPname(rs.getString(1));
p.setPrice(rs.getString(2));
p.setImg(rs.getString(3));
prod.add(p);
}
you have to remove , from category and product using as
String sql="select product.product_name , product.price , product.image_url "
+ "from category as product "
+ "where product.category_id=category.category_id and product.product_brand like 'LG%'"
or
you also try this one
prod=cs.executeQuery(sql);
Iterator it=prod.iterator;
while(it.next())
{
---------------
}
I use mybatis to perform sql queries in my project. I need to intercept sql query before executing to apply some changed dynamically. I've read about #Interseptors like this:
#Intercepts({#Signature(type= Executor.class, method = "query", args = {...})})
public class ExamplePlugin implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
}
}
And it really intercepts executions, but there is no way to change sql query since appropriate field is not writable. Should I build new instance of whole object manually to just replace sql query? Where is the right place to intercept query execution to change it dynamically? Thank.
I hope it will help you:
#Intercepts( { #Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class
})
})
public class SelectCountSqlInterceptor2 implements Interceptor
{
public static String COUNT = "_count";
private static int MAPPED_STATEMENT_INDEX = 0;
private static int PARAMETER_INDEX = 1;
#Override
public Object intercept(Invocation invocation) throws Throwable
{
processCountSql(invocation.getArgs());
return invocation.proceed();
}
#SuppressWarnings("rawtypes")
private void processCountSql(final Object[] queryArgs)
{
if (queryArgs[PARAMETER_INDEX] instanceof Map)
{
Map parameter = (Map) queryArgs[PARAMETER_INDEX];
if (parameter.containsKey(COUNT))
{
MappedStatement ms = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
BoundSql boundSql = ms.getBoundSql(parameter);
String sql = ms.getBoundSql(parameter).getSql().trim();
BoundSql newBoundSql = new BoundSql(ms.getConfiguration(),
getCountSQL(sql), boundSql.getParameterMappings(),
boundSql.getParameterObject());
MappedStatement newMs = copyFromMappedStatement(ms,
new OffsetLimitInterceptor.BoundSqlSqlSource(newBoundSql));
queryArgs[MAPPED_STATEMENT_INDEX] = newMs;
}
}
}
// see: MapperBuilderAssistant
#SuppressWarnings({ "unchecked", "rawtypes" })
private MappedStatement copyFromMappedStatement(MappedStatement ms,
SqlSource newSqlSource)
{
Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms
.getId(), newSqlSource, ms.getSqlCommandType());
builder.resource(ms.getResource());
builder.fetchSize(ms.getFetchSize());
builder.statementType(ms.getStatementType());
builder.keyGenerator(ms.getKeyGenerator());
// setStatementTimeout()
builder.timeout(ms.getTimeout());
// setParameterMap()
builder.parameterMap(ms.getParameterMap());
// setStatementResultMap()
List<ResultMap> resultMaps = new ArrayList<ResultMap>();
String id = "-inline";
if (ms.getResultMaps() != null)
{
id = ms.getResultMaps().get(0).getId() + "-inline";
}
ResultMap resultMap = new ResultMap.Builder(null, id, Long.class,
new ArrayList()).build();
resultMaps.add(resultMap);
builder.resultMaps(resultMaps);
builder.resultSetType(ms.getResultSetType());
// setStatementCache()
builder.cache(ms.getCache());
builder.flushCacheRequired(ms.isFlushCacheRequired());
builder.useCache(ms.isUseCache());
return builder.build();
}
private String getCountSQL(String sql)
{
String lowerCaseSQL = sql.toLowerCase().replace("\n", " ").replace("\t", " ");
int index = lowerCaseSQL.indexOf(" order ");
if (index != -1)
{
sql = sql.substring(0, index);
}
return "SELECT COUNT(*) from ( select 1 as col_c " + sql.substring(lowerCaseSQL.indexOf(" from ")) + " ) cnt";
}
#Override
public Object plugin(Object target)
{
return Plugin.wrap(target, this);
}
#Override
public void setProperties(Properties properties)
{
}
}
You may consider using a string template library (eg Velocity, Handlebars, Mustache) to help you
As of to date, there is even MyBatis-Velocity (http://mybatis.github.io/velocity-scripting/) to help you to do scripting for the sql.
Depending on the changes you want to make, you may want to use the dynamic sql feature of mybatis 3