SUM result value repeats even with case statement - java

I'm using posgresql as a database and java as programming language with hibernate. My problem is this query:
select cast(sum(CASE WHEN p.nropack > 0 THEN p.nropack ELSE 0 END) as integer),
cast(sum(CASE WHEN p.nropack < 0 THEN p.nropack ELSE 0 END) as integer),
cast(p.fechareg as date)
from pronostico p
inner join aeropuerto a on (a.idaeropuerto=p.idaeropuerto)
inner join ciudad c on (a.idciudad=c.idciudad)
inner join pais ps on (ps.idpais=c.idpais)
inner join continente ct on (ct.idcontinente=ps.idcontinente)
where c.idciudad=105
group by cast (p.fechareg as date);
As a result I get:
sum;sum;fechareg
30;-15;"2012-11-15"
But when I use it in my program:
public ArrayList<RepKardex> listarKardex(int ciud){
ciud=105;
ArrayList<RepKardex> listaKardex = new ArrayList<>();
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
String q = "select cast(sum( case when p.nropack > 0 then p.nropack ELSE 0 end ) as integer), "
+ "cast(sum( case when p.nropack < 0 then p.nropack ELSE 0 end ) as integer), "
+ "cast(p.fechareg as date) "
+ "from Pronostico p "
+ "inner join Aeropuerto a on (p.idaeropuerto = a.idaeropuerto) "
+ "inner join Ciudad c on (a.idciudad = c.idciudad) "
+ "inner join Pais ps on (c.idpais = ps.idpais) "
+ "inner join Continente ct on (ct.idcontinente = ps.idcontinente) "
+ "where c.idciudad = :ciud "
+ "group by cast(p.fechareg as date) ";
Query query = session.createSQLQuery(q);
query.setInteger("ciud", ciud);
List lista = query.list();
Iterator iter = lista.iterator();
while (iter.hasNext()) {
Object[] row = (Object[]) iter.next();
if (row!=null){
System.out.println("entrantes : "+(Integer)row[0]);
System.out.println("salientes : "+(Integer)row[1]);
RepKardex rep = new RepKardex((int)row[0],(int)row[1],(Date)row[2]);
listaKardex.add(rep);
}
}
tx.commit();
session.close();
return listaKardex;
}
It prints
entrantes: 30
salida: 30
Can someone help me figure out why it repeats the positive numbers even when I use the case statement inside the query? Thanks in advance.

You can simplify your query with LEAST and GREATEST:
SELECT sum(GREATEST(p.nropack, 0))::int AS entrantes
,sum(LEAST(p.nropack, 0))::int AS salida
,p.fechareg::date AS fechareg
from pronostico p
JOIN aeropuerto a ON a.idaeropuerto = p.idaeropuerto
JOIN ciudad c ON c.idciudad = a.idciudad
JOIN pais ps ON ps.idpais = c.idpais
JOIN continente ct ON ct.idcontinente = ps.idcontinente
where c.idciudad = 105
GROUP BY p.fechareg::date;
Other than that it looks just fine. I see no way the second column could return a positive number. Something else must go wrong here.
Edit:
Comment by #hvd helped to find that the client code seems to get confused by identical column names (both sum columns defaulted to "sum"). Explicit column aliases seem to fix this.

Related

An expression of non-boolean type specified in a context where a condition is expected. SQL not returning values when executed through API

I have query that returns a result when executed in the database. But it does not return anything when I execute it from my application, it just keep on executing.
Below is the code snippet I have:
#Query(value = "select distinct c.ROWID_OBJECT, rc.CMPNY_NMBR from ecm_ors.dbo.c_b_pty rc " +
"left join ecm_ors.dbo.c_b_pty_rel rel on rc.ROWID_OBJECT = rel.PTY_ID_1 " +
"left join ecm_ors.dbo.c_b_pty c on rel.PTY_ID_2 =?1 " +
"where rc.PTY_ROLE = 'L' and c.PTY_ROLE = 'L' and rel.REL_TP = 'is parent of' " +
"and rc.HUB_STATE_IND = 1 and rel.HUB_STATE_IND = 1 and c.HUB_STATE_IND = 1 " +
"AND ?2 IS NULL OR c.CMPNY_NMBR =?2 AND rel.PTY_ID_2 = c.ROWID_OBJECT", nativeQuery = true)
List<Object[]> getCompanyList(String ptyId, String cmpNumber);
The same query shows the result when run it through the database
select distinct c.ROWID_OBJECT, rc.CMPNY_NMBR from ecm_ors.dbo.c_b_pty rc
left join ecm_ors.dbo.c_b_pty_rel rel on rc.ROWID_OBJECT = rel.PTY_ID_1
left join ecm_ors.dbo.c_b_pty c on rel.PTY_ID_2 = 493
where rc.PTY_ROLE = 'L' and c.PTY_ROLE = 'L' and rel.REL_TP = 'is parent of'
and rc.HUB_STATE_IND = 1 and rel.HUB_STATE_IND = 1 and c.HUB_STATE_IND = 1
and 02637 is null or c.CMPNY_NMBR =02637
and rel.PTY_ID_2 = c.ROWID_OBJECT
The problem I'm anticipating in this condition
?2 IS NULL OR c.CMPNY_NMBR =?2
Is it the kind of error:
An expression of non-boolean type specified in a context where a condition is expected
I'm not seeing any errors though, REST call keep rotates.
Not sure how to rectify this, please advice.

Loading x rows from database at a time, showing them, loading next x rows and so on

I have a database with multiple tables, each having millions of rows of data. In my Java appliaction, my task is to display certain data from certain tables depending on the arguments which I get from the user. I have successfully been able to load all of this data at once, but when there are 10 million rows, it takes a long time. I have found out about connection.setAutoCommit(false) and statement.setFetchSize(x), but these don't seem to work.
public static int getTableResults(Result_Controller okno){
int i = 0;
try {
Connection con = getConnection();
con.setAutoCommit(false);
String query = "SELECT h.\"Nazov hotela\", k.\"Nazov krajiny\", m.\"Nazov mesta\", h.\"Adresa hotela\", h.\"Hviezdicky\", p.\"Cena pobytu\", i.\"Typ izby\", h.\"Pocet izieb\" " +
"FROM hotel h " +
"inner JOIN izba i ON i.\"ID hotela\" = h.\"ID hotela\" " +
"inner JOIN krajina k ON k.\"ID krajiny\" = h.\"ID krajiny\" " +
"inner JOIN mesto m ON m.\"ID mesta\" = h.\"ID mesta\" " +
"inner JOIN pobyt p ON p.\"ID hotela\" = h.\"ID hotela\" " +
"WHERE h.\"Nazov hotela\" = ? " +
"AND k.\"Nazov krajiny\" = ? " +
"AND h.\"Hviezdicky\" = ? " +
"AND i.\"Pocet posteli\" >= ? " +
"AND p.\"Cena pobytu\" <= ? " +
"ORDER BY h.\"Nazov hotela\"";
PreparedStatement pst = con.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
pst.setFetchSize(150);
pst.setString(1, okno.getText_nazov().getText());
pst.setString(2, (String) okno.getKrajina().getValue());
int pocet_hviezdiciek = Integer.parseInt((String) okno.getHviezdicky().getValue());
pst.setInt(3, pocet_hviezdiciek);
int pocet_osob = Integer.parseInt((String) okno.getOsoby().getValue());
pst.setInt(4, pocet_osob);
double cena_pobytu = Double.parseDouble(okno.getText_cena().getText());
pst.setDouble(5, cena_pobytu);
ResultSet rs = pst.executeQuery();
System.out.println(pst);
while (rs.next()) {
okno.getOblist().add(new Vysledok_hladania(rs.getString("Nazov hotela"),
rs.getString("Nazov krajiny"),
rs.getString("Nazov mesta"),
rs.getString("Adresa hotela"),
rs.getInt("Hviezdicky"),
rs.getDouble("Cena pobytu"),
rs.getString("Typ izby"),
rs.getInt("Pocet izieb")));
System.out.println(i++);
}
okno.getTable().setItems(okno.getOblist());
} catch (SQLException ex) {
Logger.getLogger(Result_Controller.class.getName()).log(Level.SEVERE, null, ex);
}
return i;
}
All in all I want to get these results and display them in batches, not all at the same time.
You don't show the execution plan, but the problem must be the ORDER BY. PostgreSQL needs the complete result before it can begin to sort.
You may be able to get a “fast start-up” plan with a nested loop if you create the following index:
CREATE INDEX ON hotel ("Nazov hotela");
In addition, you need to have an index for the join conditions (the ID columns) on all other tables:
CREATE INDEX ON izba ("ID hotela");
CREATE INDEX ON krajina ("ID krajiny");
CREATE INDEX ON mesto ("ID mesta");
CREATE INDEX ON pobyt ("ID hotela");

hibernate native query variable

I am trying to write native query:
#NamedNativeQuery(name = "getUncheckedTests",
query = "SELECT t.test_name AS test_name, q.question AS question, #counter \\:= COUNT(ua.is_checked=0) AS uncheckedAnswers FROM user_answer ua" +
" JOIN result r on r.id = ua.result_id" +
" JOIN test t on r.test_id = t.id" +
" JOIN question q on ua.question_id = q.id" +
" WHERE r.is_checked = false AND q.is_open = true AND ua.is_checked = false" +
" AND r.test_id IN (SELECT t.id FROM result r" +
" JOIN test t on t.id = r.test_id" +
" JOIN user u on u.id = r.user_id" +
" WHERE r.permission = 2 AND u.id = :userId) and r.permission = 1 and #counter > 0" +
" GROUP BY ua.question_id")
However, i am getting empty result as #counter > 0 does not work properly. I can execute this query right in Workbench, however no result if it's put in Hibernate as native query
You should probably check the actual SQL Hibernate executes by enabling logging of the statements or by using log4jdbc and make sure you execute the query with the proper parameters.

From List to int. Unable to convert a query result

I have this query:
select count(*) from {Order as or join CustomerOrderStatus as os on
{or:CustomerOrderStatus}={os:pk} join OrderEntry as oe on
{or.pk}={oe.order} join PurchaseAmount as pa on
{or.pointOfSale}={pa.purchaseAmountOwner} join PurchaseAmountTimeSlice
as ts on {pa.pk}={ts.purchaseamount}} where {or:company} in
(8796093710341) and {or:pointOfSale} in (8796097413125)
I have this code in Java to retrieve result:
FlexibleSearchQuery query = new FlexibleSearchQuery(queryBuilder.toString());
List<Integer> result = new ArrayList<Integer>();
result = getFlexibleSearchService().<Integer> search(query).getResult();
I want to take the int value of the count from the result list.
If I write result.get(0) I obtain an error IllegalArgumentException:
java.lang.IllegalArgumentException: invalid pks [4] - unknown typecode 0
at de.hybris.platform.core.WrapperFactory.getCachedItems(WrapperFactory.java:304)
at de.hybris.platform.core.LazyLoadItemList.loadPage(LazyLoadItemList.java:230)
at de.hybris.platform.servicelayer.search.impl.LazyLoadModelList.loadPage(LazyLoadModelList.java:60)
at de.hybris.platform.core.LazyLoadItemList.switchPage(LazyLoadItemList.java:219)
at de.hybris.platform.core.LazyLoadItemList.switchBufferedPageNoLock(LazyLoadItemList.java:475)
at de.hybris.platform.core.LazyLoadItemList.switchBufferedPageSynchronized(LazyLoadItemList.java:467)
at de.hybris.platform.core.LazyLoadItemList.switchBufferedPage(LazyLoadItemList.java:462)
at de.hybris.platform.core.LazyLoadItemList.getOrSwitchBufferedPage(LazyLoadItemList.java:453)
at de.hybris.platform.core.LazyLoadItemList.getOrSwitchBufferedPage(LazyLoadItemList.java:433)
at de.hybris.platform.core.LazyLoadItemList.getBuffered(LazyLoadItemList.java:111)
at de.hybris.platform.core.LazyLoadItemList.get(LazyLoadItemList.java:97)
at java.util.AbstractList$Itr.next(AbstractList.java:358)
at de.hybris.platform.core.internal.BaseLazyLoadItemList$1.next(BaseLazyLoadItemList.java:180)
at java.util.AbstractCollection.toArray(AbstractCollection.java:195)
at java.util.Collections$UnmodifiableCollection.toArray(Collections.java:1059)
How I can get the int value?
Replace count(*) with count({or:Pk}) and set result class of flexible search query to Integer like this query.setResultClassList(Collections.singletonList(Integer.class));
I resolved in this way:
private FlexibleSearchService flexibleSearchService;
#Override
public void onValidate(PurchaseAmountTimeSliceModel paramMODEL, InterceptorContext paramInterceptorContext)
throws InterceptorException {
//.....
final StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append("select {ts.pk}");
queryBuilder.append(
" from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk} join OrderEntry as oe on {or.pk}={oe.order} ");
queryBuilder.append(
"join PurchaseAmount as pa on {or.pointOfSale}={pa.purchaseAmountOwner} join PurchaseAmountTimeSlice as ts on {pa.pk}={ts.purchaseamount}} where ");
if (pointOfSale != null && company != null) {
queryBuilder.append("{or:company} in (" + company.getPk() + ") and {or:pointOfSale} in ("
+ pointOfSale.getPk() + ")");
}
FlexibleSearchQuery query = new FlexibleSearchQuery(queryBuilder.toString());
SearchResult<PurchaseAmountTimeSliceModel> result = flexibleSearchService.search(query);
if (result != null) {
if (result.getCount() >= 10) {
LOG.error("There's already 10 purchase amount time slices configured. You reached the limit.");
throw new InterceptorException(
"There's already 10 purchase amount time slices configured. You reached the limit.");
}
}
//.....
The solution is similar ;)

Optimizing a query using Stored Procedure

I am optimizing a code written a long time ago by a developer that I never met. I came across a method that requires modification. The first thing that came to mind is to use stored procedure. Maybe there are better ways of achieving this hence this question.
The code goes this way:
public void execute()
{
String query = "select a, b, e from table1";
....
ResultSet rs = stmt.executeQuery(query);
String query2 = null;
List<Integer> list1 = ....
List<Integer> list2 = ....
while(rs.next)
{
query2 = "select count(*) as rowcount from vw_view1 where f='" + rs.getString("a") + "' and d='" + rs.getString("b") + "'";
.....
ResultSet rs2 = stmt2.executeQuery(query2);
list1.add(rs2.getInt(rowcount));
query3 = "select count(*) as rowcount from vw_view1 where c='" + rs.getString("a") + "' and e='" + rs.getString("e") + "'";
.....
ResultSet rs3 = stmt3.executeQuery(query3);
list2.add(rs3.getInt(rowcount));
}
}
Apart from using a stored procedure, is there a better way of avoiding unnecessary trips to the database in this method.
Try this query, check if it gives you the same result. With this you should have in one query directly all the value you wanted
SELECT c,
SUM(CASE WHEN vw1.d = tb1.b THEN 1 ELSE 0 END) as rowcountListOne,
SUM(CASE WHEN vw1.e = tb1.e THEN 1 ELSE 0 END) as rowcountListTwo
from vw_view1 vw1
left join table1 tb1 on vw1.c=tb1.a
GROUP BY c
In the new case you posted you should actually join by c and f:
SELECT c, f,
SUM(CASE WHEN (vw1.d = tb1.b) AND (vw1.f=tb1.a) THEN 1 ELSE 0 END) as rowcountListOne,
SUM(CASE WHEN (vw1.e = tb1.e) AND (vw1.c=tb1.a) THEN 1 ELSE 0 END) as rowcountListTwo
FROM vw_view1 vw1
LEFT JOIN table1 tb1 on (vw1.c=tb1.a OR vw1.f=tb1.a)
GROUP BY c, f
You should check also what Lennart said about COUNT, I think I should add on those case some NULL management, but I can't test it right now.
Maybe is enough if you check vw1.f not null in the case (and vw1.c in the other):
CASE WHEN (vw1.f IS NOT NULL) AND (vw1.d = tb1.b) AND (vw1.f=tb1.a) THEN 1 ELSE 0 END
You could just perform the counts at the same time as your initial select, removing the need to run two further queries for every row in rs:
SELECT t.a, t.b, t.e, t1.RowCount1, t2.RowCount2
FROM table1 AS t
LEFT JOIN
( SELECT c, d, COUNT(*) AS RowCount1
FROM vw_view1
GROUP BY c, d
) AS t2
ON t2.c = t.a
AND t2.d = t.b
LEFT JOIN
( SELECT c, e, COUNT(*) AS RowCount2
FROM vw_view1
GROUP BY c, e
) AS t3
ON t3.c = t.a
AND t3.e = t.e;
The initial select will be slower, but the subsequent loop will be much more efficient.

Categories