Passing multiple values to SSRS using MDX - reporting-services

I am running the following command for getting a multi value report
StrToSet
("[Dim Branch].[HierarchyB-T-C].[Trading Code].&[" +
Replace(
Join(
Parameters!TradingName.Value,"],"
) +"]",",",",[Dim Branch].[HierarchyB-T-C].[Trading Code].&["),",")
But I'm getting an error
'The Syntax for 'Join' is incorrect'.
I don't know what I am doing wrong. Can anyone correct me please?
If I change it to StrToSet(#TradingName, Constrained) it works for single value, but I'd like to pass multiple values.

Do you need curly braces to form a set? I have added one at the start of the below ... a little unsure where the end of your string is - does it end like this .&["?!
StrToSet(
"{[Dim Branch].[HierarchyB-T-C].[Trading Code].&["
+
Replace(
Join(Parameters!TradingName.Value,"],") + "]"
, ","
, ",[Dim Branch].[HierarchyB-T-C].[Trading Code].&["
)
,","
)
If Parameters!TradingName.Value is equal to a string of this format MEC,RSA then maybe join is not required:
StrToSet(
"{"
+
Replace(
"[Dim Branch].[HierarchyB-T-C].[Trading Code].&["
+
Parameters!TradingName.Value
, ","
,"],[Dim Branch].[HierarchyB-T-C].[Trading Code].&["
)
+
"]}"
,constrained)

To pass multiple value from parameter, i just followed the steps
1 Add parameters and name it like
Under dataset properties (shared dataset properties as well) , the Parameters tab write an expression like this way
=Split(Parameters!TradingName.Value,",")
in Shared dataset, write the MDX with WHERE (StrToSet(#TradingName))
SELECT
{[Total]} ON COLUMNS
,
{
[Dim Account].[Account Type].&[Income]
}
*
STRTOMEMBER("[Dim Fiscal Year].[HierarchyFiscal].[E Month].&[" + #FiscalYear +"]&[" + FORMAT(Now(),"MMMM") +"].PREVMEMBER")
*
ORDER
(
{
[Dim Branch].[Branch Name].[Branch Name]
},[Total], BDESC
)
ON ROWS
from [CubeProfitLoss]
WHERE (StrToSet(#TradingName))
when you want to preview the multiple value, make sure you are using , to separate trading name likewise

Related

SSRS Report Parameters passed out

I am currently building a number of logging and analysis tools to keep tabs on our SQL environment. We are currently using SQL Server 2014.
What I want to do is keep check of all the parameters that are passed to our reports during the day. All of the reports are currently using stored procedures so in my table or a select statement based on a table is output the stored procedure with the parameters for every time the report was run.
At the end of the day I would then like to be able to take the outputted statement and run it in SSMS without having to use the report. I have been looking at the ExceutionLogStorage table and the ExecutionLog view's and though it has most of the information that I need, the parameters are not in an easily usable state.
Has anyone done something similar to what I have described?
You need to add logging part in your original SP, for example:
Alter procedure a
(#parameter)
As
Begin
..
..
Insert into loggingTable(col)
Values(#parameter)
..
..
End
Then query directly against that loggingTable for getting the history of used parameters
A Google search around this topic quickly brought up the following blog post already identified by the OP as useful and shown below (this query itself is actually an expansion of work linked to by LONG's answer below)
SELECT TOP 1 ParValue
FROM (
SELECT els.TimeEnd
, IIF(CHARINDEX('&' + 'ParameterName' + '=', ParsString) = 0, 'ParameterName',
SUBSTRING(ParsString
, StartIndex
, CHARINDEX('&', ParsString, StartIndex) - StartIndex)) AS ParValue
FROM (SELECT ReportID, TimeEnd
, '&' + CONVERT(VARCHAR(MAX), Parameters) + '&' AS ParsString
, CHARINDEX('&' + 'ParameterName' + '=', '&' + CONVERT(VARCHAR(MAX), Parameters) + '&')
+ LEN('&' + 'ParameterName' + '=') AS StartIndex
FROM ExecutionLogStorage
WHERE UserName='UserName' -- e.g. DOMAIN\Joe_Smith
) AS els
INNER JOIN [Catalog] AS c ON c.ItemID = els.ReportID
WHERE c.Name = 'ReportName'
UNION ALL
SELECT CAST('2000-01-01' AS DateTime), 'ParameterName'
) i
ORDER BY TimeEnd DESC;
Both these approaches though really only give us a starting point since they (variously) rely upon us knowing in advance the report name and parameter names. Whilst we can quickly make a couple of changes to Ken Bowman's work to get it to run against all executions of all reports, we still have the problem that the query hardcodes the parameter name.
The parameters required to execute a report are stored on the Catalog table in the Parameter column. Although the column has a datatype ntext, it is actually storing an XML string. Meaning we can use an XPath query to get at the parameter names
with
CatalogData as (
select ItemID, [Path], [Name], cast(Parameter as xml) 'ParameterXml'
from Catalog
where [Type] = 2),
ReportParameters as (
select ItemID, [Path], [Name], ParameterXml, p.value('Name[1]', 'nvarchar(256)') 'ParameterName'
from CatalogData
cross apply ParameterXml.nodes('/Parameters/Parameter') as Parameters(p))
select *
from ReportParameters;
Executing this query will list all reports on the server and their parameters. Now we just need to combine this with Ken Bowman's query. I've gone with a CTE approach
with
CatalogData as (
select ItemID, [Path], [Name], cast(Parameter as xml) 'ParameterXml'
from Catalog
where [Type] = 2),
ReportParameters as (
select ItemID, [Path], [Name], p.value('Name[1]', 'nvarchar(256)') 'ParameterName'
from CatalogData
cross apply ParameterXml.nodes('/Parameters/Parameter') as Parameters(p))
select
els.TimeEnd
, c.[Name]
, rp.ParameterName
, iif(
charindex(
'&' + rp.ParameterName + '=', ParametersString) = 0
, rp.ParameterName, substring(ParametersString
, StartIndex, charindex('&', ParametersString, StartIndex) - StartIndex
)) 'ParameterValue'
from (
select
ReportID
, TimeEnd
, rp.ParameterName
, '&' + convert(varchar(max), Parameters) + '&' 'ParametersString'
, charindex(
'&' + rp.ParameterName + '=',
'&' + convert(varchar(max), Parameters) + '&'
) + len('&' + rp.ParameterName + '=') 'StartIndex'
from
ExecutionLogStorage
inner join ReportParameters rp on rp.ItemID = ReportID) AS els
inner join [Catalog] c on c.ItemID = els.ReportID
inner join ReportParameters rp on rp.ItemID = c.ItemID and rp.ParameterName = els.ParameterName;
Note that the parameter values are passed to the report as part of a URL, so you'll still need get rid the literal space encoding and so on. Also, this doesn't (yet...) work for multi-value parameters.

Extracting Number From String SQL

I have a normal SQL statement:
SELECT VALUE_ID, UF_CRM_TASK FROM b_uts_tasks_task
Now this returns a a different field everytime but they take the form of the following:
a:1:{i:0;s:7:"CO_2012";} or a:1:{i:0;s:5:"CO_12";} or a:1:{i:0;s:7:"CO_2017";}
Basically they're different everytime. What I need is to just get the number after the CO_ part. I have tried TRIM but because everything changes in the leading and trailing section I don't think this would work.
I have looked on Stack Overflow for a while and cannot find it. I know how to do it in PHP:
$data = $row['UF_CRM_TASK'];
$companyID = substr($data, strpos($data, "CO_") + 1);
$newCompanyID = preg_replace('/[^0-9.]+/', '', $companyID);
But not SQL. Thanks in advance
In MYSQL is a bit ugly:
/*SUBSTRING_INDEX BASED ON CO_ AND THE LAST " - in 2 SUBSTRINGS*/
SELECT `VALUE_ID`, SUBSTRING_INDEX(SUBSTRING_INDEX(`UF_CRM_TASK`, 'CO_', -1), '"', 1) AS `COMPANY_ID` FROM `b_uts_tasks_task`
In PHP you can just unserialize():
$data = unserialize($row['UF_CRM_TASK']);
$companyID = str_replace('CO_', '', $data[0]);
eg:
$data = unserialize('a:1:{i:0;s:5:"CO_12";}');
echo str_replace('CO_', '', $data[0]);
//==> 12
You need to use CharIndex and SubString (Microsoft SQL) or
This is the sample code I made for my Microsoft SQL server:
declare #companyIdString varchar(50) = 'a:1:{i:0;s:7:"CO_2012";}'
print 'Company ID in a string: ' + #companyIdString
print 'Find first position: ' + Cast(charindex('"CO_', #companyIdString) as varchar(2))
print 'Locate the second position (the last "): ' + Cast(charindex('"', #companyIdString, charindex('"CO_', #companyIdString)+4) as varchar(2))
print 'Extracted Company Id: ' + substring(#companyIdString,charindex('"CO_', #companyIdString)+4, charindex('"', #companyIdString, charindex('"CO_', #companyIdString)+4) - charindex('"CO_', #companyIdString) - 4)
select
#companyIdString as CompanyIdString,
substring(#companyIdString,charindex('"CO_', #companyIdString)+4, charindex('"', #companyIdString, charindex('"CO_', #companyIdString)+4) - charindex('"CO_', #companyIdString) - 4) as CompanyId
I also made the same code on a mySQL server:
set #companyIdString := 'a:1:{i:0;s:7:"CO_2012";}';
select
#companyIdString as CompanyIdString,
substring_index(substring_index(substring_index(#companyIdString, '"', 2), '"', -1), '_', -1) as CompanyId
The substring_index starts by locating the second " (string is now a:1:{i:0;s:7:"CO_2012), then it searches backward with the -1 to locate the first " (string is now CO_2012). And then it searches backward for the underscore (string is now 2012).

SSIS Substring Extract based on qualifier

I've looked through a few different post trying to find a solution for this. I have a column that contains descriptions that follow the following format:
String<Numeric>
However the column isn't limited to one set of the previous mentioned format it could be something like
UNI<01> JPG<84>
JPG<84> UNI<01>
JPG<84>
UNI<01>
And other variations without any controlled pattern.
What I am needing to do is extract the number between <> into a separate column in another table based on the string before the <>. So UNI would qualify the following numeric to go to a certain table.column, while JPG would qualify to another table etc. I have seen functions to extract the numeric but not qualifying and only pulling the numeric if it is prefaced with a given qualifier string.
Based on the scope limitation mentioned in the question's comments that only one type of token (Foo, Bar, Blat, etc.) needs to be found at a time: you could use an expression in a Derived Column to find the token of interest and then extract the value between the arrows.
For example:
FINDSTRING([InputColumn], #[User::SearchToken] + "<", 1) == 0)?
NULL(DT_WSTR, 1) :
SUBSTRING([InputColumn],
FINDSTRING([InputColumn], #[User::SearchToken] + "<", 1)
+ LEN(#[User::SearchToken]) + 1,
FINDSTRING(
SUBSTRING([InputColumn],
FINDSTRING([InputColumn], #[User::SearchToken] + "<", 1)
+ LEN(#[User::SearchToken]) + 1,
LEN([InputColumn])
), ">", 1) - 1
)
First, the expression checks whether the token specified in #[User::SearchToken] is used in the current row. If it is, SUBSTRING is used to output the value between the arrows. If not, NULL is returned.
The assumption is made that no token's name will end with text matching the name of another token. Searching for token Bar will match Bar<123> and FooBar<123>. Accommodating Bar and FooBar as distinct tokens is possible but the requisite expression will be much more complex.
You could use an asynchronous Script Component that outputs a row with type and value columns for each type<value> token contained in the input string. Pass the output of this component through a Conditional Split to direct each type to the correct destination (e.g. table).
Pro: This approach gives you the option of using one data flow to process all tag types simultaneously vs. requiring one data flow per tag type.
Con: A Script Component is involved, which it sounds like you'd prefer to avoid.
Sample Script Component Code
private readonly string pattern = #"(?<type>\w+)<(?<value>\d+)>";
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
foreach (Match match in Regex.Matches(Row.Data, pattern, RegexOptions.ExplicitCapture))
{
Output0Buffer.AddRow();
Output0Buffer.Type = match.Groups["type"].Value;
Output0Buffer.Value = match.Groups["value"].Value;
}
}
Note: Script Component will need an output created with two columns (perhaps named Type and Value) and then have the output's SynchronousInputID property set to None).
I ended up writing a CTE for a view to handle the data manipulation and then handled the joins and other data pieces in the SSIS package.
;WITH RCTE (Status_Code, lft, rgt, idx)
AS ( SELECT a.Status_code
,LEFT(a.Description, CASE WHEN CHARINDEX(' ', a.Description)=0 THEN LEN(a.Description) ELSE CHARINDEX(' ', a.Description)-1 END)
,SUBSTRING(a.Description, CASE WHEN CHARINDEX(' ', a.Description)=0 THEN LEN(a.Description) ELSE CHARINDEX(' ', a.Description)-1 END + 1, DATALENGTH(a.Description))
,0
FROM [disp] a WHERE NOT( Description IS NULL OR Description ='')
UNION ALL
SELECT r.Status_Code
,CASE WHEN CHARINDEX(' ', r.rgt) = 0 THEN r.rgt ELSE LEFT(r.rgt, CHARINDEX(' ', r.rgt) - 1) END
,CASE WHEN CHARINDEX(' ', r.rgt) > 0 THEN SUBSTRING(r.rgt, CHARINDEX(' ', r.rgt) + 1, DATALENGTH(r.rgt)) ELSE '' END
,idx + 1
FROM RCTE r
WHERE DATALENGTH(r.rgt) > 0
)
SELECT Status_Code
-- ,lft,rgt -- Uncomment to see whats going on
,SUBSTRING(lft,0, CHARINDEX('<',lft)) AS [Description]
,CASE WHEN ISNUMERIC(SUBSTRING(lft, CHARINDEX('<',lft)+1, LEN(lft)-CHARINDEX('<',lft)-1)) >0
THEN CAST (SUBSTRING(lft, CHARINDEX('<',lft)+1, LEN(lft)-CHARINDEX('<',lft)-1) AS INT) ELSE NULL END as Value
FROM RCTE
where lft <> ''

How to replace the characters by * in a specified column dynamically in ssis package?

I have an Excel source with one of the column name Emailid.
I want the output like below example:
'mahesh123#gmail.com'
The output should be
'ma*****23#gmail.com'
As a beginner i am searching for the replacement for function STUFF, in SSIS package...
select
substring(studentEMAILIDid,1,2)
+ replicate('*',len(substring(studentEMAILIDid,1,
charindex(studentEMAILIDid,'#')
-1‌​)-4)
+ substring(studentEMAILIDid,charindex(studentEMAILIDid,'#')-2,2)
+ substring(studentEMAILIDid,charindex(studentEMAILIDid,'#')+1,
len(studentEMAILIDi‌​d)
from <tablename>
I tried the above code in SSMS,i am expecting the result through SSIS package without using "Execute SQL Task".
This is the expression I tried:
emailid==
substring(
StudentEMailID,
3,
LEN(right(StudentEMailID,
findstring('#',Stud‌​entEMailID + '#')-1
)
)-4,
REPLICATE('*',LEN(LEFT(StudentEMailID,
findstring('#',StudentEMailID + '#')-1))-4))
–
Data:
select N'mahesh123#gmail.com' as email
union all
select N'EmpireAgain#gmail.com'
Derived Column Code:
SUBSTRING(email,1,2) +
REPLICATE("*",LEN(email) - FINDSTRING(email,"#",1) - 4) +
SUBSTRING(email,FINDSTRING(email,"#",1)-2,LEN(email)-(FINDSTRING(email,"#",1)-2) + 1)
Result:
email NewEmail
mahesh123#gmail.com ma*****23#gmail.com
EmpireAgain#gmail.com Em*****in#gmail.com

oledb command not fetching values

through following query i trying to merge three things parEmail , parEmployeeLogin , and parStaffID
now in the case one is null i get whole NameValue null .
SELECT (parFirstname +' '+ parSurname) AS NAME,
(parEmail +','+ parEmployeeLogin +','+ parStaffID) AS NameValue
FROM [tblParticipants]
where parFirstname Is Not Null
ORDER BY parFirstname
NameValue only have data in it if all three fields have data, it's fetching NAME properly....i am using this to get data out of Access file..what changes should be done in this oledb query..
NULL + anything = NULL. You've prevented partFirstName from being NULL with your WHERE clause, but if either of the other two columns is NULL, the entire result is NULL.
You'll have to either use IIF to provide alternate values for NULL columns, or change your WHERE to handle multiple NULL columns. (Untested) query for first option (don't have Access on this machine):
SELECT
partFirstName + ' ' + IIF(IsNull(parSurName), '<None>', parSurName) as Name,
IIF(IsNull(parEMail), '<No Mail>', parEMail) + ', ' +
IIF(IsNUll(parEmployeeLogin), '<No Login>', parEmployeeLogin) + ', ' +
IIF(IsNull(parStaffID), '<No ID>', parStaffID) as NameValue
FROM
[tblParticipants]
WHERE
parFirstName IS NOT NULL
ORDER BY
parFirstname