Commas in String numbers in Tableau - tableau-api

I am using a number inside a calculation and have to turn it into a string. When I do this, I lose the comma formatting. Using another post:
Changing Number Format in a String
However the formula, I am using:
STR(ROUND(LOOKUP(sum([Actual]),0),0))
Does not seem to be working. The full calculation is here:
If attr([Kpi Nm]) = "Policy Retention Better-than-State Average"
Then str(round(sum([Actual]) * 100, 2)) + "%"
ElseIf attr([Kpi Nm]) = "Policy Retention Improvement (or > 90%)**"
Then str(round(sum([Actual]) * 100, 2)) + "%"
Elseif attr([Kpi Nm]) = "Premium Growth"
Then str(round(sum([Actual]) *100, 2)) + "%"
Elseif attr([Kpi Nm]) = "PIF Growth"
Then str(round(sum([Actual]), 2))
Elseif attr([Kpi Nm]) = "Product Density"
Then "NA"
else
STR(ROUND(LOOKUP(sum([Actual]),0),0))
End
I need to keep the commas on the Actual for the else statement. Any help provided would be much appreciated. The Lookup is supposedly a trick to make it work but does not work in my case.
Thanks,

This should work to keep the commas on the Actual else statement. I had a similar issue and combined a few found answers and this worked for me.
REGEXP_REPLACE(STR(SUM([Actual])),"(\d)(?=(\d{3})+$)","$0,")

I found this regular expression on another site and haven't personally tried it. Not sure if Tableau's regex implementation supports this particular type of expression though because it needs to look ahead. Use it with the regular expression replace function.
(\d)(?=(\d{3})+$)

Related

Is there a way to prevent square brackets being inserted into my string?

I seem to be getting some square brackets being inserted into my string that I am using for a dynamic SOQL query. I'm trying to check if the status of an order is one of the options chosen by the user. Usually I would be able to just throw a list after the IN clause, but because this is a string I'm not able to do so. Instead, I have a loop that iterates through the list of selected statuses and adds to the query string as needed.
I've used the exact same syntax in another org with no issues, so I'm curious as to why this would happen in another one. I've posted the version that is having the issue. Hopefully this isn't too tough to remove.
if(orderStatuses.size() > 0){
query += ' AND ccrz__OrderStatus__c IN (\''+orderStatuses[0]+'\'';
for(Integer i = 1; i < orderStatuses.size(); i++){
query += ', \''+orderStatuses[i]+'\'';
}
query += ')';
}
What I want to have is a string that looks something like
'AND ccrz__OrderStatus__c IN ('Completed', 'Order Submitted')'
But instead I get
'AND ccrz__OrderStatus__c IN ('[Completed', ' Order Submitted]')'
I've also tried using the 'replaceAll()' method to forcibly remove them before the query is run, but they still appear anyways.
query.replaceAll('[\\[\\]]','');
When only selecting one option, it formats perfectly fine without any brackets, but once more than one is picked, this happens.
Any and all help would be greatly appreciated on this one. As I mentioned above, this same exact code (granted with different objects, etc.) was giving me the correct results when run in a different org, so I'm stumped. Thanks in advance!
I was able to reproduce your issue by adding the '[' and ']' to your array "orderStatuses". If I was you, I'd look at those square brackets for your error. It is likely that the square brackets you see are literally part of the strings you're passing. There is also an extra space in the orderStatuses[1] that is further telling me you have something being added to the array you don't want earlier in the code/SQL.
var orderStatuses = [];
orderStatuses.push("[Completed");
orderStatuses.push(" Order Submitted]");
var query = ' AND ccrz__OrderStatus__c IN (\'' + orderStatuses[0] + '\'';
for (var i = 1; i < orderStatuses.length; i++) {
query += ', \'' + orderStatuses[i] + '\'';
}
query += ')';
alert(query)

Capitalizing only the first letters without changing any numbers or punctuation

I would like to modify a string that will have make the first letter capitalized and all other letters lower cased, and anything else will be unchanged.
I tried this:
function new_string=switchCase(str1)
%str1 represents the given string containing word or phrase
str1Lower=lower(str1);
spaces=str1Lower==' ';
caps1=[true spaces];
%we want the first letter and the letters after space to be capital.
strNew1=str1Lower;
strNew1(caps1)=strNew1(caps1)-32;
end
This function works nicely if there is nothing other than a letter after space. If we have anything else for example:
str1='WOW ! my ~Code~ Works !!'
Then it gives
new_string =
'Wow My ^code~ Works !'
However, it has to give (according to the requirement),
new_string =
'Wow! My ~code~ Works !'
I found a code which has similarity with this problem. However, that is ambiguous. Here I can ask question if I don't understand.
Any help will be appreciated! Thanks.
Interesting question +1.
I think the following should fulfil your requirements. I've written it as an example sub-routine and broken down each step so it is obvious what I'm doing. It should be straightforward to condense it into a function from here.
Note, there is probably also a clever way to do this with a single regular expression, but I'm not very good with regular expressions :-) I doubt a regular expression based solution will run much faster than what I've provided (but am happy to be proven wrong).
%# Your example string
Str1 ='WOW ! my ~Code~ Works !!';
%# Convert case to lower
Str1 = lower(Str1);
%# Convert to ascii
Str1 = double(Str1);
%# Find an index of all locations after spaces
I1 = logical([0, (Str1(1:end-1) == 32)]);
%# Eliminate locations that don't contain lower-case characters
I1 = logical(I1 .* ((Str1 >= 97) & (Str1 <= 122)));
%# Check manually if the first location contains a lower-case character
if Str1(1) >= 97 && Str1(1) <= 122; I1(1) = true; end;
%# Adjust all appropriate characters in ascii form
Str1(I1) = Str1(I1) - 32;
%# Convert result back to a string
Str1 = char(Str1);

Formula won't display when certain fields are null

Similar to my first question. I want to show my address in a text box containing the fields as follows
{Company}
{AddLine1}
{AddLine2}
{ZIP}{State}{City}
{Country}
The line that concerns me (and hopefully some of you guys) is {ZIP} {City} {State}. What I want to produce is a consistent addressing format, so that there will be no blank space or indentation even if a ZIP, City or State field has been left blank in the DB. This line should still line up with the rest of the rows and not be indented. I also wish to insert commas between zip, state, city where they are relevant and leave them out where not. For this I have written a formula. Below:
If isnull({BILL_TO.ZIP}) or trim({BILL_TO.ZIP})= "" Then "" else {BILL_TO.ZIP}
+
(If isnull({BILL_TO.State}) or trim({BILL_TO.State})= "" Then ""
else(If not isnull({BILL_TO.ZIP}) and length(trim({BILL_TO.ZIP})) <> 0 Then ", " else "") + {BILL_TO.State})
+
(If isnull({BILL_TO.CITY}) or length(trim({BILL_TO.CITY})) = 0 Then ""
else(
If (not isnull({BILL_TO.State}) and length(trim({BILL_TO.State})) <> 0)
or
(not isnull({BILL_TO.Zip}) and length(trim({BILL_TO.Zip})) <> 0)
Then ", " else "")+ {BILL_TO.CITY}))
The problem is that when there is only a city (no state or zip entered) the formula itself will not display. It does however display when the others are present.
Can anyone see a bug in this code??? Its killing me
Thanks for the help.
Look forward to hearing from you guys!
There are a whole lot of if-then-elses going on in that formula so it's hard to tell, but if it's not displaying anything that probably means that you're using a field somewhere without handling its null condition first. Something simpler might be your best bet:
local stringvar output;
if not(isnull({Customer.Postal Code})) then output:=trim({Customer.Postal Code}) + ', ';
if not(isnull({Customer.Region})) then output:=output + trim({Customer.Region}) + ', ';
if not(isnull({Customer.City})) then output:=output + trim({Customer.City}) + ', ';
left(output,length(output)-2)
Create a formula field for each database field. For example:
// {#CITY}
If Isnull({BILL_TO.CITY}) Then
""
Else
Trim({BILL_TO.CITY})
// {#STATE}
If Isnull({BILL_TO.STATE}) Then
Space(2)
Else
Trim({BILL_TO.STATE})
// {#ZIP}
If Isnull({BILL_TO.ZIP}) Then
Space(5) //adjust to meet your needs
Else
Trim({BILL_TO.ZIP})
Embed each formula field in a text object.
Format text object and its fields to meet your need.
** edit **
I you have data-quality issues, address them in the STATE and ZIP formulas (because they will be a constant length). I would add the commas and spacing the text object.

Perl Xpath: search item before a date year

I have an xml database that contains films, for example:
<film id="5">
<title>The Avengers</title>
<date>2012-09-24</date>
<family>Comics</family>
</film>
From a Perl script I want to find film by date.
If I search films of an exacly year, for example:
my $query = "//collection/film[date = 2012]";
it works exactly and return all films of 2012 year, but if I search all film before a year, it didn't work, for example:
my $query = "//collection/film[date < 2012]";
it returns all film..
Well, as usual, there's more than one way to do it. ) Either you let XPath tool know that it should compare dates (it doesn't know from the start) with something like this:
my $query = '//collection/film[xs:date(./date) < xs:date("2012-01-01")]';
... or you just bite the bullet and just compare the 'yyyy' substrings:
my $query = '//collection/film[substring(date, 1, 4) < "2012"]';
The former is better semantically, I suppose, but requires an advanced XML parser tool which supports XPath 2.0. And the latter was successfully verified with XML::XPath.
UPDATE: I'd like to give my explanation of why your first query works. ) See, you don't compare dates there - you compare numbers, but only because of '=' operator. Quote from the doc:
When neither object to be compared is a node-set and the operator is =
or !=, then the objects are compared by converting them to a common
type as follows and then comparing them. If at least one object to be
compared is a boolean, then each object to be compared is converted to
a boolean as if by applying the boolean function. Otherwise, if at
least one object to be compared is a number, then each object to be
compared is converted to a number as if by applying the number
function.
See? Your '2012-09-24' was converted to number - and became 2012. Which, of course, is equal to 2012. )
This doesn't work with any other comparative operators, though: that's why you need to either use substring, or convert the date-string to number. I supposed the first approach would be more readable - and faster as well, perhaps. )
Use this XPath, to check the year
//collection/film[substring-before(date, '-') < '2012']
Your Perl script will be,
my $query = "//collection/film[substring-before(date, '-') < '2012']";
OR
my $query = "//collection/film[substring-before(date, '-') = '2012']";
Simply use:
//collection/film[translate(date, '-', '') < 20120101]
This removes the dashes from the date then compares it for being less than 2012-01-01 (with the dashes removed).
In the same way you can get all films with dates prior a given date (not only year):
//collection/film[translate(date, '-', '') < translate($theDate, '-', '']

Crystal Reports formula: IsNull + Iif

There are hints of the answer to this question here and there on this site, but I'm asking a slightly different question.
Where does Crystal Reports document that this syntax does not work?
Trim({PatientProfile.First}) + " "
+ Trim(Iif(
IsNull({PatientProfile.Middle})
, Trim({PatientProfile.Middle}) + " "
, " "
)
)
+ Trim({PatientProfile.Last})
I know the solution is
If IsNull({PatientProfile.Middle}) Then
Trim({PatientProfile.First})
+ " " + Trim({PatientProfile.Last})
Else
Trim({PatientProfile.First})
+ " " + Trim({PatientProfile.Middle})
+ " " + Trim({PatientProfile.Last})
but how are we supposed to figure out we can't use the first version?
The documentation for IsNull says
Evaluates the field specified in the current record and returns TRUE if the field contains a null value
and Iif gives
[Returns] truePart if expression is True and falsePart if expression is False. The type of the returned value is the same as the type of truePart and falsePart.
I suppose if you stare at that line about "type of the return value" you can get it, but...
Where does Crystal Reports document that this syntax does not work?
I doubt there is anyplace large enough in the entire universe to document everything that does not work in Crystal Reports...
I know I'm years late on this one, but I came upon this question while trying to figure out the same thing. Funny enough, I couldn't even find the answer in Crystal Reports documentation, but instead in a link to IBM.
Baiscally, if you're using Crystal Reports 8.x or 10.x, ISNULL and IIF don't work together. From the site:
Cause
There is a defect in Crystal Reports 8.x and 10.x that prevents the above formula from working correctly. The 'IIF' and 'IsNull' commands cannot function together, and that includes attempting to use "Not" to modify the IsNull command; for example, IIF(Not IsNull ()).
Resolving the problem
The workaround is to use an "If-Then-Else" statement. For example,
If IsNull({~CRPT_TMP0001_ttx.install_date}) Then "TBD" Else "In Progress"
So if you're using CR 8.x or 10.x (which we are), you're out of luck. It makes it REAL fun when you are concatenating multiple fields together and one of them might be NULL.
I think CR evaluates both IIFs true and false parts. Because you have "Trim({PatientProfile.Middle})" part there, which will be evaluated aganst null value, CR formula evaluator seems just fail.
try this:
currencyvar tt;
currencyvar dect;
tt :={ship.comm_amount};
dect := tt - Truncate(tt);
tt := truncate(tt);
dect := dect * 100;
if dect = 0 then
UPPERCASE('$ ' + ToWords (tt,0 )) + ' ONLY'
else
UPPERCASE('$ ' + ToWords (tt,0) + ' And ' + ToWords(dect,0)) + ' ONLY ';