AMO olap Test C# generate tsql and mdx
通过AMO访问online的cube,生成等值的TSql和mdx
自动生成等值的TSQL和MDX进行Cube测试.其中难度比较大的部分是拼接TSQL.
暂时不处理calculations,只除理metrics和Regular Type的dimension Usage.
metric的聚合方法只处理(max,min,sum,count,distinct count)
以下是问题的记录与处理情况.
1.adventureworks示例cube中,会把Date dimension的attributes的表名取成dimtime. 未解决 已经解决此问题
2.如果dimension 表中的attributes引用了其他表的字段,则暂时没有解决这个问题. 解决
使用TableJoin和TableLinks方法来解决这个问题.
Tablelinks方法获取dimensionattributes中使用到的字段所在的表与主表的关系链.
Tablejoin:生成连接的语句.
或许不完善.
3.新问题 如果hierarchy的level的source attribute用的是calculation,那么现在仍然会报错,我应该判断
这个字段是不是计算成员,如果是计算成员,则要去取计算成员的定义.
http://technet.microsoft.com/en-us/library/ms345093.aspx
4.没有考虑dimension attribute的orderby 属性与name column. 未解决(尽快解决 已经解决此问题)
5.问题 自连接的情况 如果dimension usage 当中事实表和维度表是一个表的话,需要给表加别名.
现在只考虑事实表与维度表相同的情况,其他的暂时不考虑.
6.在某些情况下,sum出来的结果会发生溢出,所以需要提前把它转化为bigint.
可以在判断其列的类型为int时自动将其转化成bigint. 未解决
7.遇到父子dimension会形成死循环,或者类似存在回链关系的DSV维度,忽略掉. 解决:第二次出现的时候直接断开.
以下是生成等值TSQL与MDX的运行情况,使用Adventurework示例数据仓库SSAS进行测试,除了提到的第一个问题外,
生成的TSQL均可以运行.
界面介绍:填入OLAP CUBE的连接字符串,选择DB,CUBE与dimensions.直接点击生成mdxtsql.
以下贴一些主要的方法(代码)
由于dimension可能引用多个表,所以要把这几个表关联起来,有了以下代码:
private string TableJoin(DimensionAttribute da)
{
//根据l找到sourcetable
//然后去匹配tablelinks中的长度 然后再去获取
string morejoin = "";
string tablelinks = GetTableLinks(da.Parent);
if (tablelinks.Split(',').Length<) return "";
string TableName = da.KeyColumns[].Source.ToString().Split('.')[]+",";
if (tablelinks.IndexOf(TableName).Equals()) return "";
string strUsedTables = tablelinks.Substring(, tablelinks.IndexOf(TableName)-);
List<string> usedTables = strUsedTables.Split(',').ToList<string>();
usedTables.Remove(""); DataSet ds = da.Parent.DataSourceView.Schema;
for (int i = ; i < ds.Relations.Count && usedTables.Count > ; i++)
{
string childTable = usedTables[];
DataRelation dr = ds.Relations[i];
if (dr.ChildTable.TableName.Equals(childTable))
{
morejoin = morejoin.Append(" JOIN "
+ GetSourceQueryDefinition(da.Parent,dr.ParentTable.TableName.ReplaceFirstUnderLineWithDot())
).AppendNewLine().Append("ON ");
for (int j = ; j < dr.ChildColumns.Length; j++)
{
morejoin = morejoin.Append(
dr.ParentTable.TableName.ReplaceFirstUnderLineWithDot()+"." + dr.ParentColumns[j].ColumnName + " = " +
dr.ChildTable.TableName.ReplaceFirstUnderLineWithDot() +"." + dr.ChildColumns[j].ColumnName
).AppendNewLine();
}
usedTables.RemoveAt();
i = ;
}
} return morejoin;
}
private string GetTableLinks(Dimension dim)
{
HashSet<string> tables = new HashSet<string>();
string MainTable = "";
string tablelinks = string.Empty;
DataSet ds = dim.DataSourceView.Schema;
MainTable= dim.KeyAttribute.KeyColumns[].Source.ToString().Split('.')[];
tablelinks = tablelinks.Append(MainTable+",");
for (int i = ; i < ds.Relations.Count; i++ )
{
DataRelation dr = ds.Relations[i];
if (dr.ChildTable.TableName.Equals(MainTable))
{
tablelinks = tablelinks.Append(dr.ParentTable.TableName + ",");
MainTable = dr.ParentTable.TableName;
if (tables.Contains(MainTable))
break;
else
tables.Add(MainTable);
i = ;
}
}
return tablelinks;
}
public DataTable GetMDXSQL(Cube _cube)
{
DataTable dt = new DataTable();
dt.Columns.Add("MDX", typeof(String));
dt.Columns.Add("TSQL",typeof(String));
string mdx = "";
string tsql = ""; StringBuilder sbMeasures = new StringBuilder("{");
foreach (MeasureGroup mg in _cube.MeasureGroups)
{
#region Measure
foreach (Measure m in mg.Measures)
{
#region Metrics
if (m.AggregateFunction.Equals(AggregationFunction.Sum)
||
m.AggregateFunction.Equals(AggregationFunction.Count)
||
m.AggregateFunction.Equals(AggregationFunction.DistinctCount)
||
m.AggregateFunction.Equals(AggregationFunction.Max)
||
m.AggregateFunction.Equals(AggregationFunction.Min)
)
{
sbMeasures.Append(m.Name.QuoteName().AppendComma());
if (m.AggregateFunction.Equals(AggregationFunction.Sum))
sbsql.Append(
AggregationFunction.Sum.ToString().AppendLeftParenthesis()
+ m.Source.ToString().ReplaceFirstUnderLineWithDot()
.AppendRightParenthesis()
+ " AS "
+ m.Name.QuoteName().AppendComma().AppendNewLine()
);
if (m.AggregateFunction.Equals(AggregationFunction.Count))
sbsql.Append("COUNT(*) AS "
+ m.Name.QuoteName().AppendComma().AppendNewLine()
);
if (m.AggregateFunction.Equals(AggregationFunction.DistinctCount))
sbsql.Append(
"COUNT(Distinct "
+ m.Source.ToString().ReplaceFirstUnderLineWithDot()
.AppendRightParenthesis()
+ " AS "
+ m.Name.QuoteName().AppendComma().AppendNewLine()
);
if (m.AggregateFunction.Equals(AggregationFunction.Max))
sbsql.Append(
AggregationFunction.Max.ToString().AppendLeftParenthesis()
+ m.Source.ToString().ReplaceFirstUnderLineWithDot()
.AppendRightParenthesis()
+ " AS "
+ m.Name.QuoteName().AppendComma().AppendNewLine()
);
if (m.AggregateFunction.Equals(AggregationFunction.Min))
sbsql.Append(
AggregationFunction.Min.ToString().AppendLeftParenthesis()
+ m.Source.ToString().ReplaceFirstUnderLineWithDot()
.AppendRightParenthesis()
+ " AS "
+ m.Name.QuoteName().AppendComma().AppendNewLine()
);
#endregion sbMeasures.Remove(sbMeasures.Length - , );//remove the last coma
sbMeasures.Append("}");
sbsql.Remove(sbsql.Length - , );//remove ,\r\n HashSet<string> selectedDims = GetSelectedDimensions();
#region MeasureGroupDimension
foreach (MeasureGroupDimension mgd in mg.Dimensions)
{
if (!selectedDims.Contains(mgd.Dimension.Name)) continue; string _facttable = string.Empty;
string _dimensiontable = string.Empty;
string origindimtable = string.Empty;
string _joinby = " ON ";
string _groupby = " GROUP BY "; if (!mgd.GetType().Name.Equals("RegularMeasureGroupDimension"))
continue; foreach (MeasureGroupAttribute mga in ((RegularMeasureGroupDimension)mgd).Attributes)
{ if (mga.Type != MeasureGroupAttributeType.Granularity) continue;
origindimtable = mga.Attribute.KeyColumns[].Source.ToString().Split('.')[].ReplaceFirstUnderLineWithDot(); _dimensiontable = GetSourceQueryDefinition(mgd.CubeDimension.Dimension, origindimtable);
_facttable = GetSourceQueryDefinition(mgd.CubeDimension.Dimension, mga.KeyColumns[].Source.ToString().Split('.')[].ReplaceFirstUnderLineWithDot()); for (int i = ; i < mga.KeyColumns.Count; i++)
{
_joinby += mga.Attribute.KeyColumns[i].Source.ToString().ReplaceFirstUnderLineWithDot();
_joinby += " = " + mga.KeyColumns[i].Source.ToString().ReplaceFirstUnderLineWithDot().Append(" AND ");
}
break;
}
_joinby = _joinby.TrimEnd(" AND ".ToCharArray()); #region Hierarchy level
foreach (Hierarchy h in mgd.CubeDimension.Dimension.Hierarchies)
{
foreach (Level l in h.Levels)
{
mdx =
string.Format(mdxtemplate, sbMeasures.ToString().TrimEnd(','),
h.Parent.Name.QuoteName().Append(".").Append(h.Name.QuoteName())
.Append(".").Append(l.Name.QuoteName()),
_cube.Name.QuoteName()); foreach (DataItem di in l.SourceAttribute.KeyColumns)
{
// _groupby += di.Source.ToString().ReplaceFirstUnderLineWithDot().AppendComma();
_groupby += GetColumnDefinition(l.Parent.Parent.DataSourceView.Schema,di.Source.ToString());
}
_groupby = _groupby.TrimEnd(',');
//if the _facttable == _dimensiontable then give a alias for dimtable
if (_facttable.Equals(_dimensiontable))
{
_dimensiontable += "";
_groupby = _groupby.Replace(origindimtable, origindimtable + "");
} tsql =
sbsql.ToString()
.AppendNewLine()
.Append(" FROM ")
.Append(_facttable)
.Append(" JOIN ")
.Append(_dimensiontable)
.AppendNewLine()
.Append(_joinby);
//.AppendNewLine();
//.Append(_groupby); string morejoin = TableJoin(l.SourceAttribute);
tsql = tsql.Append(morejoin); tsql = tsql.AppendNewLine().Append(_groupby);
_groupby = " GROUP BY "; //Add rows for dt
AddRow(dt, mdx, tsql); }
} #endregion #region Attributes
if (mgd.CubeDimension.Dimension.Hierarchies.Count == )
{
foreach (DimensionAttribute da in mgd.CubeDimension.Dimension.Attributes)
{
if (da.AttributeHierarchyEnabled == true)
{
mdx = string.Format(mdxtemplate, sbMeasures.ToString().TrimEnd(','),
da.Parent.Name.QuoteName().Append(".").Append(
da.Name.QuoteName())
, _cube.Name.QuoteName());
}
else continue;
foreach (DataItem di in da.KeyColumns)
{
// _groupby += di.Source.ToString().ReplaceFirstUnderLineWithDot().AppendComma();
_groupby += GetColumnDefinition(da.Parent.DataSourceView.Schema, di.Source.ToString());
}
_groupby = _groupby.TrimEnd(',');
//if the _facttable == _dimensiontable then give a alias for dimtable
if (_facttable.Equals(_dimensiontable))
{
_dimensiontable += "";
_groupby = _groupby.Replace(origindimtable, origindimtable + "");
} tsql=
sbsql.ToString()
.AppendNewLine()
.Append(" FROM ")
.Append(_facttable)
.Append(" JOIN ")
.Append(_dimensiontable)
.AppendNewLine()
.Append(_joinby)
//.AppendNewLine()
//.Append(_groupby)
;
string morejoin = TableJoin(da);
tsql = tsql.Append(morejoin); tsql = tsql.AppendNewLine().Append(_groupby);
_groupby = " GROUP BY "; AddRow(dt, mdx, tsql);
}
}
#endregion }
#endregion sbsql = new StringBuilder(" SELECT \r\n");
sbMeasures = new StringBuilder("{");
}
} #endregion
} return dt;
}
由于dimension的source table经常会含有计算列或者本身是named query 所以有了以下代码:
public string GetSourceQueryDefinition(Dimension dim,string keycolsrc)
{
//获取dim的dsv 获取
string rst=keycolsrc;
DataSet ds = dim.DataSourceView.Schema;
string tbname = keycolsrc.Replace("dbo.","");
if(ds.Tables.Contains(tbname))
{
if(ds.Tables[tbname].ExtendedProperties.Contains("QueryDefinition"))
rst = "("+ds.Tables[tbname].ExtendedProperties["QueryDefinition"].ToString() + ") as "+ tbname;
} return rst;
}
public string GetColumnDefinition(DataSet ds, string columndatasource)
{
string columnDefinition = "";
string tableName = columndatasource.Split('.')[];
string columnName = columndatasource.Split('.')[];
if (ds.Tables.Contains(tableName)
&& ds.Tables[tableName].Columns.Contains(columnName)
&& ds.Tables[tableName].Columns[columnName].ExtendedProperties.Contains("ComputedColumnExpression")
)
{
columnDefinition = "(" + ds.Tables[tableName].Columns[columnName].ExtendedProperties["ComputedColumnExpression"].ToString() +")";
}
else
{
columnDefinition = columndatasource.ReplaceFirstUnderLineWithDot().AppendComma();
}
return columnDefinition;
}
AMO olap Test C# generate tsql and mdx的更多相关文章
- 微软BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)
[公告]本博客于2015年10月起不再更新 新博客文章主要发表在商业智能BI社区: http://www.flybi.net/blog/biwork 博客地图自动分类 文章目录方便更好的导航,阅读文章 ...
- BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)
微软 BI ETL 架构设计 如何在 ETL 项目中统一管理上百个 SSIS 包的日志和包配置框架 如何管理和记录 SSIS 各个 Task 的开始执行时间和结束时间以及 Task 中添加|删除|修改 ...
- SSIS ETL BEST PRACTICE
PackageRunLog(ExecutionGuid,PackageName,SourceTableName,DestinationTableName,StartTimeUTC,EndTimeUTC ...
- 利用PowerShell复制SQLServer账户的所有权限
问题 对于DBA或者其他运维人员来说授权一个账户的相同权限给另一个账户是一个很普通的任务.但是随着服务器.数据库.应用.使用人员地增加就变得很枯燥乏味又耗时费力的工作.那么有什么容易的办法来实现这个任 ...
- SSAS CUBE TEST CASES
经过周末两天和今天的努力,基本上完成并修复了一些bug并且集成到我的MSBIHelper项目中去,可以进行数据测试了.效果图如下: 可以帮助开发人员快速生成等值的Tsql和mdx查询,辅助测试人员快速 ...
- OLAP + MDX
基本概念 维度(Dimension):表示数据的属性,一个维度一般会有一个维表(也可能多个),事实表会有一个字段关联维表. 退化维度:有的维度可以没有维度表,因为这种维度比较简单,没有更多属性,没有必 ...
- MDX Cookbook 06 - GENERATE 循环遍历
有时候需要从集合中取出特定的成员但是又不能执行遍历操作,这个时候就可以使用 GENERATE 函数来解决这个问题. 根据地区查询每年的销售额 - SELECT NON EMPTY { , NON EM ...
- MDX Step by Step 读书笔记(七) - Performing Aggregation 聚合函数之 Max, Min, Count , DistinctCount 以及其它 TopCount, Generate
MDX 中最大值和最小值 MDX 中最大值和最小值函数的语法和之前看到的 Sum 以及 Aggregate 等聚合函数基本上是一样的: Max( {Set} [, Expression]) Min( ...
- MDX学习笔记(整理) MDX语法
1.1.members和Children的用法. select [Measures].[Internet Sales Count] on columns, [客户].[全名] on rows from ...
随机推荐
- Python入门笔记(10):字典
一.映射类型 我理解中的映射类型是:键值对的关系,键(key)映射值(value),且它们是一对多的关系.字典是Python唯一的映射类型. 扩展1:哈希表一种数据结构,值是根据相关的键进行数据存储的 ...
- 根据Expander的IsExpanded属性值的变化动态设计Control的size
简要说明: 当Expander 的IsExpanded属性为“True” 时给控件设个尺寸(此处为高度),当为“False”时给控件设另外一个值. 知识点:数据绑定.Style和Trigger < ...
- Go eclipse plugin
Installation Requirements: Eclipse 4.5 (Mars) or later. Java VM version 8 or later. Gocode and Go or ...
- 在WPF中使用文件夹选择对话框
开发中有时会想实现"选择某个文件夹"的效果: 在WPF中,使用Microsoft.Win32.OpenFileDialog只能选择文件,FolderBrowserDialog只能用 ...
- CodeBlocks VS2015编译环境设置
1. 菜单 Settings --> Compiler... 2. 设置vs 的安装路径
- SAP中关于用户IP信息的获取(转载)
SAP中如何获取登录用户的IP? 或如何查看哪些IP登录到SAP中: 在Table: USR41中查看,具体字段的说明如下: MANDT --- ClientBNAME --- 登录的 ...
- Android自动更新安装后显示‘完成’‘打开’按钮
/** * 安装apk * * @param url */ private void installApk() { File apkfile = new File(apkFilePath); if ( ...
- HashMap,HashTable,TreeMap区别和用法
开始学HashTable,HashMap和TreeMap的时候比较晕,觉得作用差不多,但是到实际运用的时候又发现有许多差别的.需要大家注意,在实际开发中以需求而定. java为数据结构中的映射定义了一 ...
- Struts2(十四)拦截器实现权限管理
一.认识拦截器 拦截器也是一个类 拦截器可以在Action被调用之前和之后执行代码 框架很多核心功能是拦截器实现的 拦截器的特点: 拦截器自由组合,增强了灵活性.扩展性.有利于系统解耦 拦截器可以拦截 ...
- 【转】c++中引用的全方位解读
对于习惯使用C进行开发的朋友们,在看到c++中出现的&符号,可能会犯迷糊,因为在C语言中这个符号表示了取地址符,但是在C++中它却有着不同的用途,掌握C++的&符号,是提高代码执行效率 ...