JDBC SQL aliasing not working - mysql

I am trying to run the following query in my java web application:
SELECT platform AS "Platform" FROM edb.cases
The web-app is working fine and is able to execute all queries however whenever I use an alias (through 'AS'), the resultant data-set gives me a null value for the alias. In fact, despite using an alias for the column 'platform' in the above query, the resultant data-set has a null value for the key 'Platform' but gives me the correct value for the key 'platform' (which is the original name of the column).
Now the actual sql statement which I need to execute is a bit more complex with select statements and left joins on the same table twice using aliases, like so:
SELECT numOne.platform , numTwo.platform AS 'PlatformTwo' FROM edb.cases LEFT JOIN
edb.platform as numOne ON (numOne.rank = cases.platform) LEFT JOIN edb.platform as numTwo ON
(numTwo.rank = cases.highestPlatform) WHERE cases.index = 1000
The problem is that the resultant data-set contains the correct value for the key 'platform' (for numOne table) but the keys 'PlatformOne' and 'PlatformTwo' DO NOT EXIST. The aliases are not working!
I have tried both the statements in MySql workbench and they work fine.
Please do not hesitate to ask for more information.
EDIT:
The code that prepares the query and sends it to the database:
public static List<Map<String, Object>> executeQuery(final String query,
Map<Integer, Object> data) {
List<Map<String, Object>> result = null;
try {
Connection conn = createConnection();
PreparedStatement pstmt = null;
pstmt = conn.prepareStatement(query);
if(data != null) {
pstmt = createPreparedStatement(pstmt, data);
}
System.out.println(pstmt.toString());
//The GET_CASE_FOR_INDEX query uses the executequery function in the else block:
if((pstmt.toString().indexOf("INSERT") >= 0) || (pstmt.toString().indexOf("UPDATE") >= 0)) {
pstmt.executeUpdate();
} else {
ResultSet rs = pstmt.executeQuery();
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
result = new ArrayList<Map<String, Object>>();
/*
* Get the next row of the ResultSet 'rs' and insert a Map of the Column/Value pair
* into the ArrayList of Maps 'result'
*/
while(rs.next()) {
Map<String, Object> row = new HashMap<String, Object>(columns);
for(int i=1; i <= columns; i++) {
try {
row.put(md.getColumnName(i), rs.getObject(i));
} catch(Exception e) {
System.out.println(md.getColumnName(i));
System.out.println(row);
e.printStackTrace();
}
}
result.add(row);
}
}
destroyConnection(conn);
pstmt.close();
} catch(SQLException e) {
//TODO
e.printStackTrace();
}
return result;
}
The function creating the prepared statement:
//creates a prepared statement by checking the type of the value that needs to be set.
private static PreparedStatement createPreparedStatement(
PreparedStatement pstmt, Map<Integer, Object> data) {
try {
for(Integer key : data.keySet()) {
Object value = data.get(key);
System.out.println(key);
if(data.get(key).equals(Types.NULL)) {
pstmt.setNull(key, Types.INTEGER);
} else if(value.getClass().equals(Integer.class)) {
pstmt.setInt(key, (Integer) value);
} else if(value.getClass().equals(String.class)) {
pstmt.setString(key, (String) value);
} else if(value.getClass().equals(Date.class)) {
pstmt.setDate(key, (Date) value);
} else if(value.getClass().equals(Timestamp.class)) {
pstmt.setTimestamp(key, (Timestamp) value);
}
}
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pstmt;
}
And the code snippet which uses the executeQuery function to execute the query and sends it to the web template:
Map<Integer, Object> data_details = new HashMap<Integer, Object>();
data_details.put(1, parameter_ID);
List<Map<String, Object>> details = DBUtility.executeQuery(DBQuery.GET_CASE_FOR_INDEX, data_details);
webContext.setVariable("details", details);//This is where the template variable is being set
System.out.println(details);
The GET_CASE_FOR_INDEX query is :
SELECT numOne.platform , numTwo.platform AS 'PlatformTwo' FROM edb.cases LEFT JOIN
edb.platform as numOne ON (numOne.rank = cases.platform) LEFT JOIN edb.platform as numTwo ON
(numTwo.rank = cases.highestPlatform) WHERE cases.index = ?
When I print the details hash map (which is the result data-set) the key PlatformTwo is entirely absent!

You are using the .getColumnName method of ResultSetMetaData, which returns the name of the underlying column (if available). .getColumnLabel will return the column alias as defined by SELECT ... AS ....
To illustrate, the following Java code
PreparedStatement ps = conn.prepareStatement(
"SELECT platform AS Platypus FROM cases");
ResultSet rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
System.out.println(String.format(
".getColumnName returns \"%s\"",
rsmd.getColumnName(1)));
System.out.println(String.format(
".getColumnLabel returns \"%s\"",
rsmd.getColumnLabel(1)));
returns
.getColumnName returns "platform"
.getColumnLabel returns "Platypus"

Related

Rename value within query

I have a problem with renaming a specific value in a column in mySQL Database. At first i thought i could just use 'AS' to rename, but i'm actually trying to rename a value in a column. My column is named FoundLost. In this column I Store values '0' and '1'. '0' is Found and '1' is Lost.
The reason I need to rename this values is because I use the data from this database to create a pieChart. with the function .getName it gives the names '0' and '1'.
I was hoping someone could help me out!
The class with the query is the code below:
public static ObservableList getPChartFoundLost() {
String query = "SELECT FoundLost, concat(round(count(FoundLost) *100 / (SELECT count(FoundLost) FROM Luggage))) AS percent FROM Luggage GROUP BY FoundLost";
ObservableList FoundLost = FXCollections.observableArrayList();
Connection connection = DatabaseUtils.connect();
if (connection != null) {
try {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
while (resultSet.next()) {
FoundLost.add(new PieChart.Data(resultSet.getString("FoundLost"), resultSet.getInt("percent")));
}
resultSet.close();
statement.close();
} catch (SQLException sqle) {
System.out.println(sqle.getMessage());
}
DatabaseUtils.disconnect(connection);
}
return FoundLost;
}
Controller:
public void clickPChartFoundLost(ActionEvent event) {
//PieChart
ObservableList FoundLost = StatisticsUtils.getPChartFoundLost();
pieChart.setVisible(true);
pieChart.setData(FoundLost);
pieChart.setTitle("Found and Lost luggage");
for (final PieChart.Data data : pieChart.getData()) {
data.getNode().addEventHandler(MouseEvent.ANY,
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
//Label vullen met data van Observable list uit Database
pieChartValueLable.setText(String.valueOf(data.getName()) + ": "
+ String.valueOf(data.getPieValue()) + "%");
}
});
}
}
Thanks!!
In your query, try this as your first column instead of just FoundLost. It translates your 0 and 1 values to meaningful strings for your chart. The rest of your query can stay the same.
IF(FoundLost = 0,'Found','Lost') AS FoundLost

Does h2 have a query/clause similar to the WHERE IN in MySQL?

My code currently goes as follows:
public List<DeviceOrganizationMetadataHolder> getChildrenByParentId(List<String> parentIds) throws DeviceOrganizationDAOException {
List<DeviceOrganizationMetadataHolder> children = new ArrayList<>();
Connection conn;
PreparedStatement stmt = null;
ResultSet rs = null;
DeviceOrganizationMetadataHolder deviceMetadataHolder;
String[] data = parentIds.toArray(new String[parentIds.size()]);
try {
conn = this.getConnection();
String sql = "SELECT * FROM DEVICE_ORGANIZATION_MAP WHERE DEVICE_PARENT IN (?)";
stmt = conn.prepareStatement(sql);
data = parentIds.toArray(data);
stmt.setObject(1, data);
rs = stmt.executeQuery();
while (rs.next()) {
deviceMetadataHolder = this.loadOrganization(rs);
children.add(deviceMetadataHolder);
}
} catch (SQLException e) {
throw new DeviceOrganizationDAOException("Error occurred for device list with while retrieving children.", e);
} finally {
DeviceManagementDAOUtil.cleanupResources(stmt, rs);
return children;
}
}
However even though in the unit tests I try to pass an array with parentIds, the return remains null.
What I can gauge from this is one of the following:
The array data isn't getting properly read, therefore the output is coming as null.
WHERE IN is not supported by h2 or else there is a different implementation that needs to be used instead.
Where am I going wrong in this?
EDIT - There was a similar duplicate question that was tagged. While it suggested using a StringBuilder and a loop, I was looking for an answer stating how it could be done in a cleaner way using the query itself.
Try setting the parameter as a list instead of an array, ie replace
stmt.setObject(1, data);
with
stmt.setObject(1, Arrays.asList(data));
Figured it out.
There was an issue posted on the h2database GitHub about this exact problem. Followed the suggested edits and it worked!
Code after edits is as follows:
public List<DeviceOrganizationMetadataHolder> getChildrenByParentId(List<String> parentIds) throws DeviceOrganizationDAOException {
List<DeviceOrganizationMetadataHolder> children = new ArrayList<>();
Connection conn;
PreparedStatement stmt = null;
ResultSet rs = null;
DeviceOrganizationMetadataHolder deviceMetadataHolder;
Object[] data = parentIds.toArray();
try {
conn = this.getConnection();
String sql = "SELECT * FROM DEVICE_ORGANIZATION_MAP WHERE DEVICE_PARENT IN (SELECT * FROM TABLE(x VARCHAR = ?))";
stmt = conn.prepareStatement(sql);
stmt.setObject(1, data);
rs = stmt.executeQuery();
while (rs.next()) {
deviceMetadataHolder = this.loadOrganization(rs);
children.add(deviceMetadataHolder);
}
} catch (SQLException e) {
throw new DeviceOrganizationDAOException("Error occurred for device list with while retrieving children.", e);
} finally {
DeviceManagementDAOUtil.cleanupResources(stmt, rs);
return children;
}
}
As you can see, I've used an Object array for data instead and added an additional query inside the main query.
Followed the instructions given in the GitHub issue to a tee and it worked flawlessly.

Return values from database queries into a LinkedHashMap

I keep getting one value from this LinkedHashMap it's either the first [ if (resultset.next()) ] or the last [ while(resultset.next()) ], only one result is coming back but I want the full map. How do I return all rows in the table that fit my criteria? Any help would be appreciated.
/** A method to list all previous statuses for a certain user given the userID */
public StringBuilder showStatusHistory(int userID) {
try {
Date date;
String status;
preparedStatement = createStatement("select statusDate,statusText from statusTable where userID = ?");
preparedStatement.setInt(1,userID);
resultSet = preparedStatement.executeQuery();
StringBuilder allStatus = new StringBuilder("");
statusesList = new LinkedHashMap<>();
while (resultSet.next()){
date = resultSet.getDate(1);
status = resultSet.getString(2);
statusesList.put(date,status);
}
Set<Date> statusTime = statusesList.keySet();
for(Date k:statusTime){
allStatus.append(k+" "+statusesList.get(k));
}
return allStatus;
}
catch (SQLException sqlE){
sqlE.printStackTrace();
}
return null;
/** A helper method was used to minimize code duplication. It works for sure */
private PreparedStatement createStatement(String query) {
try {
connection = DB_ConnectionConfiguration.getConnection();
this.query = query;
preparedStatement = connection.prepareStatement(query);
return preparedStatement;
}
catch (SQLException sqlE) {
sqlE.printStackTrace();
return null;
}
}
here are a couple suggestions in sample code below...
public StringBuilder showStatusHistory(int userID) {
// define at top and return "" if no results
StringBuilder allStatus = new StringBuilder("");
try {
Date date;
String status;
// define local in the method
PreparedStatement preparedStatement = createStatement("select statusDate,statusText from statusTable where userID = ?");
preparedStatement.setInt(1, userID);
// define local in the method
ResultSet resultSet = preparedStatement.executeQuery();
// append to the all Status here and skip the other loop
// if you need a distinct list (like you had fro the Set) you could use a DISTINCT on the SQL statement.
while (resultSet.next()) {
date = resultSet.getDate(1);
status = resultSet.getString(2);
// append to the allStatus here
allStatus.append(date).append(" ").append(status); // add a newline to the end? append(System.lineSeparator())
}
} catch (SQLException sqlE) {
sqlE.printStackTrace();
// do you want to throw this if something bad happened?
} finally {
// close up your jdbc resources
}
// will contain "" if no records or concatenated statuses from the resultset
return allStatus;
}

Search in database with like operator and return list of results

Here is my method to searching a specific String:
(I want to do search in title of books table)
private static String searchInDB(String keyword) {
String url = "jdbc:mysql://localhost/bookstore";
String query = "Select title from books where title like %?% ";
try {
Connection connection = DriverManager.getConnection(...);
PreparedStatement ps = connection.prepareStatement(query);
ps.setString(1, keyword);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
return rs.getString("title");
}
} catch (SQLException sqle) {
sqle.printStackTrace();
}
return null;
}
But when i call this method:
System.out.println(searchInDB("so"));
there is an exception in the result:
java.sql.SQLException: Parameter index out of range (1 > number of parameters, which
is 0).
null
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
...
UPDATE
I add this code to get all the results, but i got into a infinitive loop with a identical value!
String result = searchInDB("so");
while (result != null) {
System.out.println(result);
}
Change the code so that the wildcards are contained in the parameter, and not in the query, viz:
String query = "Select title from books where title like ?";
....
ps.setString(1, "%" + keyword + "%");
Edit Re, other question
AFAIK Java has no yield return capability, so you'll need to change your method signature.
Currently, you are returning the first result and then never returning to the function.
My Java is pretty basic, but how about:
private static List<String> searchInDB(String keyword) {
List<String> theStrings = new List<String>();
String url = "jdbc:mysql://localhost/bookstore";
String query = "Select title from books where title like %?% ";
try {
Connection connection = DriverManager.getConnection(...);
PreparedStatement ps = connection.prepareStatement(query);
ps.setString(1, keyword);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
theStrings.Add(rs.getString("title"));
}
} catch (SQLException sqle) {
sqle.printStackTrace();
}
return theStrings ;
}

How to get data from MYSQL database

I have a database named as "test" in which I have a table named as "first" which contains raw data, I want to get this table data. What should be the prepare statement I have to use in order to get data from table "first" ? Below is the code I am trying. Any help or guidance would be appreciable.
#Path("/database") // Specific URL
#GE
#Produces(MediaType.TEXT_PLAIN)
public String returnDB_Status() throws Exception {
PreparedStatement query = null;
String result = null;
Connection conn = null;
try {
conn = mysql_prac.dbConn().getConnection(); // this works fine ...
query = conn.prepareStatement("SELECT * from first" ); // Table named as "first" is placed inside the connected database.
ResultSet rs = query.executeQuery();
result = "Data received : " + rs;
query.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null)
conn.close();
}
return result;
}
and the source code used get a connection
public class mysql_prac {
private static DataSource mysql_prac = null;
private static Context context = null;
public static DataSource dbConn() throws Exception {
if (mysql_prac != null) {
return mysql_prac;
}
try {
if (context == null) {
context = new InitialContext();
}
mysql_prac = (DataSource) context.lookup("JDBC_ref"); //JNDI ID (JDBC_REF)
} catch (Exception e) {
e.printStackTrace();
}
return mysql_prac;
}
}
You must loop through the ResultSet to get the fields of each row. So I made the following edit together with some comments.Please notice the comments.
try {
conn = mysql_prac.dbConn().getConnection(); // this works fine ...
query = conn.prepareStatement("SELECT * from first" ); // Table named as "first" is placed inside the connected database.
ResultSet rs = query.executeQuery();//You must loop through the results set to get the fields of each row
while(rs.next()){
String dbUserID = rs.getString("column1");//this is just an example to retrieve all data in the column called 'column1'
result = "Data received : " + dbUserID;
System.out.println(result);
}
query.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null)
conn.close();
}