I have sql select with parameters:
SELECT * FROM tbl t WHERE t.name = ? AND t.age = ? AND t.number = ? AND ... AND t.last_parameter = ? order by t.some desc //many parameterss
I get parameters from form's fields and some fields may be empty. I build sql string:
String sqlStatementText;
MessageFormat sqlStatementTextTemplate = new MessageFormat(Queries.WAR_GET_REPORT_COUNT);
List<Object> parametrs = new ArrayList<>();
if (null == subscriberMSISDN || subscriberMSISDN.length() == 0) {
parametrs.add("");
} else {
parametrs.add(Queries.WAR_REPORT_CALLING_NUMBER);
}
if (null == operatorID || operatorID.length() == 0) {
parametrs.add("");
} else {
parametrs.add(Queries.WAR_REPORT_OPERATOR_AVAYA_ID);
}
if (null == operatorNickname || operatorNickname.length() == 0) {
parametrs.add("");
} else {
parametrs.add(Queries.WAR_REPORT_NICKNAME);
}
if (null == msg1 || msg1.length() == 0) {
parametrs.add("");
} else {
parametrs.add(Queries.WAR_REPORT_MSG1);
}
if (null == msg2 || msg2.length() == 0) {
parametrs.add("");
} else {
parametrs.add(Queries.WAR_REPORT_MSG2);
}
sqlStatementText = sqlStatementTextTemplate.format(parametrs.toArray());
ant them i do it:
try (Connection sqlConnection = connectionPool.getConnection();
PreparedStatement sqlStatment = sqlConnection.prepareStatement(sqlStatementText)) {
int paramID = 1;
sqlStatment.setInt(paramID++, 1);
sqlStatment.setDate(paramID++, new java.sql.Date(fromDate.getTime()));
sqlStatment.setDate(paramID++, new java.sql.Date(toDate.getTime()));
if (null != subscriberMSISDN && subscriberMSISDN.length() != 0) {
sqlStatment.setString(paramID++, subscriberMSISDN);
}
if (null != operatorID && operatorID.length() != 0) {
sqlStatment.setString(paramID++, operatorID);
}
if (null != operatorNickname && operatorNickname.length() != 0) {
sqlStatment.setString(paramID++, operatorNickname);
}
if (null != msg1 && msg1.length() != 0) {
sqlStatment.setString(paramID++, msg1);
}
if (null != msg2 && msg2.length() != 0) {
sqlStatment.setString(paramID++, msg2);
}
try (ResultSet resultSet = sqlStatment.executeQuery()) {
while (resultSet.next()) {
count = resultSet.getInt(1);
}
resultSet.close();
sqlStatment.close();
sqlConnection.close();
}
But i thig it not correctly. But I dont know how build sql query with many paramaters and if some parameters maybe empty.
Switch to an ORM. They will have some form of criteria-like object.
Use the param is null or column = param SQL syntax. select x from y where (? is null OR column1 = ?)
You need to set the value of the param twice, and the input value can not legitimately be null.
There is no way to do it, given the SQL statement you have.
You need to change the SQL statement WHERE conditions from things like t.name = ? to t.name = nvl(?, t.name). Then, you can bind a NULL there and the condition will always evaluate to true (so it's not acting as a filter -- which is what you want when the user leaves the field blank).
Or -- a better approach if you can do it, it's even better to use conditions like you've got them (e.g., t.name= ?), but build the conditions dynamically based on what fields the user give you. That is, for example, if the user leaves the "name" parameter blank, just omit the t.name = ? condition entirely.
That leaves you with a shorter SQL statement that makes the Oracle optimizer's job a little bit easier. With the t.name = nvl(?, t.name) approach I gave you above, you're relying on some pretty advanced optimizer features to get the best performance, because it's not immediately clear whether, say, it would be good or bad for the optimizer to use an index on t.name.
Related
My application cannot find the roommate I added to the room, see sequence:
Please select one of the following options:
Add a room in the apartment[1]
Search for a room in the apartment[2]
Add a roommate to an existing room[3]
Check if a room has a roommate[4]
Count the number of existing rooms that have roommates living in them[5]
3
What is the name of this roommate?
kack
What is the surname of thid roommata?
han
What is the age of this roommate?
20
Which room you want to add this roommate in?[A]/[B]/[C]
b
The roommate was added to the room!
Do you want to continue using the App? (Y/N)
y
Please select one of the following options:
Add a room in the apartment[1]
Search for a room in the apartment[2]
Add a roommate to an existing room[3]
Check if a room has a roommate[4]
Count the number of existing rooms that have roommates living in them[5]
4
What is the ID of the room?[A]/[B]/[C]
b
Sorry! There is no roommate in this room.
I am not sure where I have to rewrite. I want to know which part is wrong and how I should rewrite my code. The code is following, and the first part is to add roommate and the second part is to check if there is a roommate in the room:
public boolean addRoommate(String pName, String pSurname, int pAge, char pID) {
boolean response = false;
if (roomA != null && roomA.getID() == (pID)) {
Roommate newRoommate = new Roommate(pName, pSurname, pAge);
response = true;
} else if (roomB != null && roomB.getID() == (pID)) {
Roommate newRoommate = new Roommate(pName, pSurname, pAge);
response = true;
} else if (roomC != null && roomC.getID() == (pID)) {
Roommate newRoommate = new Roommate(pName, pSurname, pAge);
response = true;
}
return response;
}
Here is the second part of the code, which is where I check for roommate:
public Roommate checkRoommate(char pID) {
Roommate response = null;
if (roomA != null && roomA.getID() == (pID) && roomA.getRoommate() != null) {
response = roomA.getRoommate();
} else if (roomB != null && roomB.getID() == (pID) && roomB.getRoommate() != null) {
response = roomB.getRoommate();
} else if (roomC != null && roomC.getID() == (pID) && roomC.getRoommate() != null) {
response = roomC.getRoommate();
}
return response;
}
You need to put the rommate into a rool, for example this way:
roomA.setRoomMate(newRoommate)
Someone can tell me how can I reuse rootOpt object inside of my forEach. Is there any way to reuse this variable? I have the following message "Can not resolve symbol rootOpt" when I write rootOpt.getChildOptions() inside my forEach. Please find below what I did:
I have tried to rewrite the for loop below by using stream. Thank you
opts.stream()
.flatMap(rootOpt -> rootOpt.getChildOptions().stream())
.forEach(subOpt -> {
if (subOpt.getOptLogic() != null && subOpt.getOptLogic().getCant() != null && !"".equals(subOpt.getOptLogic().getCant())) {
String[] oldCHs = subOpt.getOptLogic().getCant().split("( )");
OptionList samePriceSibs = getSamePriceS(rootOpt.getChildOptions(), subOpt);
for (String ch : oldCHs) {
Option chRootOpt = childOptCodeToParentOptMap.get(ch.toUpperCase());
if (chRootOpt != null) {
if (!DoesVariableOptionsCompletelyExcludeOther(samePriceSibs, chRootOpt.getChildOptions())) {
List<OptionList> tmp = new ArrayList<OptionList>();
tmp.add(samePriceSibs);
tmp.add(chRootOpt.getChildOptions());
optionsPairsToRemoveCHs.add(tmp);
}
}
}
}
});
for (Option rootOpt : opts) {
for (Option subOpt : rootOpt.getChildOptions()) {
if (subOpt.getOptLogic() != null && subOpt.getOptLogic().getCant() != null && !"".equals(subOpt.getOptLogic().getCant())) {
String[] oldCHs = subOpt.getOptLogic().getCant().split("( )");
OptionList samePriceSibs = getSamePriceS(rootOpt.getChildOptions(), subOpt);
for (String ch : oldCHs) {
Option chRootOpt = childOptCodeToParentOptMap.get(ch.toUpperCase());
if (chRootOpt != null) {
if (!DoesVariableOptionsCompletelyExcludeOther(samePriceSibs, chRootOpt.getChildOptions())) {
List<OptionList> tmp = new ArrayList<OptionList>();
tmp.add(samePriceSibs);
tmp.add(chRootOpt.getChildOptions());
optionsPairsToRemoveCHs.add(tmp);
}
}
}
}
}
}
The scope of rootOpt ends at the closing parenthesis.
You could write it like this instead
opts.stream().forEach(rootOpt ->
rootOpt.getChildOptions().stream().forEach(subOpt -> {
...
});
);
However streams were not really intended to simply replace for loops. A more canonical way of using them would be something like this.
Stream<List<OptionList>> optionsPairsToRemoveCHs = opts.stream()
.flatMap(rootOpt ->
rootOpt.getChildOptions().stream()
.filter(subOpt -> subOpt.getOptLogic() != null && subOpt.getOptLogic().getCant() != null && !"".equals(subOpt.getOptLogic().getCant()))
.flatMap(subOpt -> {
String[] oldCHs = subOpt.getOptLogic().getCant().split("( )");
OptionList samePriceSibs = getSamePriceS(rootOpt.getChildOptions(), subOpt);
return Stream.of(oldCHs)
.map(ch -> childOptCodeToParentOptMap.get(ch.toUpperCase()))
.filter(chRootOpt -> chRootOpt != null && !DoesVariableOptionsCompletelyExcludeOther(samePriceSibs, chRootOpt.getChildOptions()))
.map(chRootOpt -> Arrays.asList(samePriceSibs, chRootOpt.getChildOptions()));
})
);
I didn't test that code though. Also refactoring it into several methods as mike suggested would help making it easier to read.
Is there a best practice for handling optional sub-queries? So say my search service has
query = builder.bool().must(createQuery(field1, term1)).must(createQuery(field2, term2)).createQuery();
createQuery(field, term) {
if(term != null) {
return builder.keyword().onField(field).matching(term).createQuery();
}
return null;
}
With the default QueryBuilder if I use a query like this and the term is null, the resulting query is "+term1 +null" or something along those lines, which causes a null pointer exception when the query is executed against the index. Is there a recommended way to avoid this issue? I was thinking about a custom QueryBuilder but I'm not sure how to tell the fulltext session to use my implementation rather than it's default. The only other way I can think of is something like
query;
query1 = createQuery(field1, term1);
query2 = createQuery(field2, term2);
if(query1 != null && query2 != null) {
query = builder.bool().must(query1).must(query2).createQuery();
} else if(query1 != null && query2 == null) {
query = query1;
} else if(query1 == null && query2 != null) {
query = query2;
}
createQuery(field, term) {
if(term != null) {
return builder.keyword().onField(field).matching(term).createQuery();
}
return null;
}
But this gets really messy really fast if there are more than a handful of sub-queries.
What you might do is introducing a method whose sole purpose would be to add a "must" in a null-safe way. I.e. do something like this:
BooleanJunction junction = builder.bool();
must(junction, createQuery(field1, term1));
must(junction, createQuery(field2, term2));
query = junction.createQuery();
void must(BooleanJunction junction, Query query) {
if (query != null) {
junction.must(query);
}
}
Query createQuery(String field, Object term) {
if(term != null) {
return builder.keyword().onField(field).matching(term).createQuery();
}
return null;
}
This would take out the "fluidity" of the BooleanJunction API, but since it's at the top-level only, I guess it's not so bad.
what about this
org.json.JSONObject json = new org.json.JSONObject();
json.put(field1, term1);
json.put(field2, term2);
...
bool = builder.bool();
for (Iterator keys = json.keys(); keys.hasNext();) {
String field = (String) keys.next();
String term = (String) json.get(field);
q = createQuery(field, term);
if (q != null) {
bool.must(q);
}
}
query = bool.createQuery();
if you have duplicate fields with different terms you must use this :
org.json.JSONObject json = new org.json.JSONObject();
json.append(field1, term1);
json.append(field2, term2);
...
bool = builder.bool();
for (Iterator keys = json.keys(); keys.hasNext();) {
String field = (String) keys.next();
JSONArray terms = (JSONArray) json.get(field);
for (int i = 0; i < terms.length(); i++) {
String term = (String) terms.get(i);
q = createQuery(field, term);
if (q != null) {
bool.must(q);
}
}
}
query = bool.createQuery();
I have the following method
public Message JavaMethod(String id1, String id2)
In which I need to call a Dao class's method to verify that an user with the provided Id exist, and if it does not, create a message detailing the Id that couldn't be found on the database with the following method:
createMessage("Message string",Enum.TYPE,IdofMissingUser);
At first I thought of doing it like this:
public Message JavaMethod(String id1, String id2) {
if(Dao.findUser(id1) == null || Dao.findUser(id2) == null){
return createMessage("Error",Enum.Error,id1);
}else{
//do some other stuff
}
}
But obviously this way I won't know which of the ids has not been found.
So I went ahead and created an ugly if else cycle:
public Message JavaMethod(String id1, String id2) {
if (Dao.findUser(id1) == null) {
return createMessage("Error", Enum.Error, id1);
} else if (Dao.findUser(id2) == null) {
return createMessage("Error", Enum.Error, id2);
} else {
// Do stuff after veryfing users exists
return createMessage("All OK", Enum.OK, messageData);
}
}
But I'm not feeling really confident that this is the best solution for this basic issue.
What would you guys recommend in this case?
You could wrap the ids in a list and use a for loop:
public Message someMethod(String id1, String id2) {
for (String id: Arrays.asList(id1, id2)) {
if (Dao.findUser(id) == null) {
return createMessage("Error", Enum.Error, id);
}
}
// Do stuff after verifying users exists
return createMessage("All OK", Enum.OK, messageData);
}
If you're only ever going to have two IDs, you could deal with a shorthand boolean. Question is whether that makes it less readable though. E.g.
public Message JavaMethod(String id1, String id2) {
User user1 = Dao.findUser(id1);
User user2 = Dao.findUser(id2);
if(user1 == null || user2 == null){
return createMessage("Error",Enum.Error,user1 == null ? id1 : id2);
}else{
//do some other stuff
}
}
This also doesn't deal with if both of the IDs were null, for that you could extend it:
public Message JavaMethod(String id1, String id2) {
User user1 = Dao.findUser(id1);
User user2 = Dao.findUser(id2);
if(user1 == null || user2 == null){
return createMessage("Error",Enum.Error,user1 == null && user2 == null? both : user1 == null ? id1 : id2);
}else{
//do some other stuff
}
}
You'd need to define what you would return for the both variable
More details on the shorthand boolean annotation can be found here
I am trying to do below things. Plesse check.
rule "new rule"
salience -101
dialect "mvel"
when
$pricingLineItem : PricingLineItem( $ackId : ackId, $prefix : prefix )
$baseUpChargeConfig : BaseUpChargeConfig( $baseOptionId : baseOptionId,
prefix == $prefix )
$pricingOptionType : PricingOptionType( ackId == $ackId,
$optionId : optionId, $optionValue : optionValue )
$baseOptionConfig : BaseOptionConfig( bOptionValue == $optionValue,
bOptionCode == $optionId ,id == $baseOptionId )
then
$pricingLineItem.increment($baseOptionId);
System.out.println("excuted - "+ $baseOptionId +" "+$baseOptionConfig);
end
There will multiple BaseUpChargeConfig object match for one PricngLineItem. In the BaseUpChargeConfig object, we are getting all related BaseOptionConfig object and then trying to matche with PricingOptionType object of PricingLineItem. I need to take the best BaseUpChargeConfig object having maximum match with the PricingOptionType object of PricngLineItem.
EDIT
Say I have one PricingLineItem object with ackID, prefix value.
Now, I have multiple set of BaseUpChargeConfig object based on prefix value of PricingLineItem.
Now on ackId value, I have certain set of PricingOptionType object in rule engine.
and Also on baseOptionId value, I have multiple BaseOptionConfig object.
In PricingOptionType and BaseOptionConfig object, I need to compare the optioncode and option value.
If both are matching, I need to collect all matched pricing option type for a perticuler BaseUpChrageConfig.
In the same way, this will check for all other BaseUpChrageConfig object BaseOptionConfig and match.
Now the highest matched BaseOptionConfig object ; we will select that BaseUpChargeConfig as best object for our purpose.
I hope it would be clear for you.
Currently I am doing through java method by passing all three and calculating in java.
public void matchOptions(BaseUpChargeConfig config, List pricingOptionList,
List baseOptionList) {
if ((pricingOptionList != null && !pricingOptionList.isEmpty())
&& (baseOptionList != null && !baseOptionList.isEmpty())) {
List<PricingOptionType> matchedOption = null;
matchedOption = new ArrayList<PricingOptionType>();
for (PricingOptionType pOption : pricingOptionList) {
int matchCount = 0;
for (BaseOptionConfig bConfig : baseOptionList) {
boolean optioncodeMatch = pOption.getOptionCode() == bConfig.getBaseOptionCode();
boolean optionValueMatch = pOption.getOptionValue() == bConfig.getBaseOptionValue();
if (optioncodeMatch && optionValueMatch) {
matchedOption.add(pOption);
matchCount++;
}
}
if (matchCount > 0) {
if (bestBaseUpChargeConfig != null) {
optionMatchCount = matchCount;
bestBaseUpChargeConfig = config;
matchedPrcOptionList = matchedOption;
} else if (matchCount == optionMatchCount) {
bestBaseUpChargeConfig = null;
matchedOption = null;
matchedPrcOptionList.clear();
} else if (matchCount > optionMatchCount) {
optionMatchCount = matchCount;
bestBaseUpChargeConfig = config;
matchedPrcOptionList = matchedOption;
} else {
// do nothing
}
}
}
} else {
// do nothing
}
}
Thanks
This compiles with 5.5, so it shouldn't be a problem with 6.x either.
The duplication of the accumulate can't be helped unless you consider a more complicated evaluation involving derived facts.
rule "find best BaseUpChargeConfig"
when
// pick up some PricingLineItem
$pli: PricingLineItem( $prefix: prefix, $ackId : ackId )
// it should have a BaseUpChargeConfig with a matching prefix
$bucc: BaseUpChargeConfig( prefix == $prefix,
$baseOptionId : baseOptionId )
// count BaseOptionConfigs (linked to BaseUpChargeConfig) matching
// PricingOptionTypes, by option id/code and option value
accumulate(
BaseOptionConfig( id == $baseOptionId,
$ocod: bOptionCode, $oval: bOptionValue )
and
PricingOptionType( ackId == $ackId,
optionId == $ocod, optionValue == $oval );
$count: count(1) )
// The $count computed above is the maximum if we don't have another
// BaseUpChargeConfig (for that prefix) where the count of the
// subordinate BaseOptionConfigs is greater than $count
not(
( BaseUpChargeConfig( this != $bucc,
prefix == $prefix,
$baseOptionId2 : baseOptionId )
and
accumulate(
BaseOptionConfig( id == $baseOptionId2,
$ocod2: bOptionCode, $oval2: bOptionValue )
and
PricingOptionType( ackId == $ackId,
optionId == $ocod2, optionValue == $oval2);
$count2: count(1);
$count2 > $count ) ) )
then
System.out.println( "best BaseUpChargeConfig: " + $baseOptionId );
end