I am trying to implement sqlparser and using gsqlparser from here. The source of the jar is in Java but I am implementing the same in Scala.
Below is my query which contains a join condition.
SELECT e.last_name AS name, e.commission_pct comm, e.salary * 12 "Annual Salary" FROM scott.employees AS e right join scott.companies as c on c.orgid = e.orgid and c.orgname = e.orgn WHERE e.salary > 1000 ORDER BY e.first_name, e.last_name
I was able to parse the query to read names & aliases of columns, where conditions, table names (checking the table names directly inside the query) as below.
val sqlParser = new TGSqlParser(EDbVendor.dbvsnowflake)
sqlParser.sqltext = "SELECT e.last_name AS name, e.commission_pct comm, e.salary * 12 \"Annual Salary\" FROM scott.employees AS e right join scott.companies as c on c.orgid = e.orgid and c.orgname = e.orgn WHERE e.salary > 1000 ORDER BY e.first_name, e.last_name"
val selectStmnt = sqlParser.sqltext
println("Columns List:")
for(i <- 0 until selectStmnt.getResultColumnList.size()) {
val resCol = selectStmnt.getResultColumnList.getResultColumn(i)
println("Column: " + resCol.getExpr.toString + " Alias: " + resCol
.getAliasClause().toString)
}
Output:
Columns List:
Column: e.last_name Alias: name
Column: e.commission_pct Alias: comm
Column: e.salary * 12 Alias: "Annual Salary"
I am trying to parse the join condition and get the details inside it
for(j <- 0 until selectStmnt.getJoins.size()) {
println(selectStmnt.getJoins.getJoin(j).getTable)
}
The problem here is there is only one join condition in the query, so the size returned is 1.
Hence the output is scott.employees.
If I do it a bit different as below using getJoinItems
println("Parsing Join items")
for(j <- 0 until selectStmnt.getJoins.size()) {
println(selectStmnt.getJoins.getJoin(j).getJoinItems)
}
I get the output by cutting off the first table from the join condition as below:
scott.companies as c on c.orgid = e.orgid and c.orgname = e.orgn
The method: getJoinItems() returns a list: TJoinItemList which I thought of traversing through. But even its size is 1.
println(selectStmnt.getJoins.getJoin(j).getJoinItems.size()) -> 1
I am out of ideas now. Could anyone let me know how can I parse the query's join condition and get the table names inside the join ?
I don't have access to Snowflake dialect in GSP but I mimicked this scenario with Teradata dialect using the following query and created a sql parser.
SELECT e.last_name as name
FROM department d
RIGHT JOIN
trimmed_employee e
ON d.dept_id = e.emp_id
WHERE e.salary > 1000
ORDER BY e.first_name
Here is the Groovy code of getting both the tables department, trimmed_employee. It boils down to iterating over each join and while doing so collect the current join's items (joinItems) using curJoin.joinItems only if it is not null.
stmt.joins.asList().collect { curJoin ->
[curJoin.table] + (curJoin?.joinItems?.asList()?.collect { joinItems -> joinItems.table } ?: [])
}.flatten()
Result:
department
trimmed_employee
For this simple sql that you mentioned in my case, the following code also works.
stmt.tables.asList()
I am trying to change one of the value in my table in database based on an another value in the same database but different table. The first table is called orders and the second is called buy supply. What I want to do is I want to change the value of sumquantity that is in 'buysupply' table by subtracting a value from the column named quantity_ordered from 'orders' table. I tried writing some query but it is not working, it keeps popping up error. If you know of a solution, do let me know. The code is all below as well
private void DispatchButtonActionPerformed(java.awt.event.ActionEvent evt) {
String type = txttype.getSelectedItem().toString();
String name = txtname.getText();
String quantity = txtquantity.getText();
String dispatch_row = txtdispatch.getText();
String statusDispatched = "Dispatched";
try {
Class.forName("com.mysql.jdbc.Driver");
con1 = DriverManager.getConnection("jdbc:mysql://localhost/restock", "root", "password");
// Focus on this
String template = "UPDATE orders SET status = '%s' WHERE id = %s";
String template2 = "UPDATE buysupply SET sumquantity = sumquantity - %s WHERE id = %s";
String quantity_ordered = "quantity_ordered FROM orders";
pst = con1.prepareStatement(String.format(template, statusDispatched, dispatch_row));
pst.executeUpdate();
pst1 = con1.prepareStatement(String.format(template2, quantity_ordered , dispatch_row));
pst1.executeUpdate();
// Look on top
JOptionPane.showMessageDialog(null, "Item has been dispatched");
// To update the newly recorded data to the table
table_update();
// Set the textfields to empty upon button click
txttype.setSelectedIndex(-1);
txtname.setText("");
txtquantity.setText("");
txtdispatch.setText("");
txttype.requestFocus();
} catch (ClassNotFoundException | SQLException ex) {
JOptionPane.showMessageDialog(null, "Quantity or Dispatch field is not an integer, Please try again.");
Logger.getLogger(mainpage.class.getName()).log(Level.SEVERE, null, ex);
}
}
// This code is in another class file
try {
Class.forName("com.mysql.jdbc.Driver");
con1 = DriverManager.getConnection("jdbc:mysql://localhost/restock", "root", "password");
String template = "SELECT SUM(quantity) as sumquantity FROM buysupply WHERE itemtype IN ('Plastic gloves', 'Rubber gloves')";
PreparedStatement pst = con1.prepareStatement(template);
ResultSet rs = pst.executeQuery();
if (rs.next()) {
glovesum = rs.getString("sumquantity");
} else {
System.out.print("Query didn't return any results");
}
} catch (ClassNotFoundException | SQLException ex) {
Logger.getLogger(stock.class.getName()).log(Level.SEVERE, null, ex);
}
As far I understand (and please read until the end) if it is a classic Invoice order database with a list of product into "buysupply" table and "order" table for the ordering client list of product.
The first point, several people into the comment point is the missing link data between both table. I assume reading your peace of code that the link is made by a ID but that not clear, so I offer a solution base on a link between those columns:
orders.itemtype = buysupply.itemtype
If it on an other element, please change the information into the SQL query below.
I assume also the column orders.status as to change the values from what I call 'Waiting' value to 'Dispatched' value.
So here the data before into "buysupply" table:
id, itemtype, quantity
1 , mask , 704
2 , clothed, 101
3 , N95, 18
Here the data before into "order" table:
id, itemtype, quantity_orderred, status,
1,mask, 1 , Dispatched
2,clothed,3,Waiting
The SQL to update both value (the orders.status and buysupply.quantity ) should be something like that suppose the order.id to update is 2:
update orders,buysupply
set orders.status='Dispatched',
buysupply.quantity = buysupply.quantity - orders.quantity_orderred
where
orders.itemtype = buysupply.itemtype
AND
orders.status = 'Waiting'
AND
orders.id = '2'
AFTER:
So here the data after into "buysupply" table:
id, itemtype, quantity
1 , mask , 704
2 , clothed, 98
3 , N95, 18
Here the data before into "order" table:
id, itemtype, quantity_orderred, status,
1,mask, 1 , Dispatched
2,clothed,3,Dispatched
The update could apply on several tables and columns, you should just indicate the column table name with each column to avoid confusion.
That could be the first step to let you improve the code for the sum part, that, I afraid no understand at all.
Then I find a partial information explaining that the sum_quantity is a computed calcul from a sum of the value, so you do not want to change the quantity, my bad.
So you can create a temporary table with this kind of SQL, temporary table is detroy at the connection close:
CREATE TEMPORARY TABLE IF NOT EXISTS TMPsumquantity AS
SELECT SUM(quantity) as sumquantity FROM buysupply WHERE itemtype IN ('Plastic gloves', 'Rubber gloves')
That could create a column with the information you want, BUT, it's not my recommendation as far I understand ;-)
I will create a new column to store the sum value into the table "buysupply", to say the "the quantity in stock avalaible at the moment this order will be Dispatched is that for this element" so the result of you sum value
Before "buysupply":
id, itemtype, quantity, quantity_avalaible
1 , mask , 704, 704
2 , clothed, 101, 101
3 , N95, 18, 18
Before "order":
id, itemtype, quantity_orderred, status, quantity_avalaible
1,mask, 1 , Dispatched
2,clothed,3, Waiting
So the SQL to create this column is complex, base on an inner-join between the same table
UPDATE buysupply b1
INNER JOIN (
SELECT SUM(quantity) as sumquantity, id
FROM buysupply
where buysupply.itemtype IN ('clothed', 'N95')
) b2 ON true
SET b1.quantity_avalaible = b2.sumquantity
So the new table "buysupply" with the colum "quantity_avalaible" containing the sum of the value of the colum quantity for N95 and clothed values :
id, itemtype, quantity, quantity_avalaible
1 , mask , 704, 116
2 , clothed, 101, 116
3 , N95, 18, 116
So then you can use the first SQL proposal to update quantity_avalaible depending the value of "orders.quantity_orderred"
Last point, I have a partial view on the data structure and the bussiness logic, it could be usefull to store a negative value into the column "orders.quantity_orderred" so the SQL SUM could add and substract values with the same call to the SUM function
Best
I'm stuck in get the total count of group by query result.
JPAQuery jpaQuery = new JPAQuery(entityManager);
jpaQuery.from(QMessageSend.messageSend)
.where(predicate)
.groupBy(QMessageSend.messageSend.messageId).count();
this is my current code.
and this code return count for each group.
SELECT count(*)
FROM MESSAGE_SEND ms
GROUP BY ms.MESSAGE_ID
but I want to get the total count of group by query result.
like result of below sql
SELECT count(*)
FROM (
SELECT *
FROM MESSAGE_SEND ms
GROUP BY ms.MESSAGE_ID
) msc
What I should do?
MESSAGE_ID is not primary key.
and JPAQuery's distinct method not support select specific column. (has no parameter)
I think you want COUNT(DISTINCT):
SELECT COUNT(DISTINCT s.MESSAGE_ID)
FROM MESSAGE_SEND ms;
If MESSAGE_ID is the primary key in the table, then COUNT(*) suffices.
im having a hard time finding where is my mistake so i could use some help.
I'm using 2 tables. "diamerismata", and another one based on which users selects in previous steps, you'll be looking at it as "+KataxDiamTable+".
My query is:
String monthly = "SELECT diamerismata.DIAMERISMA as Διαμέρισμα, diamerismata.ΟΝΟΜΑ as Όνομα, "+KataxDiamTable+".LASTDIFF as ΠρΔιαφορά, "+KataxDiamTable+".ΧΡΕΩΣΕΙΣ as Χρέωση, "+KataxDiamTable+".DATE as Ημερομηνία, "+KataxDiamTable+".DIFF as Διαφορά FROM diamerismata, "+KataxDiamTable+" WHERE MONTH("+KataxDiamTable+".DATE) = "+ms+" AND YEAR("+KataxDiamTable+".DATE) = "+yr+" AND "+KataxDiamTable+".IDdiam = diamerismata.IDdiam AND ID = ( SELECT MAX(ID) FROM "+KataxDiamTable+" WHERE "+KataxDiamTable+".IDdiam = diamerismata.IDdiam) ORDER BY diamerismata.DIAMERISMA";
But it only returns 4 rows when it should be returning 10.
"yr" and "ms" are date filters. But every record of mine has the same date, so the problem isn't there...
IDdiam and ID are ASC and UNIQUE.
Any Ideas? Thank you
I am getting the following error on the execution of the below hibernate transaction : expecting DOT, found '=' near line 1, column 32 [update t_credential set status = :status , assigned_engine = :engine where id = :id] .
Also, t_credential is a table and not an object. Does hibernate allow to use this way or does it compulsorily have to be an object?
for(Credential credential: accountList){
Query query = ssn.createQuery("update t_credential set status =:status , assigned_engine = :engine where id = :id");
query.setParameter("status", status);
query.setParameter("engine", assignedTo);
query.setParameter("id", String.valueOf(credential.getId()));
int result = query.executeUpate();
}
Look at the HQL example here: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html#batch-direct. It seems that you need to refer to an object: "update t_credential c", and then update it's fields, like this: "set c.status = :status" and so on.
If you want to use Hibernate with SQL Query (and not HQL query), you may have to use a different function.
ssn.createSQLQuery(" ... ");
I never used this function, so I hope it's a good answer for you.
Max