I am using "with data as" as in below query. When I run this in sql developer, it's executing fine, but in java code when I call the query as normal string or through jdbc template in xml configuration file, it gives me bad SQL grammar. Is there any alternative to the below query?
public class NppGWOrphanMessageDao extends DefaultDao {
String sql = "same sql as i posted"
private String replayGWOrphanMsgSQL;
public void setReplayGWOrphanMsgSQL(String replayGWOrphanMsgSQL) {
this.replayGWOrphanMsgSQL = replayGWOrphanMsgSQL;
}
public String getReplayGWOrphanMsgSQL() { return replayGWOrphanMsgSQL; }
public List<Map<String, Object>> getReplayList(HashMap<String, Object> epoch) {
return retrieveAll(replayGWOrphanListSQL, params);
return retrieveAll(sql, epoch); }
}
WITH DATA AS (
SELECT GLOB.ID, GLOB.CHARACTERS
FROM GW_LOB_STORE GLOB
WHERE
NOT EXISTS(SELECT 1 FROM GW_NPP_MSG_INTEGRITY M WHERE M.LOB_STORE_ID=GLOB.ID)
AND NOT EXISTS(SELECT 1 FROM GW_NPP_SAFE_STORE S WHERE S.LOB_STORE_ID=GLOB.ID)
AND NOT EXISTS(SELECT 1 FROM GW_POISON_LOG P WHERE P.LOB_STORE_ID=GLOB.ID)
AND GLOB.CREATED_TS > = :epoch)
SELECT
A.ID AS "GLOBID",
INQUEUEDTL.ID AS "INQUEID",
A.CHARACTERS AS "REQUESTBODY",
INQUEUEDTL.ENDPOINT_ID AS "ENDPOINTID",
INQUEUEDTL.HEADER AS "HEADERS"
FROM DATA A, GW_IN_QUEUE_DETAIL INQUEUEDTL
WHERE A.ID=INQUEUEDTL.ID;
For the sake of completeness:
The problem with this query is the ; at the end of it.
Oracle JDBC driver does not handle it well.
Related
I am trying to do "sql interpreter" in my web-app, only for CRUD. Everything work fine, I am using method prepareStatement() to execute query. But I have problem with operation select :
When I use the select operation only for 1 field, then parsing to a string gives a fairly good result:
for(String x: resultList){
System.out.println(x);
}
Is there any way to execute:
SELECT field_1, field_2, field_3 FROM table;
and print result in console, with some neat form without use Entites?
Well if it isn't possible, is there any way to generate entity "on the fly"? I mean generate Entities using java code.
You could use a native query and explicitly specify which columns you want to select:
String sql = "SELECT field_1, field_2, field_3 FROM table";
Query q = em.createNativeQuery(sql);
List<Object[]> results = q.getResultList();
for (Object[] r : results) {
System.out.println("(field_1, field_2, field_3) = (" + r[0] + ", " + r[1] + ", " + r[2] + ")");
}
With Spring Data JPA Projections
If you already use some entities and Spring Repository then you can add this code to one of them. Thanks Spring Data JPA Projections.
public interface SomeEntityRepository extends Repository<SomeEntity, Long> {
#Query(value = "SELECT field_1, field_2, field_3 FROM table", nativeQuery = true)
List<TableDto> getFromTable();
}
Where TableDto:
public interface TableDto{
Long getField_1();
String getField_2();
String getField_3();
}
With Spring JdbcTemplate
Or use Spring JdbcTemplate:
String query = "SELECT field_1, field_2, field_3 FROM table where id = ?";
List<TableDto> resluts = jdbcTemplate.queryForObject(
query, new Object[] { id }, new TableDtoRowMapper());
public class TableDtoRowMapper implements RowMapper<TableDto> {
#Override
public TableDtomapRow(ResultSet rs, int rowNum) throws SQLException {
TableDto dto = new TableDto();
dto.setField_1(rs.getString("field_1"));
dto.setField_2(rs.getString("field_2"));
dto.setField_3(rs.getString("field_3"));
return dto;
}
}
In this example TableDto is real class with getters and setters.
I'm testing a Dao with an In-Memory DB with H2. I'm passing an int to the query with a map to execute it. This query is working OK on Oracle SQL, but is not succeding in H2.
DAO
#Override
public int deleteCancelled(int days) {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put(DAYS, days);
namedParameters.put(STATUS, StatusEnum.CANCELLED.toString());
int updated = this.namedParameterJdbcTemplate.update(Query.QUERIES.DELETE_CANCELLED, namedParameters);
return updated;
}
QUERIES
public static final String DELETE_CANCELLED = "DELETE FROM MY_TABLE "
+ "WHERE UPDATE_TS < SYSDATE - :days AND STATUS = :status";
When I try to execute this query on H2, it returns:
Error
org.springframework.jdbc.UncategorizedSQLException:
PreparedStatementCallback; uncategorized SQLException for SQL [DELETE FROM
MY_TABLE WHERE UPDATE_TS < SYSDATE - ? AND STATUS = ?]; SQL state
[HY004]; error code [50004]; Unknown data type : "?"
Unknown data type: "?"; SQL statement:
DELETE FROM MY_TABLE WHERE UPDATE_TS < SYSDATE - ? AND STATUS = ?
[50004-196]; nested exception is org.h2.jdbc.JdbcSQLException: Unknown data
type : "?"
Unknown data type: "?"; SQL statement:
DELETE FROM MY_TABLE WHERE UPDATE_TS < SYSDATE - ? AND STATUS = ?
[50004-196]
I tried to execute the query hardcoding the int in the query (SYSDATE = 4) and it worked, also tried to wrap primitive int into Integer.valueOf(days) and using MapSqlParameterSource to specify which data type is, but none of both worked.
Why is it not working? Anyone knows? Thanks in advance.
EDIT:
StatusEnum
public enum StatusEnum {
CANCELLED("Cancelled"),
CONFIRMED("Confirmed"),
PENDING("Pending"),
SENT("Sent"),
private final String text;
/**
* #param text
*/
private StatusEnum(final String text) {
this.text = text;
}
/* (non-Javadoc)
* #see java.lang.Enum#toString()
*/
#Override
public String toString() {
return text;
}
}
This exception appears to arise because H2 is trying to type-check the statement at compile time and can't uniquely determine the type of the parameter: it could be a date or it could be a number, or perhaps something else.
The workaround (provided in the GitHub issue I raised) is to replace
SYSDATE - ?
with
SYSDATE - CAST(? AS INTEGER)
I've checked this and it works on both H2 and Oracle.
For integer param (Spring data) there is workaround: embrace parameter and add 0:
#Query(value = "DELETE FROM my_table WHERE update_ts < SYSDATE - (:days + 0)")
void cleanup(#Param("days") Integer days);
I'm using namedQuery and this Worked for me. if it can help others.
CAST(:variable AS double)
It must be lowercase to respect hibernate types:
https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/#mapping-types-basictypes
the solution of #Luke is working but I had to change to lowercase
This is my function to get all rows from table player.
public List<Player> getAllPlayer() {
String sql = "SELECT * FROM PLAYER";
List<Player> lstPlayers = getJdbcTemplate().query(
sql, new BeanPropertyRowMapper(Player.class)
);
return lstPlayers;
}
I want to get data from another table 'student' using this same function.
Is it possible to get data from both table using same function by changing the
above code something like below ?
public List<Object> getData(String TableName) {
String sql = "SELECT * FROM " + TableName;
List<Object> lstPlayers = getJdbcTemplate().query(
sql, new BeanPropertyRowMapper(Object.class)
);
return lstPlayers;
}
You could do something like the following
List<Player> players = getData(Player.class);
List<Student> students = getData(Student.class);
public List<T> getData(Class<T> clazz) {
String sql = "SELECT * FROM " + clazz.getSimpleName();
List<T> lstPlayers = getJdbcTemplate().query(
sql,
new BeanPropertyRowMapper(clazz));
return lstPlayers;
}
However in real life there's not much advantage. It's not that common to want to load all the contents of a database table at once due to performance and other reasons, so this method won't be as helpful as you think.
I am using Java and SQLBuilder from http://openhms.sourceforge.net/sqlbuilder/ and am trying to build SQL SELECT query dynamicly:
SelectQuery sql = new SelectQuery();
sql.addAllColumns().addCustomFromTable("table1");
sql.addCondition(BinaryCondition.like("column1", "A"));
However, it creates string like this:
SELECT * FROM table1 WHERE ('column1' LIKE 'A')
Because of wrong quotes ('column1') it doesn't work properly. I suppose it expects some Column object in .like() method.
Is there any way to create query with proper quotes?
I've found a solution. I had to create new class Column that extends CustomSql and pass my column name as parameter:
public class Column extends CustomSql {
public Column(String str) {
super(str);
}
}
And then:
SelectQuery sql = new SelectQuery();
sql.addAllColumns().addCustomFromTable("table1");
sql.addCondition(BinaryCondition.like(new Column("column1"), "A"));
Or without creating own class:
SelectQuery sql = new SelectQuery();
sql.addAllColumns().addCustomFromTable("table1");
sql.addCondition(BinaryCondition.like(new CustomSql("column1"), "A"));
It creates following SQL query, which works fine:
SELECT * FROM table1 WHERE (column1 LIKE 'A')
BinaryCondition.like() takes Object which is a Column Object and then it is converted to SqlObject using Converter.toColumnSqlObject(Object) internally . There is a method named findColumn(String columnName) and findSchema(String tableName) in Class DbTable and Class DbSchemarespectively where you can pass a simple String Object. Try this it would solve your problem:
DbTable table1= schema.findSchema("table1");
DbColumn column1 = table1.findColumn("column1");
SelectQuery sql = new SelectQuery();
sql.addAllColumns().addCustomFromTable(table1);
sql.addCondition(BinaryCondition.like(column1, "A"));
Please, check the working example and refactor your own query
String query3 =
new SelectQuery()
.addCustomColumns(
custNameCol,
FunctionCall.sum().addColumnParams(orderTotalCol))
.addJoins(SelectQuery.JoinType.INNER, custOrderJoin)
.addCondition(BinaryCondition.like(custNameCol, "%bob%"))
.addCondition(BinaryCondition.greaterThan(
orderDateCol,
JdbcEscape.date(new Date(108, 0, 1)), true))
.addGroupings(custNameCol)
.addHaving(BinaryCondition.greaterThan(
FunctionCall.sum().addColumnParams(orderTotalCol),
100, false))
.validate().toString();
Look at this library JDSQL (It requires Java 8):
JQuery jquery = new JQuery();
Collection<Map<String, Object>> result = jquery.select("tbl1::column1", "tbl2::column2") //Select column list
.from("Table1" , "TB1") // Specifiy main table entry, and you can add alias
.join("Table2::tb2") // Provide your join table, and another way to provide alias name
.on("tbl1.key1", "tbl2.key1") // your on statement will be based on the passed 2 values equaliy
.join("Table3", "tbl3", true) // Join another table with a flag to enable/disable the join (Lazy Joining)
.on("tbl2.key2", "tbl3.key1", (st-> {st.and("tbl3.condition = true"); return st;}))
.where("tbl1.condition", true, "!=") // Start your where statment and it also support enable/disable flags
.and("tbl2.condition = true", (st-> {st.or("tbl.cond2", 9000, "="); return st;})) // And statment that is grouping an or inside parentheses to group conditions
.and("tbl3.cond3=5", false) // And statment with a flag to enable/disable the condition
.get((String sql, Map<String, Object> parameters)-> getData(sql, parameters)); // Passing the hybrid getter.
//You can also assign the getter at the jqueryobject itself by calling setGetter.
}
private static Collection<Map<String, Object>> getData(String sql, Map<String, Object> parameters){
return null;
}
}
I was trying to get all the details of a sql query. If I provide the query "SELECT a,b FROM TAB1 INNER JOIN TAB2 ON TAB1.a=TAB2.b WHERE a>5", then its working fine. But when it's "SELECT a,b FROM Tab" then it throws exception "java.lang.NullPointerException".
The corresponding code is,
public class ParseJSQLService implements ParseJSQLServiceInterface
{
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
#Override
public QueryDetails parseSqlDetails(QueryDetails queryDetails) throws JSQLParserException
{
CCJSqlParserManager parserManager = new CCJSqlParserManager();
String sql=queryDetails.getQueryText();
Statement statement=parserManager.parse(new StringReader(sql));
String joinType="";
if(statement instanceof Select)
{
Select selectstatement=(Select) statement;
System.out.println(selectstatement);
PlainSelect plainSelect=(PlainSelect) selectstatement.getSelectBody();
String fromItems=plainSelect.getFromItem().toString();
String fieldItems=plainSelect.getSelectItems().toString();
System.out.println("fromItems====>"+fromItems);
System.out.println("fieldItems====>"+fieldItems);
List tableList=tablesNamesFinder.getTableList(selectstatement);
System.out.println(tableList.size());
System.out.println(tableList.toString());
joinType=plainSelect.getJoins().toString();
System.out.println("joinType====>"+joinType);
}
}
The problem is that JSQLParser finds in your second SQL no joins. Therefore plainSelect.getJoins() delivers null. Thats why plainSelect.getJoins().toString() throws a NullPointerException. A slightly modification will make your code work with the second SQL as well.
if (plainSelect.getJoins() != null) {
joinType = plainSelect.getJoins().toString();
System.out.println("joinType====>" + joinType);
}