Unable to remove last comma from string - apex-code

I am trying to remove the last comma in a string using the substring method:
system.debug('******************* quoteQuery ' + quoteQuery);
quoteQuery = quoteQuery.subString(0,quoteQuery.Length()-1);
system.debug('******************* quoteQuery ' + quoteQuery);
This is the string debug output:
DEBUG|******************* quoteQuery SELECT phone, lineitemcount, additionalstreet, expirationdate, shippingname, contactid, createdbyid, shippinghandling, additionalstate, billingcity, description, isdeleted, quotetostate, quotenumber, systemmodstamp, fax, totalprice, status, quotetocountry, shippingcity, quotetopostalcode, billingpostalcode, shippingstate, createddate, subtotal, discount, tax, email, shippingpostalcode, lastmodifiedbyid, additionalcountry, billingstate, billingcountry, lastmodifieddate, id, name, pricebook2id, shippingstreet, opportunityid, quotetocity, additionalpostalcode, billingname, additionalcity, shippingcountry, additionalname, grandtotal, billingstreet, issyncing, quotetoname, quotetostreet,
The last comma is not getting removed?
Any help is appreciated.
Thanks.

This will return the complete string
quoteQuery.subString(0,quoteQuery.Length()-1);
So instead of Lenght()-1 try Length()-2
quoteQuery = quoteQuery.subString(0,quoteQuery.Length()-2);

Related

Spring boot 2 #Query named parameter binding value resolution messes up after upgrade from 1.5

We have the following working query using SpringBoot 1.5:
#Query(value = "SELECT DISTINCT c FROM Customer c INNER JOIN c.industry i WHERE " +
"c.role IN :roleFilter " +
"AND (:#{#industryFilter.size()} = 1 OR i.id IN :industryFilter) " +
"AND (:searchString IS NULL " +
"OR CONCAT_WS(' ', c.name, c.name2) LIKE CONCAT('%', :searchString, '%') " +
"OR CONCAT_WS(' ', c.name2, c.name) LIKE CONCAT('%', :searchString, '%')) " +
"AND (:includeDeleted = true OR c.deletedDate is NULL)",
countQuery = "SELECT COUNT(DISTINCT c) FROM Customer c INNER JOIN c.industry i WHERE " +
"c.role IN :roleFilter AND " +
"(:#{#industryFilter.size()} = 1 OR i.id IN :industryFilter) " +
"AND (:searchString IS NULL " +
"OR CONCAT_WS(' ', c.name, c.name2) LIKE CONCAT('%', :searchString, '%') " +
"OR CONCAT_WS(' ', c.name2, c.name) LIKE CONCAT('%', :searchString, '%')) " +
"AND (:includeDeleted = true OR c.deletedDate is NULL)")
Page<Customer> findCustomers(#Param("roleFilter") Set<Role> roleFilter,
#Param("industryFilter") Set<String> industryFilter,
#Param("searchString") String searchString,
#Param("includeDeleted") boolean includeDeleted, Pageable pageable);
Please note how we pass the input to the LIKE: CONCAT('%', :searchString, '%')
After upgrading from springBootVersion = '1.5.17.RELEASE' to springBootVersion = '2.1.3.RELEASE' (we use Gradle) that query will fail at runtime with an exception:
org.hibernate.QueryException: Named parameter not bound : includeDeleted
Replacing CONCAT('%', :searchString, '%') with %:searchString% fixes the problem.
The question I have is: why?
By going into debug mode and following the full callstack, I could see the parameters being correctly retrieved from the method invocation as observed in JdkDynamicAopProxy at line 205 makes a call Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); that results in:
argsToUse = {Object[5]#15562}
0 = {HashSet#15491} size = 4
1 = {HashSet#15628} size = 1
2 = null
3 = {Boolean#15629} false
4 = {PageRequest#15490} "Page request [number: 0, size 20, sort: name: ASC,name2: ASC]"
So far so good. Then, we keep going and the method to call is also correctly resolved:
parameterTypes = {Class[5]#15802}
0 = {Class#198} "interface java.util.Set"
1 = {Class#198} "interface java.util.Set"
2 = {Class#311} "class java.lang.String"
3 = {Class#15811} "boolean"
4 = {Class#9875} "interface org.springframework.data.domain.Pageable"
Then we go a bit further and we get to RepositoryFactorySupport line 599 calling private Object doInvoke(MethodInvocation invocation) throws Throwable which uses private final Map<Method, RepositoryQuery> queries; from the inner class public class QueryExecutorMethodInterceptor implements MethodInterceptor (I am unsure when/how was this variable created and populated), which contains all the queries annotated with #Query in my repository interface.
For our specific case, it contains an entry (last one) that matches the query I am invoking (findCustomers):
queries = {HashMap#16041} size = 3
0 = {HashMap$Node#16052} "public abstract com.swisscom.psp.domain.Customer com.swisscom.psp.repository.CustomerRepository.getOne(java.lang.String)" ->
1 = {HashMap$Node#16055} "public abstract boolean com.swisscom.psp.repository.CustomerRepository.existsWithRole(java.lang.String,java.util.Set)" ->
2 = {HashMap$Node#16058} "public abstract org.springframework.data.domain.Page com.swisscom.psp.repository.CustomerRepository.findCustomers(java.util.Set,java.util.Set,java.lang.String,boolean,org.springframework.data.domain.Pageable)" ->
And expanding that entry I can see where the error comes from, the binding for the :includeDeleted named parameter is simply not there:
value = {SimpleJpaQuery#16060}
query = {ExpressionBasedStringQuery#16069}
query = "SELECT DISTINCT c FROM Customer c INNER JOIN c.industry i WHERE c.role IN :roleFilter AND (:__$synthetic$__1 = 1 OR i.id IN :industryFilter) AND (:searchString IS NULL OR CONCAT_WS(' ', c.name, c.name2) LIKE CONCAT('%', :searchString, '%') OR CONCAT_WS(' ', c.name2, c.name) LIKE CONCAT('%', :searchString, '%')) AND (:includeDeleted = true OR c.deletedDate is NULL)"
bindings = {ArrayList#16089} size = 6
0 = {StringQuery$InParameterBinding#16092} "ParameterBinding [name: roleFilter, position: null, expression: null]"
1 = {StringQuery$ParameterBinding#16093} "ParameterBinding [name: __$synthetic$__1, position: null, expression: #industryFilter.size()]"
2 = {StringQuery$InParameterBinding#16094} "ParameterBinding [name: industryFilter, position: null, expression: null]"
3 = {StringQuery$ParameterBinding#16095} "ParameterBinding [name: searchString, position: null, expression: null]"
4 = {StringQuery$ParameterBinding#16096} "ParameterBinding [name: searchString, position: null, expression: null]"
5 = {StringQuery$ParameterBinding#16097} "ParameterBinding [name: searchString, position: null, expression: null]"
Now, I have the fix as mentioned earlier, but I would still very much like to know the following for future reference:
when and how is the private final Map<Method, RepositoryQuery> queries variable created and populated?
what exactly is causing this error? Did I miss something in the upgrade process? Am I using/mixing deprecated logic/wrong logic and should change the code further?
Our DB is MariaDB 10.1.36
EDIT: In all the places where this behaviour occurred (in some it still occurs), the unbound parameter is always the last one
EDIT2: Someone else also has a similar behaviour after the upgrade, why does this happen? reference
EDIT3: reference and also this weird behaviour has been reported. Interesting enough, I do not get the exception IF I pass already concatenated input to :searchString (eg: %SOMETHING%) and I do get the exception if I leave %:searchString% instead. And yes, moving those parameters in the end solves some errors I had with binding.
EDIT4: Maybe related bug?
Clearly there is something strange going on, so: how does this binding resolution happen exactly?
Thanks in advance and have a nice day
Actually, as far as I know, neither of your two approaches is the correct one to use here for handling LIKE with a wildcard placeholder. Instead, the LIKE expression should be:
LIKE :searchString
To this parameter :searchString you should be binding:
String searchString = "bananas";
String param = "%" + searchString + "%";
// then bind param to :searchString
That is, you bind the entire string, with the % wildcard, together. Then, let the database worry about how to escape it.

USING CASE STATEMENT IN SQL LOADER CONTROL FILE

I have a control file that loads text to oracle but i am trying to strip first 3 digits of Phone number example 1-469-428-5920 to 469-428-5920, please see below control file. what should be the syntax?
I keep getting error below, Please help
thanks
options (ERRORS=1000, SKIP=2)
load data
infile '/clients/vca2/data/API/ADHOC_LOAD/VCA_RP_Hospital_Website_Master_List_VCA.CSV'
replace
into table VCABARK_CDI_DV.RP_HOSPITAL_MASTER_LIST
fields terminated by '|'
OPTIONALLY ENCLOSED BY '"' AND '"'
trailing nullcols
(
HOSPITAL_EXT_NUMBER,
REGION,
HOSPITAL_NAME,
ADDRESS_1,
CITY ,
STATE,
POSTAL_CODE,
PHONE "CASE WHEN SUBSTR(:PHONE,1,2) = '1-' THEN ‘SUBSTR(:PHONE,3)’ ELSE ‘:PHONE’ END",
RCF_PHONE,
FAX ,
EMAIL ,
WEBSITE_CLASS,
DOMAIN,
SHORTNAME,
PMS,
INDICATOR_24_HOUR,
CARECLUB,
HOME_DELIVERY,
APPOINTMENT_CTA,
FREE_FIRST_EXAM,
AAHA ,
AAFP_MEMBER,
CAT_FRIENDLY,
FEAR_FREE ,
LOW_STRESS, E
VECCS,
FACEBOOK_URL,
GMB_URL ,
YELP_URL,
BOOK_URL,
REQUEST_URL,
HOURS_OPERATIONS_URL,
HD_URL_SUBDOMAIN,
HD_URL_ORIGINAL,
PET_PORTAL_URL,
AIS_CLINIC_ID,
AIS_TOKEN
)
You haven't said what error you are getting, but you should have quotes - curly or otherwise - within your case expression. Instead of:
PHONE "CASE WHEN SUBSTR(:PHONE,1,2) = '1-' THEN ‘SUBSTR(:PHONE,3)’ ELSE ‘:PHONE’ END",
use:
PHONE "CASE WHEN SUBSTR(:PHONE,1,2) = '1-' THEN SUBSTR(:PHONE,3) ELSE :PHONE END",
You could also just keep the last 12:
PHONE "SUBSTR(:PHONE, -12, 12)",

Update datetime and a string in Memo field using Java and UCanAccess

I want to update datetime and a string in Memo field using UCanAccess. For example - 5/27/2015 System : some string, this is all I have to update in memo field.
What I have tried - I am converting date to a string using following code:
DateFormat df = new SimpleDateFormat("yyyyMMdd");
Date today = Calendar.getInstance().getTime();
String reportDate = df.format(today);
and then using update query of ucanaccess like this:
st.executeUpdate(" update tblCaseInventory set fldContactNotes = " + reportDate + "' System : CAR Report '" + " where fldCaseNumber = " + rs1.getInt("fldCaseNumber"));
but I am getting an error:
Unexpected token : System.
How to achieve this?
You should use a PreparedStatement to run a parameterized query, something like this:
String sql =
"UPDATE tblCaseInventory " +
"SET fldContactNotes=? " +
"WHERE fldCaseNumber=? ";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
DateFormat df = new SimpleDateFormat("yyyyMMdd");
java.util.Date today = Calendar.getInstance().getTime();
String reportDate = df.format(today);
ps.setString(1, reportDate + " System : CAR Report");
ps.setInt(2, rs1.getInt("fldCaseNumber"));
ps.executeUpdate();
}

Unable to get out of ORA-00907 error

I am getting the missing right paranthesis error. If I remove the comments around iterator.next() statement, its working fine. Unable to figure out whats wrong. There is NO "(" in the data I pass.
String ORACLE_SUM_QUERY = "select item_number, sum(system_quantity) from ITEMS " +
"where sndate = ? and item_id in" +
" (select item_id from ap.system_items where org_id = 4 " +
" and segment1 in ";
......
while (iterator.hasNext()) {
//iterator.next();
String oracleQuery = String.format(ORACLE_SUM_QUERY + "(%s)) GROUP BY item_number", iterator.next());
preparedStat = connection.prepareStatement(oracleQuery);
preparedStat.setDate(1, getSnDate());
The error seems to indicate that the SQL statement you are building up in oracleQuery has an incorrect number of parenthesis. It would probably be helpful to print that SQL statement out before passing it to the prepareStatement call to make debugging easier.
My guess is that the string that is returned by iterator.next() is not what you expect.
Try rewriting your code as
String ORACLE_SUM_QUERY = "select item_number, sum(system_quantity) from ITEMS " +
"where sndate = ? and item_id in" +
" (select item_id from ap.system_items where org_id = 4 " +
" and segment1 in (";
......
while (iterator.hasNext())
{
ORACLE_SUM_QUERY = ORACLE_SUM_QUERY + String.format("%s", iterator.next());
if(iterator.hasNext())
ORACLE_SUM_QUERY = ORACLE_SUM_QUERY + ",";
}
ORACLE_SUM_QUERY = ORACLE_SUM_QUERY + ")) GROUP BY item_number";
preparedStat = connection.prepareStatement(ORACLE_SUM_QUERY);
preparedStat.setDate(1, getSnDate());
This may not get it exactly as I can't test it, but it might get you closer.
Share and enjoy.

how to generate a string from complex format similiar to regular expression?

We know String.format() can accept format with such style:
%[argument_index$][flags][width][.precision]conversion
which is well known as C printf() format, and introduced in java 1.5.
My task is, generating complex format including repeated or optional parameters.
For example, with the format:
select %1 from %2 where %3 and give %1->'*' %2->'users' %3->'age>20'
it returned:
select * from users where age>20
the format can be supported by Stirng.format().
However, I expect a format similar to:
select %1{, } from (%2(as %3)){,} (where %4 (and %5))?
when: %1->'*', %2->'users' %3->null, %3->'age>20'
it returned:
select * from users where age>20
when: %1->Stirng{'name','age'} , %2->'users' %3->'u', %4->'age>20', %5->null
it returned:
select name, age from users as u where age>20
when: %1->Stirng{'name','age'} , %2->'users' %3->'u', %4->null, %5->null
it returned:
select name, age from users as u
when: %1->Stirng{'name','age'} , %2->String{'users','order'} %3->{'u','o'}, %4->'age>20', %5->'u.id=o.userid'
it returned:
select name, age from users as u,orders as o where age>20 and u.id=o.userid
I think now you may understand my meanings. Are there a mature library to do such complex 'anti-regexp' work?
Maybe you are looking for a CustomFormatProvider?
class SqlFormatter:IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
return this;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
StringBuilder concat = new StringBuilder();
string[] formatParts = format.Split(':');
switch (formatParts[0])
{
case "sqlfield":
string sep = "";
if (formatParts.Length>1)
{
sep = formatParts[1];
}
string[] fields = (string[]) arg;
concat.Append(fields[0]);
for (int fieldIndex = 1; fieldIndex < fields.Length; fieldIndex++)
{
concat.Append(sep);
concat.Append(fields[fieldIndex]);
}
break;
case "sqltables":
concat.Append(arg.ToString());
break;
default:
break;
}
return concat.ToString();
}
}
Use it like this:
String sql = String.Format(
new SqlFormatter()
, "select {0:sqlfield:,} from {1:sqltables} "
, new string[]{"name","lname"}
, "person" );
Will give:
"select name,lname from person "
I'll leave the rest of the implementation (and robustness etc) to you...

Resources