I am using report builder and SSRS to create a report that needs to count the number of a given character in a string. I have looked for a function that might do this to no avail. Is there a way to pull this off?
StringCount("The quick brown fox jumps over the lazy dog","o")
This function should return 4 for the o in brown, fox, over, and dog.
So there isn't a quick and easy function that does exactly what you want, but there is a way to do this in SSRS using LEN and REPLACE. So to test, I made a simple dataset with just two fields, one value each. The first is a string of random letters and the second uses your example sentence.
SELECT
'AAABBBCCCWWWLLLaaaoooSSSEEEWWW',
'The quick brown fox jumps over the lazy dog' AS QuickFox
The expression will use REPLACE to replace the desired character with nothing in the string. You can then subtract that value from the full length of the string to get the correct count. This also uses UCASE to catch both upper and lower case variations.
= LEN(Fields!QuickFox.Value) - LEN(REPLACE(UCASE(Fields!QuickFox.Value),"O",""))
To finish this more fully, you could take in a parameter or a field and apply the UCASE function. This should get you an accurate count of all possible instances of a letter in a given string.
= LEN(Fields!QuickFox.Value) - LEN(REPLACE(UCASE(Fields!QuickFox.Value), UCASE(Parameters!CharToSearch.Value),""))
You can use regex combined with LEN to do this.
The following is based on having two report parameters, one is the string to search and the other is the character to search for. You may need to modify to suit your purpose but the principle is sound.
=LEN(System.Text.RegularExpressions.Regex.Replace
(UCASE(Parameters!SearchThis.Value)
, "[^" + UCASE(Parameters!searchChar.Value) +"]"
, ""
))
Notes:
RegEx is not one of my strong points so there may be cleaner ways to do this...
If you want a case sensitive search, remove the UCASE statements
Related
data output
I am pretty new to Webi and am having an issue creating a variable. I'm trying to check if there is more than 1 email address for each entity legacy account number and if 1 of the contact names contains "Annual Report". So when I flag each entity legacy account number for no email only the ones without a contact name that contains "Annual Report" will be pulled. In the example above only the yellow groups should be called no email. Right now all of them are being pulled into no email. I have tried using if and match as those are what I am most familiar with. Does anyone have any suggestions?
There are number of ways you could do this. I am going to give an example using two variables, but you could easily combine them into one.
Has No Email Var=If(Match(Upper([Contact EmailAddress]); "NOEMAIL*"); 1; 0)
Annual Report Contact Name Var=If(Match(Upper([Contact Name]); "ANNUAL REPORT*"); 1; 0)
Then you would apply a report filter with two components...
Has No Email Var = 1
AND
Annual Report Contact Name Var = 0
Let me explain a few things...
The purpose of the Upper function is the Match function is case sensitive. If you know your email address are always lower case then you could remove that the Upper function and have it match on "noemail*".
It is significant that I only have a asterisk ("*") at the end of the string being sought. That will only find a match where the corresponding column value starts with that string. If you want it to be true whenever the string is found anywhere in the column being searched you would be asterisks on both ends.
You could also put limiting criteria in your query filter. But here is where thing can get confusing. Within the query filter you can choose the Matches pattern operator. However, the wildcard character is different ("%" rather than "*") and you do not put double-quotes around your search text. So you would have some thing like this...
Contact EmailAddress Matches pattern noemail%
AND
Contact Name Different from pattern Annual Report%
I am sure you noticed I didn't convert the search text to uppercase. In the Query Panel Web Intelligence is case-insensitive and would likely follow the case-sensitivity of the database of the source data. All of our databases are case-insensitive so if yours is case-sensitive you may need to play around this this a bit. Or just go with the approach of creating the variables and report filters as I initially laid out.
If you want a wildcard for a single character rather than multiple characters (which is what "*" and "%" will do) you need to use a "?" within your variable definition or a "_" in your query filter.
Hope this helps,
Noel
I have a column in my access database table, I ran a query to make it proper case by using StrConv([MyColumn],3) but last two letters are state names and this query makes SOmeThing, soMethINg, NY to Something, Something, Ny,
I want the result as Something, Something, NY
Is there a another query I can run after to capitalize last letter?
You can use:
UcaseLast: Left([YourColumn], Len([YourColumn]) - 1) & UCase(Right([YourColumn], 1))
Well, most people would tell you to store your 'address', 'city', and 'state' as separate fields. Then you Proper Case each separately and concatenate them together. If you can do that... that is your best approach.
If this is a database or file that's been tossed at you and you can't make the field/table changes... it's still possible to get your desired results. However, you better make sure all strings end with your state code. Also make sure you don't have foreign addresses since Canadian (and other countries) use more that two letters for the province code at the end.
But if you are sure all records contain two letter state abbreviations, you can continue with the following:
MyColumnAdj: StrConv(Mid([MyColumn],1,len([MyColumn])-2),3) + StrConv(right([MyColumn],2),1)
This takes the midstring of your [MyColumn] from position 1 to the length of your [MyColumn] minus 2 (leaving off the state code) and it Proper Case's it all.
It then concatenates (using the plus sign) to a rightstring of [MyColumn] for a length of 2 and Upper Case's it.
Once again, this is dangerous if the field doesn't have the State Code consistently at the end of the string.
Best of luck. Hope this helps. :)
Using Microsoft Access 2010
I have a field for [box_no]. I need to run a query to get a list of all box numbers within a range. Here is my issue....several box numbers have a letter in front of them (typically the letter "T"), several do not. If I use *Like* '*'+[Search Box Number]+'*' in the query I have no problem searching for a box with or without a letter. I can use *Between [beginning box number] And [ending box number]* in the query to retrieve a range of box numbers, as long as I include the corresponding letter(s). Is there a string or something I can write to get the result I want?
EXAMPLE: I want to retrieve a report for box numbers 732913000 to 732914000. 732913000 through 73213055 do not have a letter in the beginning. 73213056 has the letter T in the beginning (T73213056). I need to make sure all box numbers appear in the report, regardless of the beginning character.
I hope this makes sense! :-)
You can set up a function in VBA to strip out the leading character if its not numeric and then use that function in your query.
The function would be;
Function StripChar(BoxNumber As String) As String
If IsNumeric(Left(BoxNumber, 1)) Then
StripChar = BoxNumber
Else
StripChar = Right(BoxNumber, Len(BoxNumber) - 1)
End If
End Function
You can then use the function in your query;
SELECT BoxNumber, StripChar([BoxNumber]) AS Stripped
FROM <YourTable> WHERE (StripChar([BoxNumber]) Between 100 And 200));
You could probably put the whole thing together using SQL but it's probably easier to work with this because you can easily amend the VBA function to do the adaptation.
I have the following data in TableA...
ID | Text
---------------------------------------------
1 | let's find this document
2 | docments are closed
...and if I do the following select...
select Text from TableA where Text like '%doc%';
...I seem to get a strange result. Both rows are returned. With this select, should it not only return row 1? I would have thought that..
select Text from TableA where Text like 'doc%';
...would have returned just row 2. Am I missing something?
What I'm trying to do is run 3 separate searches across this data as part of my searching tool. The first match is to look for the specified pattern "doc" at the beginning of a string, secondly, my next match looks for the same pattern but at the end of a string, and thirdly, identify if the pattern appears anywhere within the text - so can have text surrounding it. Ideally, the first search would only match row 2, the second search would return no results and the third result would only return row 1.The reason for doing it like this is I wanted to try and get a feel for how the pattern matched the string. Would make it easier to read the results to know that the pattern for a given row matched either (a) at the beginning, (b) at the end, (c) anywhere in the middle.Had thought about using regexp, but my data is unicode.
No, the first query returns both rows, because % means 0 or more characters. So if doc is the first thing appearing in the field, it matches the %doc% pattern as well.
But you're right on the second query, it will only return row 2.
doc_% should match it at the beginning, having at least one character after it.
%_doc should match it at the end, having at least one character before it.
%_doc_% should match it anywhere, having at least one character before and after it.
Note that these strict criteria fail to find the exact string "doc", i.e. with nothing before or after it. You may want to include this case in, say, query #1, by loosening it:
doc% should match it at the beginning, having any number of characters after it.
Let's consider a multiple selection parameter on a report: Employee
This parameter has a lot of possible values. Initially nothing is shown on the list and there is a textfield search parameter associated, that updates the Employee selection list with top n matches for the searched string.
If the entered search query is John Doe we can imagine that now the selection list shows:
John Doe
...
Xavier John Doesson
Now I can select as many items as I want from this filtered list, but if I want to select both John Doe and Alicia Keys happens the following:
First when I enter the search string "John Doe" the selection list gets populated accordingly
I select John Doe - OK
I enter search string "Alicia Keys", the selection list gets populated also
Selection of John Doe is gone - I want to be able to select both Alicia and John at the same time, but I don't want to go through a thousands of names long selection list
Update:
Forgot to mention that we have an OLAP cube in the background with dimension 'Employee'. This dimension is used as the source of the parameter and the param dataset uses MDX to fetch the values, therefore the SQL solution cannot be applied here.
The current solution creates an custom set with MDX Filter and Head functions and then this set is used in the ROWS-part of the MDX query.
Here is how the set created:
SET setEmployees AS {
HEAD(
FILTER( [Employees].[Employees].ALLMEMBERS,
INSTR([Employees].[Employees].CURRENTMEMBER.Name,#EmployeeSearch,1 >= 1 )
)
,100)
}
Basically the problem with this solution is that how do you add multiple search strings to the instr function
Is there a common solution to this kind of situation? Am I approaching the problem from wrong direction?
What you could do is make the search parameter more flexible, so you can handle input such as:
John OR Jane
If "OR" queries are more common than "AND" queries you could support it with queries such as:
John Jane
Note that this may throw people off, because the search features they're used to (such as Google search) typically tend interpret multiple words in the "AND" sense.
Anyhow, the tricky bit of course is the SQL behind the Employee data set. This should use the search parameter in a more flexible way. You haven't specified how that's currently working, but I imagine you may be using something like:
WHERE Employee.FullName LIKE '%' + #SearchParameter + '%'
You would need to extend that to support "OR" queries. There's a whole range of solutions for that, from quick 'n dirty handmade SQL (e.g. string split combined with WHERE...IN) to full-text querying. Choose a solution that's best for your situation.
If you have a fixed number of search terms than you can do something like the following.
FILTER( [Employees].[Employees].ALLMEMBERS,
INSTR([Employees].[Employees].CURRENTMEMBER.Name,#EmployeeSearch1,1 >= 1) OR
INSTR([Employees].[Employees].CURRENTMEMBER.Name,#EmployeeSearch2,1 >= 1)
)
Even if you can do that, I do not recommend it. You don't have the luxury to index Analysis Services like you do SQL. A better possible approach would be to query your data warehouse for the employees and return the appropriate keys, and then filter by those keys in your MDX statement.