H2 user-defined function is called many times - java

I'm using the h2 v1.3.176.
I have user-defined function which execute RECURSIVE query.
public static ResultSet getChildCategories(Connection connection, long categoryId) throws SQLException {
String sql =
"WITH RECURSIVE r(CATEGORY_ID, PARENT_ID) AS (\n" +
" SELECT CATEGORY_ID\n" +
" ,PARENT_ID\n" +
" FROM CATEGORY\n" +
" WHERE CATEGORY_ID = " + categoryId + "\n" +
" UNION ALL\n" +
" SELECT CATEGORY.CATEGORY_ID\n" +
" ,CATEGORY.PARENT_ID\n" +
" FROM CATEGORY, r\n" +
" WHERE CATEGORY.PARENT_ID = r.CATEGORY_ID\n" +
")\n" +
"SELECT CATEGORY_ID FROM r";
ResultSet resultSet = connection.createStatement().executeQuery(sql);
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("CATEGORY_ID", Types.INTEGER, 12, 0);
try {
while(resultSet.next()) {
rs.addRow(resultSet.getLong(1));
}
} finally {
resultSet.close();
}
return rs;
}
I have registered this function by following SQL.
create alias GET_CHILD_CATEGORIES for "com.myapp.db.function.Functions.getChildCategories";
My problem is the getChildCategories function will be called many times when I execute the following query.
SELECT DISTINCT B.BOOK_ID
,B.SERIES_ID
,B.TITLE
,B.ISBN
,B.VOLUME
,(
SELECT MAX(SAME_SERIES.VOLUME)
FROM BOOK SAME_SERIES
WHERE SAME_SERIES.SERIES_ID = B.SERIES_ID
AND SAME_SERIES.VOLUME IS NOT NULL
) AS VOLUME_COUNT
,B.PAGE_COUNT
,B.FILE_PATH
,B.SORTABLE_FILE_NAME
,B.SIZE
,B.HASH
,B.COVER_IMAGE_TYPE
,B.COVER_PAGE_NO
,B.COVER_LARGE_IMAGE_URL
,B.COVER_SMALL_IMAGE_URL
,B.COVER_CROP_COORD
,B.IS_ENCRYPT
,B.PUBLISHER_ID
,B.PUBLISHED_DATE
,B.CREATION_TIME
,B.LAST_MODIFIED_TIME
,B.NOTE
,B.IS_ISBN_SEARCH
,S.CATEGORY_ID
,S.TITLE
,BA.AUTHOR_ID
,BT.TAG_ID
FROM BOOK AS B
INNER JOIN SERIES AS S ON S.SERIES_ID = B.SERIES_ID
LEFT OUTER JOIN BOOK_TAG AS BT ON BT.BOOK_ID = B.BOOK_ID
LEFT OUTER JOIN BOOK_AUTHOR AS BA ON BA.BOOK_ID = B.BOOK_ID
WHERE
(
S.CATEGORY_ID IN (SELECT CATEGORY_ID FROM GET_CHILD_CATEGORIES(106))
And
S.IS_COMPLETION = 1
)
ORDER BY BA.AUTHOR_ID
Why do many times would be called this function?

Extracted from H2 documentation
A function that returns a result set can be used like a table.
However, in this case the function is called at least twice: first
while parsing the statement to collect the column names (with
parameters set to null where not known at compile time). And then,
while executing the statement to get the data (maybe multiple times if
this is a join). If the function is called just to get the column
list, the URL of the connection passed to the function is
jdbc:columnlist:connection. Otherwise, the URL of the connection is
jdbc:default:connection.
The first calls are only to retrieve the resultset column types. Then you have to check if the connection url is "jdbc:columnlist:connection". If true you have to return an empty result set with column list.
The connection url test is:
connection.getMetaData().getURL().equals("jdbc:columnlist:connection");

Related

how to create temp table using jdbc java

I need to create a temp table in order to store some ids which i will process under a later query. I am receiving error
com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.
When i execute my query for the creation of #temp table inside my sql. I don't need any resultset from this execution just need to create a temporary table with records. Please guide.
Code for my main query:
String queryTempTable = "SELECT TOP (2) A.Id INTO #temp\n" +
"FROM SALESDM.dbo.FactSales A\n" +
"INNER JOIN SALESDM2.dbo.FactSales B\n" +
"ON A.Id = B.Id\n" +
"AND (\n" +
" A.sysDateModified = B.sysDateModified\n" +
" OR A.Id = B.Id\n" +
" OR A.ModifiedDatetime = B.ModifiedDatetime\n" +
" )";
System.out.println(queryTempTable);
if (conn == null) {
System.out.println("Unable to create Connection");
} else {
Statement stmtTempTable = conn.createStatement();
stmtTempTable.executeQuery(queryTempTable);
}
You should use executeQuery only when you are retrieving data and want a ResultSet.
If you are modifying data, then you should use execute:
stmtTempTable.execute(queryTempTable);
If possible create a view using the given query? This will act as a temporary table. And call the view later based on your requirement.

MySQL JDBC Fail calculating row number

I have this select that works every time running in workbench but fails sometimes for the same arguments over jdbc. The problem is that sometimes, over JDBC, 'pos' value returns null. I Think that, for some reason, the #p as not started, but dont know how to fix.
SELECT t1.wId, t1.twId, t1.name, t1.timeout, t1.pos
FROM (
SELECT w.id AS wId, tw2.id AS twId, w.name AS name, tw2.timeout AS timeout, #p:=#p+1 AS pos
FROM timeout_workqueue tw1
INNER JOIN timeout_workqueue tw2
ON tw1.workqueue_id = tw2.workqueue_id
INNER JOIN workqueue w
ON tw1.workqueue_id = w.id
WHERE tw1.id = ?
ORDER BY tw2.id) t1, (SELECT #p:=1) c
WHERE t1.twId = ?;
The whole Java Code Are:
public TimeoutWorkqueueView getTimeoutWorkqueueView(Integer id) {
String sql = "SELECT t1.wId, t1.twId, t1.name, t1.timeout, t1.pos"
+ " FROM ("
+ " SELECT w.id AS wId, tw2.id AS twId, w.name AS name, tw2.timeout AS timeout, #p:=#p+1 AS pos"
+ " FROM timeout_workqueue tw1"
+ " INNER JOIN timeout_workqueue tw2"
+ " ON tw1.workqueue_id = tw2.workqueue_id"
+ " INNER JOIN workqueue w"
+ " ON tw1.workqueue_id = w.id"
+ " WHERE tw1.id = ?"
+ " ORDER BY tw2.id) t1, (SELECT #p:=1) c"
+ " WHERE t1.twId = ?";
return (TimeoutWorkqueueView) getJdbcTemplate().queryForObject(sql, new BeanPropertyRowMapper(TimeoutWorkqueueView.class), id, id);
}
Ok so the problem i can see here (please verify) is that you think you are running the query with parameter set to 1 to begin with.
However if you set #p = 1 -> this #p:=#p+1 will not evaluate to 1 any more.
Also assuming you have 20 rows, you run this query 20 times but on the last run it will return null because pos will be 21 and this does not exists.

Cannot get my Query to execute in my DAO. Always returns null

I had a small issue updating a query to link with my DAO.
Here is my Query:
String PROJECT_ID_QUERY_BY_RAB_WWID = "SELECT PR.ID FROM PR "
+ "LEFT OUTER JOIN PROJECT ON PR.PROJECT_ID = PROJECT.ID "
+ "LEFT OUTER JOIN TW_V_WWID ON PR.ID = TW_V_WWID.PR_ID "
+ "LEFT OUTER JOIN PR_STATUS_TYPE ON PR_STATUS_TYPE.ID = PR.STATUS_TYPE "
+ "LEFT OUTER JOIN TW_V_SITE_NAME_S ON PR.ID = TW_V_SITE_NAME_S.PR_ID "
+ "WHERE PROJECT.NAME = 'Site Lead' "
+ "and TW_V_WWID.S_VALUE = (SELECT PERSON_RELATION.S_EXTERNAL_ID FROM TW_V_ROLES_APPROVED_BY "
+ "left outer join person_relation on tw_v_roles_approved_by.id = person_relation.id "
+ "WHERE TW_V_ROLES_APPROVED_BY.PR_ID IN ?) and "
+ "(TW_V_SITE_NAME_S.S_VALUE IN (SELECT TW_V_SITE_NAME.S_VALUE FROM TW_V_SITE_NAME "
+ "left outer join tw_v_site_name_s on tw_v_site_name_s.pr_id = tw_v_site_name.pr_id "
+ "where tw_v_site_name.pr_id in ?) or tw_v_site_name_s.s_value = 'ALL SITES') "
+ "and PR_STATUS_TYPE.NAME = 'Approved Site Lead Permissions'";
As you can see there are two ?. These two ? are actually going to be the same.
This is my DAO class to call this Query:
public Integer getProjectID(Integer UA_PrID)
throws SQLException, IOException {
Integer prId = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(QueryConstants.PROJECT_ID_QUERY_BY_RAB_WWID);
ps.setLong(1, UA_PrID);
ps.setLong(2, UA_PrID);
rs = ps.executeQuery();
while (rs.next()) {
prId = rs.getInt("ID");
}
} finally {
DaoUtil.cleanUp( ps, rs);
}
return prId;
}
As you can see my PS statements are the same.
I make this call in my Service class to the DAO method:
Integer prId = userAccessVerificationDAO.getProjectID(wsdlDtoList.get(0).getPrId());
where wsdlDtoList.get(0).getPrId() is an integet value in my DTO class.
Everytime I try and debug this code I get to the DAO file and step over and I notice it skips this line everytime in the DAO:
rs = ps.executeQuery();
I know I am missing something small here. A second set of eyes on this would be great. Please let me know if more information is required in order to solve this minor issue. I thank you all in advance for you input and help.
Here is the larger portion of the service class:
Integer prId = userAccessVerificationDAO.getProjectID(wsdlDtoList.get(0).getPrId());
if (prId == null) {
verificationResponse = new VerificationResponseDto();
verificationResponse.setErrorType(ErrorConstants.VERIFICATION_ERROR_TYPE);
verificationResponse.setErrorCode(ErrorConstants.FAILURE_ERROR_CODE);
verificationResponse.setErrorMessage(ErrorConstants.NO_PR_ID_ERROR);
logger.error(ErrorConstants.NO_PR_ID_ERROR);
verificationResponseDtoList.add(verificationResponse);
return verificationResponseDtoList;
Basically it returns null everytime. I manually ran this query in sqldeveloper and it does return a valid prID.
Thanks
The reason behind the executeQuery getting skipped is because of exception occurring in previous line of code.
In your method, conn object is not initialized(this may be the issue). Also, add a catch block to log the error.

How can I get the alias name for my ResultSet from a Subquery?

I have a problem with getting the alias of the columnnames for my ResultSet.
I made a subquery, where i use the alias function(MAX(...) in SQL) but everytime I execute the Statement, I get java.sql.SQLException because the column name is not valid. And I use the current alias where I call the getString - Function of my ResultSet.
This is my SQL-Statement in Eclipse:
String sql = "SELECT a.steelgrade, a.prod_order_id, a.prod_order_item_pos, "
+"a.prod_order_version, a.strip_thickn_aim, a.strip_width_aim, "
+"a.customer, a.order_weight_plan, b.grund_kommlos, b.coil_weight "
+"FROM (SELECT prod_order_id, prod_order_item_pos, "
+ "MAX (prod_order_version) AS max_version "
+ "FROM production_order "
And in the ResultSet while.next()-Loop:
prod_order_version = AuftraegeProduction.getString("max_version");
This is the whole SQL-Statement( in the Database it works fine!):
SELECT a.steelgrade, a.prod_order_id, a.prod_order_item_pos,
a.prod_order_version, a.strip_thickn_aim, a.strip_width_aim,
a.customer, a.order_weight_plan, b.grund_kommlos, b.coil_weight
FROM (SELECT prod_order_id, prod_order_item_pos,
MAX (prod_order_version) AS max_version
FROM production_order
GROUP BY prod_order_id, prod_order_item_pos) c
JOIN
production_order a
ON a.prod_order_id = c.prod_order_id
AND a.prod_order_item_pos = c.prod_order_item_pos
AND a.prod_order_version = c.max_version
JOIN pps_plan_slab b
ON b.prod_order_id = c.prod_order_id
AND b.prod_order_item_pos = c.prod_order_item_pos
AND b.prod_order_version = c.max_version
WHERE a.strip_thickn_aim > 1.78
AND a.strip_thickn_aim < 3.26
AND a.steelgrade = 'M4R51'
AND a.prod_order_id NOT BETWEEN '0999551' AND '0999599'
AND a.strip_width_aim BETWEEN 1126 AND 1166
AND NVL (a.order_weight_plan, 0) > 0
AND a.order_weight_plan >= b.coil_weight
ORDER BY prod_order_id ASC
Anyone have a suggestion?
Maurice
when using aggregate functions max(),min(),sum(),... you must use group by clause clause.

assigning variable in SQL query statement

In my current project, I have a function with argument (e.g., int badgID in the following code snippet). This function connects with Apache Derby database, creates table (e.g., FIRSTTABLE), then query to FIRSTTABLE table. The query statement uses function argument for query (e.g., ID = $badgeID ). My question:
Is ID = $badgeID the right way from a syntax point of view?. I have tried this case, but it is not working.
public void getprofile (int badgeID) {
// Create connection with Apache-Derby Database.
// Create table in Apache Derby datbase.
String createString = " CREATE TABLE FIRSTTABLE "
+ "(ID INT PRIMARY KEY, "
+ "PREF INT, "
+ " NAME VARCHAR(12))";
// SQL query on table
querystmt = "SELECT * FROM FIRSTTABLE WHERE ID = $badgeID"
}
that's php syntax...
in java you would write
String querystmt = "SELECT * FROM FIRSTTABLE WHERE ID = " + badgeID;

Categories

Resources