I am using jsqlparser to parse a SQL string and replace table names in the string.
My input is
SELECT id, test
FROM test1 JOIN test2
ON test1.aa = test2.bb
WHERE test1.conf = \"test\"
LIMIT 10"
and my goal output is
SELECT id, test
FROM test1_suffix
JOIN test2_suffix
ON test1_suffix.aa = test2_suffix.bb
WHERE test1_suffix.conf = \"test\"
LIMIT 10"
And I managed to replace table name by extend the TablesNamesFinder, but it gave me this:
SELECT id, test
FROM test1_suffix
JOIN test2_suffix
ON test1.aa = test2.bb
WHERE test1.conf = \"test\"
LIMIT 10
I say that's half of the job done, but how can I do the rest of my job?
So here is a complete (hopefully) example to replace all occurances of table names. The problem is, that JSqlParser does not differ between aliases and table names. There has to be some logic to skip aliases of your sqls, if you do not want to correct those.
The usage of TableNamesFinder does not do the full job, because it traverses the AST only as far as it is needed to find table names and stops then. That is why my example uses the deparsers.
This code transforms
select id, test from test where name = "test"
to
SELECT id, test FROM test_mytest WHERE name = "test"
and
select * from t2 join t1 on t1.aa = t2.bb where t1.a = "someCondition" limit 10
to
SELECT * FROM t2_mytest JOIN t1_mytest ON t1_mytest.aa = t2_mytest.bb WHERE t1_mytest.a = "someCondition" LIMIT 10
I think that solves your problem.
public class SimpleSqlParser24 {
public static void main(String args[]) throws JSQLParserException {
replaceTableName("select id, test from test where name = \"test\"");
replaceTableName("select * from t2 join t1 on t1.aa = t2.bb where t1.a = \"someCondition\" limit 10");
}
private static void replaceTableName(String sql) throws JSQLParserException {
Select select = (Select) CCJSqlParserUtil.parse(sql);
StringBuilder buffer = new StringBuilder();
ExpressionDeParser expressionDeParser = new ExpressionDeParser() {
#Override
public void visit(Column tableColumn) {
if (tableColumn.getTable() != null) {
tableColumn.getTable().setName(tableColumn.getTable().getName() + "_mytest");
}
super.visit(tableColumn);
}
};
SelectDeParser deparser = new SelectDeParser(expressionDeParser, buffer) {
#Override
public void visit(Table tableName) {
tableName.setName(tableName.getName() + "_mytest");
super.visit(tableName);
}
};
expressionDeParser.setSelectVisitor(deparser);
expressionDeParser.setBuffer(buffer);
select.getSelectBody().accept(deparser);
System.out.println(buffer.toString());
}
}
Add an alias when parsing that gets used instead of the table name.
SELECT *
FROM test a
WHERE a.conf = 'something'
Then this should be changed to, that is the where clause can be the same
SELECT *
FROM test_suffix a
WHERE a.conf = 'something'
Related
I have various sql requests.For example
SELECT COUNT(project_id) AS 'count', project.name AS 'projects' FROM test
JOIN project ON project_id = project.id
or
SELECT count(*) AS 'browsers' FROM `test`
I want to receive words that are in ''. For example 'count', 'projects', 'browsers'.
Thus, I want to get the names of the columns from the table.But how can I do this, something I don't understand.So far I just wrote
String[] str = sqlRequest.split("FROM");
but what can I write next, I don’t guess. Tell me how you can get words from these brackets?
Don't do this with String split, replace etc. At some point, it will fail.
You should parse the sql statement. Example with JsqlParser like
public class Main {
public static void main(String[] args) throws JSQLParserException {
Select stmt = (Select) CCJSqlParserUtil.parse(
"SELECT COUNT(project_id) AS 'count', project.name AS 'projects' FROM test\n"
+ "JOIN project ON project_id = project.id ");
for (SelectItem selectItem : ((PlainSelect) stmt.getSelectBody()).getSelectItems()) {
selectItem.accept(new SelectItemVisitorAdapter() {
#Override
public void visit(SelectExpressionItem item) {
System.err.println(item.getAlias().getName());
}
});
}
}
}
Output:
'count'
'projects'
You can do it as follow:
String query = "SELECT COUNT(project_id) AS 'count', project.name AS 'projects' FROM test JOIN project ON project_id = project.id";
LinkedList<String> queryColumns = new LinkedList<>();
String[] test = query.replace("SELECT", "").split("FROM")[0].split(","); //You have a string from which you need to extract single names, taking care of aliases.
for(String s : test) {
int aliasIndex = s.indexOf("AS");
String column;
if(aliasIndex != -1) {
//if there is an alias
column = s.substring(aliasIndex + 2).replace("'","").strip();
} else {
//if there isn't an alias
column = s.replace("'","").strip();
}
queryColumns.add(column);
}
I assume that the alias is indicated as 'AS' in uppercase, if it can be lowercase too, it's easy to change and adapt the code.
I would like to fetch serveral rows of data from a table.
I have a dao, sql and some parameters.
public static final String SELECT = ""
+ "SELECT NAME, SURNAME, AGE, LEVEL"
+ "FROM MYTABLE "
+ "WHERE "
public static final String CONDITION = ""
+ "SURNAME = :" + PARAM_SURNAME
+ "AND LEVEL = :" + PARAM_LEVEL;
For retrieval of a signle object I would do something like that:
public MyObject getMyThing(
final String surname,
final Integer level) {
final MapSqlParameterSource parameters = new MapSqlParameterSource()
.addValue(PARAM_SURNAME, surname)
.addValue(PARAM_LEVEL, level);
final String query = SELECT + CONDITION;
return myNamedTemplate.query(query, parameters, new MyObjectRowMapper());
}
And it is be just fine. However I would also like to use one SQL to retrieve several objects from databse. I know about the "IN" clause but it is not good enough as its usage will affect performance in the bad way.
What I would want is something that results in a following query:
SELECT STUFF FROM TABLE WHERE
//and the part I am interested in:
(SURNAME = :PARAM_SURNAME
AND LEVEL = :PARAM_LEVEL)
OR
(SURNAME = :PARAM_SURNAME
AND LEVEL = :PARAM_LEVEL)
OR
(SURNAME = :PARAM_SURNAME
AND LEVEL = :PARAM_LEVEL)
//and so on...
So the question:
How can I achieve this using JDBC Named Template in Spring? I cannot figure out how to do parameter mapping. Desired method in DAO could be something like that:
public List<MyObject> getMyThings(
final List<String> surnames,
final List<Integer> levels) {
final MapSqlParameterSource parameters = // magic
final String query = // more magic
return myNamedTemplate.query(query, parameters, new MyObjectRowMapper());
}
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);
}
I have a table T1 with columns ID(primary key,varchar), name(varchar), value(number) and key(number).I have a String array which consists of ID's and I want to retrieve all the records with those id in the String array from TABLE T1 in a single query. How can I write this query in oracle?
I'm currently using a for loop and getting the records:
for(String id: idList)
{
//Query to get record one by one (Select * from t1 where ID='id')
}
Could you suggest me a query to retrieve all these values in a single query?
Use the following query
select * from t1 where id in ('id1', 'id2', 'id3')
To get the ArrayList into the format, do the following
StringBuilder sb = New StringBuilder();
for(String id: idList)
{
sb.append("'"+id+"',")
}
sb.deleteCharAt(sb.length() -1);
sb.toString();
//Prep the query string
//---------------------------------
$strQ ="";
$len = count($idList);
$strQ = "'".$idList[0]."'";
for($i=1; $i<$len; $i++){
$strQ += " or ID = '".$idList[$i]."'";
}
//Now Da Query
//---------------------------------------
"Select * from t1 where ID= ".$strQ;
//---------------------
I've explained da above using PHP...
Try this
List<Long> itemIDs = new ArrayList<Long>();
itemIDs.add(10);
....
....
AuthService.deletePracticeAppMenu(itemIDs, selectedPractice.getID());
public void deletePracticeAppMenu(List<Long> prAppMenuIDs, Long practiceID) {
String query = "delete from PracticeAppMenu where PrAppMenuID in (:appMenuIDs) and practiceID = :pracid ";
Query q = getCurrentSession().createQuery(query);
q.setParameterList("appMenuIDs", prAppMenuIDs);
q.setParameter("pracid", practiceID);
q.executeUpdate();
}