我已经获得了对多维数据集的访问权限,并且需要知道我是否可以设置一个可以连接到多维数据集并检索内容的存储过程(通过 MDX 查询)。我需要这个来防止必须从 Management Studio 或 Excel(通过 PowerPivot)导出数据。我对多维数据集/olap 查询非常陌生,所以请原谅我可能表现出的任何天真。
问问题
13813 次
2 回答
3
最简单的方法是为您的多维数据集创建一个链接服务器,然后 INSERT..SELECT FROM OPENQUERY http://sqlblog.com/blogs/stacia_misner/archive/2010/11/30/31193.aspx
此选项的局限性在于
- 它对 MDX 查询有 8000 个字符的限制
- 您必须为每个数据库手动创建一个链接服务器
- 结果为空时需要特殊代码处理
- 结果集列中的数据类型过多(列的 ntext 和行的 nvarchar(4000))
一个高级选项是 ExecuteOLAP CLR 存储过程https://olapextensions.codeplex.com/
于 2013-09-24T16:03:56.887 回答
0
如果您选择使用 OPENQUERY(最简单的方法,但有 Brian 指定的限制),以下过程可能会很方便:
/*
PARAMS:
@mdx: mdx statement
@mdx_columns: specifies the mdx columns to retrieve from the executed mdx
@linkedServer: linked server to be used
@resultsTable: temporary table to hold results from mdx
@resultsCols: if only some columns should be filled in @resultsTable, specify them here (e.g. '(col1, col2, ... )' )
@expectedColCount: expected column count for mdx result. If actual column count is different from the expected count, no data is filled in
@actualColCount: actual column count. Specify NULL if not interesed in this value
@Debug: outputs debug info
*/
ALTER PROCEDURE [dbo].[exec_mdx_over_linked_server] (
@mdx NVARCHAR(MAX),
@mdx_columns NVARCHAR(1024) = '*',
@linkedServer VARCHAR(64),
@resultsTable VARCHAR(64),
@resultsCols VARCHAR(1024) = '',
@expectedColCount SMALLINT,
@actualColCount SMALLINT = NULL OUTPUT,
@Debug BIT = 0
)
AS
BEGIN
SET NOCOUNT ON
if (@Debug = 1)
PRINT 'Started exec_mdx_over_linked_server procedure for populating ' + @resultsTable
IF LEN(@MDX)>8000 RAISERROR ('MDX too long for openquery (exec_mdx_over_linked_server)',
16,
1);
declare @SQL NVARCHAR(MAX)
IF (@Debug = 1)
BEGIN
-- getting results from mdx
SET @SQL = 'SELECT ''Mdx results for ' + @resultsTable + ''' AS ''Mdx results'', ' + '*' + '
FROM OPENQUERY(' + @linkedServer + ', ''' + @mdx + ''')';
IF LEN(@SQL)>8000 RAISERROR ('MDX too long for openquery (exec_mdx_over_linked_server)',
16,
1);
EXEC (@SQL)
END
SET @SQL = '
SELECT ' + '*' + ' INTO #resultsWithWeirdNameToAvoidTempCollisions
FROM OPENQUERY(' + @linkedServer + ', ''' + @mdx + ''');
SELECT @colCount = COUNT(*)
FROM tempdb.sys.columns
WHERE object_id = object_id(''tempdb..#resultsWithWeirdNameToAvoidTempCollisions'');
if (@colCount = @expectedColCount)
INSERT INTO ' + @resultsTable + @resultsCols + '
SELECT ' + @mdx_columns + ' FROM #resultsWithWeirdNameToAvoidTempCollisions'
IF LEN(@SQL)>8000 RAISERROR ('MDX too long for openquery (exec_mdx_over_linked_server)',
16,
1);
if (@Debug = 1)
PRINT 'dbo.exec_mdx_over_linked_server SQL = ' + @SQL
DECLARE @colCount INT
EXECUTE sp_executesql @SQL, N'@expectedColCount SMALLINT, @ColCount SMALLINT OUTPUT', @expectedColCount = @expectedColCount, @colCount = @actualColCount OUTPUT
if (@Debug = 1)
BEGIN
PRINT '@expectedColCount = '; PRINT @expectedColCount
PRINT '@actualColCount = '; PRINT @actualColCount
END
-- correction for small float numbers (< 10E-10)
DECLARE @UpdateSql NVARCHAR(MAX) = N''
DECLARE @SmallThreshold FLOAT = 0.00000000001
SELECT @UpdateSql += '
UPDATE ' + @resultsTable + '
SET ' + QUOTENAME(COLUMN_NAME) + ' = 0
WHERE TRY_CONVERT (FLOAT, ' + QUOTENAME(COLUMN_NAME) + ') IS NOT NULL
AND ABS(' + QUOTENAME(COLUMN_NAME) + ') < ' + CAST(@SmallThreshold AS NVARCHAR(30))
FROM tempdb.INFORMATION_SCHEMA.COLUMNS with(NOLOCK)
-- WHERE table_name like @resultsTable + '[_][_][_]%'
-- changed, in order not to take into consideration objects from other spids
WHERE table_name = object_name(object_id('tempdb..' + @resultsTable), (select database_id from sys.databases where name = 'tempdb'))
IF (@Debug = 1)
BEGIN
PRINT '@UpdateSql = '; PRINT @UpdateSql;
END
EXEC (@UpdateSql);
END
它具有以下优点:
- 处理接收到的结果没有预期列的情况(不执行任何操作)
- 对非常小的数字执行一些舍入(这可能会发生,因为多维数据集只知道使用浮点数)
- 所有 mdx 语句都经过一个过程
分析时,我注意到大约。100ms 开销(通过过程执行与针对分析服务器直接执行)。
.NET 开发人员可以使用ADOMD.NET框架,该框架允许运行参数化查询并具有更小的开销。
于 2015-06-14T13:28:43.803 回答