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 ...
随机推荐
- [PHP] 读取大文件并显示
使用PHP读取日志文件,当文件比较大的时候,会报内存不足,因此应该部分读取,读取指定的行数的数据 PHP代码: <?php class Test{ //日志路径 const LOG_PATH=& ...
- Java与线程
导语 我们知道,new一个thread,调用它的start的方法,就可以创建一个线程,并且启动该线程,然后执行该线程需要执行的业务逻辑, 那么run方法是怎么被执行的呢? Java线程和os线程 os ...
- 那些教程没有的php4-composer依赖管理工具
phpcomposer PHP 5.3.2+ Composer 不是一个包管理器,但它在每个项目的基础上进行管理,在你项目的某个目录中(例如 vendor)进行安装.默认情况下它不会在全局安装任何东西 ...
- jquery实现拖拽以及jquery监听事件的写法
很久之前写了一个jquery3D楼盘在线选择,这么一个插件,插件很简单,因为后期项目中没有实际用到,因此,有些地方不是很完善,后面也懒得再进行修改维护了.最近放到github上面,但是也少有人问津及s ...
- SharePoint Iframe 报错“此内容不能显示在一个框架中”
问题描述 我们SharePoint站点用Excel Service发布的Excel,需要Iframe到其他系统中,但是,Iframe的时候发现报错“此内容不能显示在一个框架中”. 后来,尝试在其他系统 ...
- Android用路径api在内部存储读写文件
复制并修改原有项目 复制之前创建的项目CC+CV操作 需要改动的地方: * 项目名字 * 应用包名 * R文件重新导包 接着修改件/AndroidManifest.xml中的包名:package=&q ...
- C标准库<assert.h>实现
本文地址:http://www.cnblogs.com/archimedes/p/c-library-assert.html,转载请注明源地址. 1.背景知识 头文件<assert.h>唯 ...
- 【读书笔记】iOS-内存管理
Cocoa的内存管理:retain,release和autorelease. 每个对象都维护一个保留计数器.对象被创建时,其保留计数器值为1:对象被保留时,保留计数器值加1:对象被释放时,保留计数器值 ...
- Android学习一(入门)
一.Android 系统简介 1.1.1G-4G 1G:模拟制式手机,1995年问世的第一代模拟制式手机,只能进行语音通话, 2G:手机使用GSM,CDMA(9K/s),增加了接收数据的功能 2.5G ...
- IOS 杂笔-13(appearance的巧妙使用)
在我们查看原生api时,我们不难发现,有些api的后面有着->UI_APPEARANCE_SELECTOR 那么我可以很高兴的说我们可以通过appearance对象来统一设置.十分巧妙. 例如: ...