StringBuilder Regex Needed For Creating Dymanic SQL Statement - java

I have the following SQL string defined as a StringBuilder and want to replace all the ? with their appropriate keys:
SELECT a.accountNumber, a.eventKey, a.createdAtUtc FROM myFirstTable a, mySecondTable b where a.eventKey = b.eventKey and a.status = ? and
a.accountNumber = ?
I was hoping to use the following replace() function to retrieve the corresponding values from a map that are stored without the prefix "a." or ".b" but having trouble getting it working:
private String replace(StringBuilder sqlBuilder, Map<String, String> filterMap) {
for (Map.Entry<String, String> entry : filterMap.entrySet()) {
int startPositionOfKey = sqlBuilder.indexOf(entry.getKey());
int startIndex = startPositionOfKey + entry.getKey().length() + 4;
sqlBuilder.replace(startIndex, 1, "'" + entry.getValue() + "'");
}
return sqlBuilder.toString();
}

Related

how to create comma separated string in single quotes from arraylist of string in JAVA

I have requirement in Java to fire a query on MS SQL like
select * from customer
where customer.name in ('abc', 'xyz', ...,'pqr');
But I have this IN clause values in the form of ArrayList of String. For ex: the list look like {"abc","xyz",...,"pqr"}
I created a Prepared Statement :
PreparedStatement pStmt = conn.prepareStatement(select * from customer
where customer.name in (?));
String list= StringUtils.join(namesList, ",");
pStmt.setString(1,list);
rs = pStmt.executeQuery();
But the list is like "abc,xyz,..,pqr", but I want it as "'abc','xyz',..,'pqr'"
so that I can pass it to Prepares Statement.
How to do it in JAva with out GUAVA helper libraries.
Thanks in Advance!!
I know this is a really old post but just in case someone is looking for how you could do this in a Java 8 way:
private String join(List<String> namesList) {
return String.join(",", namesList
.stream()
.map(name -> ("'" + name + "'"))
.collect(Collectors.toList()));
}
List<String> nameList = ...
String result = nameList.stream().collect(Collectors.joining("','", "'", "'"));
For converting the string you can try this:
String list= StringUtils.join(namesList, "','");
list = "'" + list + "'";
But i dont thing it's a good idea to pass one string for multiple params.
Even if you formatted the String as you wish, it won't work. You can't replace one placeholder in the PreparedStatement with multiple values.
You should build the PreparedStatement dynamically to have as many placeholders as there are elements in your input list.
I'd do something like this :
StringBuilder scmd = new StringBuilder ();
scmd.append ("select * from customer where customer.name in ( ");
for (int i = 0; i < namesList.size(); i++) {
if (i > 0)
scmd.append (',');
scmd.append ('?');
}
scmd.append (")");
PreparedStatement stmt = connection.prepareStatement(scmd.toString());
if (namesList.size() > 0) {
for (int i = 0; i < namesList.size(); i++) {
stmt.setString (i + 1, namesList.get(i));
}
}
rs = stmt.executeQuery();
You can use a simple separator for this type of activity. Essentially you want an object that evaluates to "" the first time around but changes after the first request to return a defined string.
public class SimpleSeparator<T> {
private final String sepString;
boolean first = true;
public SimpleSeparator(final String sep) {
this.sepString = sep;
}
public String sep() {
// Return empty string first and then the separator on every subsequent invocation.
if (first) {
first = false;
return "";
}
return sepString;
}
public static void main(String[] args) {
SimpleSeparator sep = new SimpleSeparator("','");
System.out.print("[");
for ( int i = 0; i < 10; i++ ) {
System.out.print(sep.sep()+i);
}
System.out.print("]");
}
}
I did it as following with stream. Almost the same, but a bit shorter.
nameList = List.of("aaa", "bbb", "ccc")
.stream()
.map(name -> "'" + name + "'")
.collect(Collectors.joining(","));
I guess the simplest way to do it is using expression language like that:
String[] strings = {"a", "b", "c"};
String result = ("" + Arrays.asList(strings)).replaceAll("(^.|.$)", "\'").replace(", ", "\',\'" );

Return list of query in Java 1 dimensional e.g., 1 row is returned

I am having a lot of trouble iterating through all my records. Perhaps, by reading my code someone could help.
private String saveData(Handle handle, String username, String name, String prof, String table) {
String sqlCommand;
Map<String, Object> userResults;
for (Integer tableNum = 1; tableNum < 5; tableNum++) {
//query all tables
sqlCommand = String.format("SELECT varname FROM s" + tableNum.toString());
userResults = handle.createQuery(sqlCommand)
.bind("username", username)
.first();
//attempt to ierate all records
for (Map.Entry<String, Object> entry : userResults.entrySet()) {
Object obj = entry.getValue(); // doesnt have .get(string) as below
}
//get the desired field
logger.debug("Results: " + userResults.toString());
String varname = (String) userResults.get("varname");
if ((varname.toLowerCase()).matches(name.toLowerCase()))
return "";
}
//save data
return name;
}
How do I iterate through each record of the table?
You say this works for row1. You cannot go to the next row as there is .first(); in your handle and you have not tried to fetch next record. Modify your query - the documentation here says you can use .list(maxRows);

Comparing same Keys in ArrayList<HashMap<String, String>> based off comparison remove element in Array

Below is my current code:
private void processData(StringBuffer reportBuffer) {
String tableName = "db2_table_name";
ArrayList<HashMap<String, String>> tableValue = FileData.get(tableName);
String No = "No";
String versionNumber = "VersionNumber";
for (HashMap<String, String> fieldValue : tableValue) {
String No = fieldValue.get(No);
String Version = fieldValue.get(versionNumber);
reportBuffer.append("No is: " + No + " and Version is: " +Version + NL);
}
}
The current output of this is:
No is: 1. and Version is: 1.
No is: 1. and Version is: 2.
No is: 3. and Version is: 1.
No is: 3. and Version is: 2.
No is: 3. and Version is: 3.
What I am looking to do is only keep the latest version of each No while removing the element of the older versions. So within my new ArrayList I would ideally want to only have:
No is: 1. and Version is: 2.
No is: 3. and Version is: 3
Let me know if you need any clarifications!
Thanks!
.
You could create a new HashMap and save the latest version for each No inside that hashmap.
You should be able to do that by saving each No and Version in the hashmap while you go through the for loop you have there. However, every time before you save a value, you should check if the hashmap contains the current No, and if yes don't save it but check if the stored version is smaller than the current one and replace it.
At the end, create a loop to go around the hashmap and use it along with the reportBuffer.append()
Heres one way
Keep a Map<String,Integer> lowestAmongMaps = new HashMap<String,Integer>();
In your for loop, add the lowest value for each key to this map..
basically, something like this
Integer currentLowest = Integer.valueOf(lowestAmongMaps.get(versionNumber));
if(currentLowest == null){
currentLowest = Integer.MAX_VALUE;
}
Integer currentVal = Integer.valueOf(Version).intValue();
if( currentVal.intValue() < currentLowest.intValue()){
lowestAmongMaps.put(versionNumber,currentVal);
}
Now in the next iteration remove all keys which are not lowest.
So basically you have two iterations over
for (HashMap<String, String> fieldValue : tableValue)
If its a database the best way would be to modify the query to return only max version from FileData.get(). But I suppose its a file. So a simple solution would be to keep a third map to store the report values. Eg
private void processData(StringBuffer reportBuffer) {
String tableName = "db2_table_name";
ArrayList<HashMap<String, String>> tableValue = FileData.get(tableName);
String no = "No";
String versionNumber = "VersionNumber";
Map<String, String> mergedMap = new HashMap<String, String>();
for (HashMap<String, String> fieldValue : tableValue) {
String No = fieldValue.get(no);
String Version = fieldValue.get(versionNumber);
if(mergedMap.containsKey(No)){
Integer previousVersion = Integer.valueOf(mergedMap.get(No));
Integer currentVersion = Integer.valueOf(Version);
if(currentVersion > previousVersion){
mergedMap.put(No, Version);
}
} else {
mergedMap.put(No, Version);
}
}
for(Entry<String, String> entry : mergedMap.entrySet()){
reportBuffer.append("No is: " + entry.getKey() + " and Version is: " + entry.getValue() + NL);
}
}

How to sort a string into a map and print the results

I have a string in the format nm=Alan&hei=72&hair=brown
I would like to split this information up, add a conversion to the first value and print the results in the format
nm Name Alan
hei Height 72
hair Hair Color brown
I've looked at various methods using the split function and hashmaps but have had no luck piecing it all together.
Any advice would be very useful to me.
Map<String, String> aliases = new HashMap<String, String>();
aliases.put("nm", "Name");
aliases.put("hei", "Height");
aliases.put("hair", "Hair Color");
String[] params = str.split("&"); // gives you string array: nm=Alan, hei=72, hair=brown
for (String p : params) {
String[] nv = p.split("=");
String name = nv[0];
String value = nv[1];
System.out.println(nv[0] + " " + aliases.get(nv[0]) + " " + nv[1]);
}
I really do not understand what you problem was...
Try something like this:
static final String DELIMETER = "&"
Map<String,String> map = ...
map.put("nm","Name");
map.put("hei","Height");
map.put("hair","Hair color");
StringBuilder builder = new StringBuilder();
String input = "nm=Alan&hei=72&hair=brown"
String[] splitted = input.split(DELIMETER);
for(Stirng str : splitted){
int index = str.indexOf("=");
String key = str.substring(0,index);
builder.append(key);
builder.append(map.get(key));
builder.append(str.substring(index));
builder.append("\n");
}
A HashMap consists of many key, value pairs. So when you use split, devise an appropriate regex (&). Once you have your string array, you can use one of the elements as the key (think about which element will make the best key). However, you may now be wondering- "how do I place the rest of elements as the values?". Perhaps you can create a new class which stores the rest of the elements and use objects of this class as values for the hashmap.
Then printing becomes easy- merely search for the value of the corresponding key. This value will be an object; use the appropriate method on this object to retrieve the elements and you should be able to print everything.
Also, remember to handle exceptions in your code. e.g. check for nulls, etc.
Another thing: your qn mentions the word "sort". I don't fully get what that means in this context...
Map<String, String> propsMap = new HashMap<String, String>();
Map<String, String> propAlias = new HashMap<String, String>();
propAlias.put("nm", "Name");
propAlias.put("hei", "Height");
propAlias.put("hair", "Hair Color");
String[] props = input.split("&");
if (props != null && props.length > 0) {
for (String prop : props) {
String[] propVal = prop.split("=");
if (propVal != null && propVal.length == 2) {
propsMap.put(propVal[0], propVal[1]);
}
}
}
for (Map.Entry tuple : propsMap.getEntrySet()) {
if (propAlias.containsKey(tuple.getKey())) {
System.out.println(tuple.getKey() + " " + propAlias.get(tuple.getKey()) + " " + tuple.getValue());
}
}

Java finding substring

I have the following String:
oauth_token=safcanhpyuqu96vfhn4w6p9x&**oauth_token_secret=hVhzHVVMHySB**&application_name=Application_Name&login_url=https%3A%2F%2Fapi-user.netflix.com%2Foauth%2Flogin%3Foauth_token%3Dsafcanhpyuqu96vfhn4w6p9x
I am trying to parse out the value for oauth_token_secret. I need everything from the equals sign (=) to the next ampersand sign (&). So I need to parse out: hVhzHVVMHySB
Currently, I have the following code:
Const.OAUTH_TOKEN_SECRET = "oauth_token_secret";
Const.tokenSecret =
content.substring(content.indexOf((Const.OAUTH_TOKEN_SECRET + "="))
+ (Const.OAUTH_TOKEN_SECRET + "=").length(),
content.length());
This will start at the beginning of the oauth_token_string, but it will not stop at the next ampersand. I am unsure how to specify to stop at the end of the following ampersand. Can anyone help me?
The indexOf() methods allow you to specify an optional fromIndex. This allows you to find the next ampersand:
int oauth = content.indexOf(Const.OAUTH_TOKEN_SECRET);
if (oauth != -1) {
int start = oath + Const.OATH_TOKEN_SECRET.length(); // or
//int start = content.indexOf('=', oath) + 1;
int end = content.indexOf('&', start);
String tokenSecret = end == -1 ? content.substring(start) : content.substring(start, end);
}
public static Map<String, String> buildQueryMap(String query)
{
String[] params = query.split("&");
Map<String, String> map = new HashMap<String, String>();
for (String param : params)
{
String[] pair = param.split("=");
String name = pair[0];
String value = pair[1];
map.put(name, value);
}
return map;
}
// in your code
Map<String, String> queryMap = buildQueryMap("a=1&b=2&c=3....");
String tokenSecret = queryMap.get(Const.OAUTH_TOKEN_SECRET);
Using String.split gives a much cleaner solution.
static String getValue(String key, String content) {
String[] tokens = content.split("[=&]");
for(int i = 0; i < tokens.length - 1; ++i) {
if(tokens[i].equals(key)) {
return tokens[i+1];
}
}
return null;
}
Click here for a test drive! ;-)
A much better solution is using the Pattern and corresponding Matcher class.
By using a capturing group you can check and "cut out" the the appropriate substring in one step.

Categories