#Error while showing DateTime field with Blank or Space in a SSRS Report...

In a SSRS Report, DataSet returns a column which contains datetime values in string data type.
Due to that it contains values with spaces or blank. Let assume the particular field name is "DateValueField".
To show that in the SSRS Report, initially the below expression is used.

=IIf(IsNothing(Fields!DateValueField.Value) OR LTRIM(RTRIM(Fields!DateValueField.Value))="", "", FormatDateTime(Fields!DateValueField.Value, DateFormat.ShortDate))

Eventhough the above expression seems to be correct, when we ran the report, it gives the value as #Error for the rows which contains Blank or Space for the DateValueField.
But it gives the correct value for the rows which contains a valid datetime value.

Actually the issue exists with SSRS IIF expression and to overcome that, we have to modify the IIF expression as below.

=IIf(IsNothing(Fields!DateValueField.Value) OR LTRIM(RTRIM(Fields!DateValueField.Value))="", "", FormatDateTime(IIf(IsNothing(Fields!DateValueField.Value) OR LTRIM(RTRIM(Fields!DateValueField.Value))="", Nothing,Fields!DateValueField.Value), DateFormat.ShortDate))

There may be other situations that the same issue may occur while using IIF expressions.

SSIS Script Component to Trim data in all the columns...

There are situations that we may have large number of input columns and we may need to Trim the data in those. Normally we can use Derived Column component to get done this, but in this scenario it is very difficult due to the large number of columns.
In such scenario it is easy to use Script Component and it can be configured to trim data for any number of input columns.

Solution is as below.


We can have a Script Component to trim data and there are some steps to follow.
We need to select on the required input columns and change the Usage Type of those columns to ReadWrite as below image.


Then click on Edit Script and follow the below steps to add the required code in C#
Add the using System.Reflection; namespace
Then modify the Input0_ProcessInputRow method as below
 public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        /*
         * Add your code here
         */
        foreach (PropertyInfo p in Row.GetType().GetProperties())
        {
         
           if (object.ReferenceEquals(p.PropertyType, typeof(string)))
            {
                if (p.GetValue(Row, null) != null)
                {
                    p.SetValue(Row, TrimData(p.GetValue(Row, null).ToString()), null);
                }
            }
        }
    }

The TrimData method is below
 public string TrimData(string ValueOfProperty)
    {
        // Uppercase the value
        ValueOfProperty = ValueOfProperty.TrimStart().TrimEnd();
        return ValueOfProperty;
    }


The complete code after those modifications is as below

#region Namespaces
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using System.Reflection;
#endregion

///



/// This is the class to which to add your code.  Do not change the name, attributes, or parent
/// of this class.
///
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
    ///



    /// This method is called once, before rows begin to be processed in the data flow.
    ///
    /// You can remove this method if you don't need to do anything here.
    ///
    public override void PreExecute()
    {
        base.PreExecute();
        /*
         * Add your code here
         */
     
    }

    ///



    /// This method is called after all the rows have passed through this component.
    ///
    /// You can delete this method if you don't need to do anything here.
    ///
    public override void PostExecute()
    {
        base.PostExecute();
        /*
         * Add your code here
         */
    }

    ///



    /// This method is called once for every row that passes through the component from Input0.
    ///
    /// The row that is currently passing through the component
    public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        /*
         * Add your code here
         */
        foreach (PropertyInfo p in Row.GetType().GetProperties())
        {
         
            if (object.ReferenceEquals(p.PropertyType, typeof(string)))
            {
                if (p.GetValue(Row, null) != null)
                {
                    p.SetValue(Row, TrimData(p.GetValue(Row, null).ToString()), null);
                }
            }
        }
    }

    // New function that you can adjust to suit your needs
    public string TrimData(string ValueOfProperty)
    {
        // Uppercase the value
        ValueOfProperty = ValueOfProperty.TrimStart().TrimEnd();
        return ValueOfProperty;
    }
}

After that Build the code, save and close it. Then connect the Script Component with the Output source.

This can be used for any number of columns and it will loop though the available input columns and trim the data on those.

SSAS Single Role - Multiple Dimensions Issue...

In my previous post, I explained how to provide access using multiple roles for different dimensions.
Also I faced issues while providing access for multiple dimensions using a single role.

Let assume a scenario that we only need to provide the access for a Sales Manager, only for his Current Region. But Region of the Sales Manager may be changed and he should be able to see the relevant data for the Region for the period he assigned for that Region.

As I explained in my previous post, we need to maintain a mapping table for this requirement as well. Lets assume the name of the mapping table is SECURITY_MANAGER_REGION and the columns will be SalesManagerId, RegionId and MonthId. In this scenario I assumed sales manager is assigned for a particular region, at least for a period of Month.

Then we need to have the SECURITY_MANAGER_REGION table data in a fact table and can grant the access for the Region and Month dimensions based on it with in the same role.

But the issue is since those are two different dimension, security is applied separately and it is causing the issue.

To overcome that what I have done was, add a composite key using RegionId and MonthId  values to the SECURITY_MANAGER_REGION table.
Based on that table created a new dimension as DIM_SECURITY_MANAGER_REGION which uses the Key as the composite keys of RegionId and MonthId.

Then the Security is applied for the DIM_SECURITY_MANAGER_REGION dimension and the same dimension is linked with the measure groups using the RegionId and MonthId values.

That is it!

Multiple Roles - Different Dimensions in SSAS Security is not impossible...

We had a requirement to implement dynamic security in SSAS with multiple roles for different dimensions.
But due to the Additive design of SSAS security, it is causing issues and people think that is impossible.
But I found the below useful link, which mentioned some of the alternative approaches.
http://blogs.msdn.com/b/psssql/archive/2014/07/30/the-additive-design-of-ssas-role-security.aspx

Actually to have multiple roles for different dimensions, you need to consider below scenarios

  1. If you allow access in one role, you need to restrict that in the other roles.
  2. Need to consider the scenario that the user is not belongs to any of the roles and restrict access in that scenario as well.
  3. Also make sure that you put the tick for the Enable Visual Total check box in the security applied attribute.
Instead of the custom assembly approach mentioned in the above link, I was able to get done the same using a reference table and have that as a Non-Additive fact in the cube.

As an example let say we have two dimension as Customer and Region and we need to restrict the access for those based on the Sales Person. To provide the access for Customer data, there is a role as Role_Customer and to provide the access for Region data, there is a role as Role_Region.

To achieve that there are two mapping tables are maintained as SECURITY_REGION (Columns as SalesPersonId, RegionId) and SECURITY_CUSTOMER (Columns as SalesPersonId, RegionId) to keep the relevant mappings. Two measure groups are created based on those mapping tables as SECURITY REGION and SECURITY CUSTOMER to use the mapping tables in the cube.

In the SECURITY_REGION role, security is provided for the Region dimension using the below expression. You need provide expression for the Allowed member set of the RegionId attribute of the Region dimension, under the Dimension Data.

Exists
(
{[DIMREGION].[REGIONID].[REGIONID].Members},
STRTOSET("[LOGIN].[PERSON NAME].&["+username()+"]"),
"SECURITY REGION ")

LOGIN Dimension maintains the log in details of the users and it uses to capture the relevant logged user.

In the same way, security can be provided for the Customer dimension using SECURITY_CUSTOMER role, by using the below mdx expression for the CustomerId attribute in the Customer dimension.

Exists
(
{[DIMCUSTOMER].[CUSTOMERID].[CUSTOMERID].Members},
STRTOSET("[LOGIN].[PERSON NAME].&["+username()+"]"),
"SECURITY CUSTOMER ")

But if you only follow above steps, security will not be applied due to the Additive design of SSAS Security.
To avoid it we need to follow the second step mentioned in the top of the post and it can be done as below.

In the SECURITY_REGION role, we need make sure if the user is in the SECURITY_CUSTOMER role, then for the CustomerId attribute of the Customer dimension, we need to restrict all the members since the 
security will be applied from the SECURITY_CUSTOMER role. Otherwise we need to allow all the members.

We can achieve it by applying the below mdx expression for allowed member set of the CustomerID attribute of the Customer dimension in the SECURITY_REGION role.

IIF(Count(NonEmpty
(
{[DIMCUSTOMER].[CUSTOMERID].[CUSTOMERID].Members}*
STRTOSET("[LOGIN].[PERSON NAME].&["+username()+"]"),

[Measures].
[SECURITY CUSTOMER Count]))>0 OR 
(Count(NonEmpty
(
{[DIMCUSTOMER].[CUSTOMERID].[CUSTOMERID].Members}*
STRTOSET("[LOGIN].[PERSON NAME].&["+username()+"]"),

[Measures].
[SECURITY CUSTOMER Count]))=0 AND 
COUNT(NonEmpty
(
{[DIMREGION].[REGIONID].[REGIONID].Members}*

STRTOSET("[LOGIN].[PERSON NAME].&["+username()+"]"),
[Measures].[SECURITY REGION Count]))=0) ,
{},{[DIMCUSTOMER].[CUSTOMERID].[CUSTOMERID].Members})


We have to do the same thing for the RegionId attribute in the SECURITY_CUSTOMER  role.

Also make sure that you put the tick for the Enable Visual Total check box in all the security applied attributes.

These steps will allow you to provide security based on Multiple Roles for Different Dimensions.

Errors in the OLAP storage engine: A duplicate attribute key has been found when processing:

While processing a dimension, processing got failed and shown the below warning as well.
Errors in the OLAP storage engine: A duplicate attribute key has been found when processing:..

But when I checked the values of the mentioned attribute, there were no duplicate values. But the relevant column data type is INT and it has a value as NULL.
When I checked the dimension attribute key column properties, NullProcessing property is set to Automatic.
Actually this is causing the above error message since during the processing, NULL values are converted to 0 and we already have an attribute value as 0.
Same issue can happen for the string data types having blank value as well.

To fix this we can replace NULL values with the relevant value in the Data Source View of the Cube or replace it in the Data Warehouse using the ETL. Best way to do is to change it in the Data Warehouse.

Below link contains more details about this issue as well.


Error message when trying to open SQL Server Configuration Manager in SQL Server: "Cannot connect to WMI provider. You do not have permission or the server is unreachable"

We had an issue that SQL Server Analysis Server is not getting started and cannot connect to the SQL Server Configuration Manager as well. While trying to connect to the SQL Server Configuration Manager, got the below error message.

Cannot connect to WMI provider. You do not have permission or the server is unreachable. Note that you can only manage SQL Server 2005 and later servers with SQL Server Configuration Manager.

According to the below Microsoft support link, it says that the WMI Provider file is removed when the SQL Server is uninstalled.

https://support.microsoft.com/en-us/kb/956013

But in my case that is not the reason, since we did not do any uninstall. Possible reason could be that file is corrupted.

Before following the steps mentioned in the link, you can just try the below steps.


  • Stop the Analysis Service service
  • Restart the Windows Management Instrumentation service
  • Then try to restart the SQL Server Analysis Service service.
  • Check whether the SQL Server Analysis Service service is getting started, if not follow the steps mentioned in the link as below.


  • open a command prompt, type the following command, and then press ENTER:
  • mofcomp "%programfiles(x86)%\Microsoft SQL Server\number\Shared\sqlmgmproviderxpsp2up.mof"
  • Note For this command to succeed, the Sqlmgmproviderxpsp2up.mof file must be present in the %programfiles(x86)%\Microsoft SQL Server\number\Shared folder.

  • The value of number depends on the version of SQL Server:nnn
    Microsoft SQL Server 2012 - 110
    Microsoft SQL Server 2008 R2 - 100
    Microsoft SQL Server 2008 - 100
    Microsoft SQL Server 2005 - 90
  • Then restart the Windows Management Instrumentation service.
  • After that restart the SQL Server Analysis Service service as well.


This should fix both the issues mentioned above.

How to prevent first time cube access performance issue, after a cube refresh with Dynamic Security...

Recently we faced an issue that, after a cube refresh there is a performance issue while accessing the cube. This happens since the dynamic security was implemented.
This performance issue can be prevented by building cache for each user.

SSIS package was implemented to build the cache. In the package the approach used was to execute the create cache mdx command using each user id.
You can connect to the SSAS cube with different users by using the EffectiveUserName property in the Connection String.

The structure of the package is as shown below



Steps:

  • Create four variables as shown below. 





  • OLAP_ConnString is the value used as the connection string for SSAS cube. It includes the user name by using the EffectiveUserName property.
  • UserNames variable is used to get the list of users. 
  • Each user is assigned to UserName variable in the Foreach Loop Container.




  • Execute SQL Task us used with in the Foreach Loop Container use to create the cache using the MDX command. Since Effective User Name property is set using the UserName variable, the MDX command is executed for the particular user. That means the cache was created for that user.


After a cube refresh, we need to execute this package and it will prevent the first time access performance issue.





tablename_WriteToDataDestination: Mashup Exception Data Source Error Couldn't refresh the entity...

 Once a Dataflow is created and published on Fabric, got the below error while refreshing the Dataflow. tablename_ WriteToDataDestination: M...