Введение в SQL Server Analysis Services для разработчика. Параметризованные MDX-запросы.
Странно, но иногда на семинарах обнаруживается, что народ искренне полагает, будто в MDX-запрос в отличие от SQL нельзя передать параметры. Я думаю, это заблуждение происходит скорее всего оттого, что в SQL Server Management Studio в редакторе Analysis Services MDX Query нет возможности задать параметризованный запрос. Синтаксис MDX поддерживает параметры в запросе, а почему их не удосужились приспособить в SSMS - вопрос к тем, кто ее писал. Параметры можно передать, написав классический XMLA. Если вместо Analysis Services MDX Query открыть в SSMS Analysis Services XMLA Query и изобразить что-нибудь навроде
<Execute xmlns="urn:schemas-microsoft-com:xml-analysis">
<Command>
<Statement>
select [Measures].members on 0,
Filter(Customer.[Customer Geography].Country.members,
Customer.[Customer Geography].CurrentMember.Name = @CountryName) on 1
from [Adventure Works]
</Statement>
</Command>
<Properties>
<PropertyList>
<Catalog>Adventure Works DW 2008R2</Catalog>
</PropertyList>
</Properties>
< Parameters >
< Parameter >
< Name > CountryName</Name>
< Value > 'United Kingdom'</Value>
</ Parameter >
</ Parameters >
</Execute>
Скрипт 1
можно видеть, что параметризованные запросы прекрасно работают (см. Рис.1). Еще возникает недоумение, что бы в синтаксисе XMLA было не сделать однотипными элементы <Properties> и <Parameters>? Например, вместо
<Properties>
<PropertyList>
<Catalog>Adventure Works DW 2008R2</Catalog>
</PropertyList>
</Properties>
сделать, как у параметров:
<Properties>
<Property>
<Name> Catalog</Name>
<Value> Adventure Works DW 2008R2</Value>
</Property>
</Properties>
или наоборот? Не знаю, Моше виднее.
Рис.1
К сожалению, редактор XMLA в SSMS отображает результат запроса в его исконном виде XML и не позволяет его отобразить в виде наглядного набора ячеек, как это умеет делать редактор MDX Query:
Рис.2
Ровно так же параметризованный запрос можно выполнить из приложения. Программно заслать в AS произвольный XMLA-запрос можно, например, средствами SOAP, как рассматривалось в одном из предыдущих постов. В ADOMD.NET, как мы помним, в AdomdCommand можно засунуть только начинку элемента Command. Элементы Properties и Parameters в XMLA-запросе находятся на одном уровне с элементом Command и в его InnerXml не попадают. Для их передачи используются коллекции Properties и Parameters класса AdomdCommand:
using System.Data;
using System.IO;
using System.Xml;
using System.Diagnostics;
using Microsoft.AnalysisServices.AdomdClient;
class Program
{
static void Main(string[] args)
{
AdomdConnection cnn = new AdomdConnection(@"Data Source=http://192.168.0.29/msolap/msmdpump.dll; User ID=192.168.0.29\\Administrator;Password=cth%tyflf");
cnn.Open();
AdomdCommand cmd = new AdomdCommand(
@"select [Measures].members on 0,
Filter(Customer.[Customer Geography].Country.members,
Customer.[Customer Geography].CurrentMember.Name = @CountryName) on 1
from [Adventure Works]", cnn);
cmd.Properties.Add("Catalog", "Adventure Works DW 2008R2");
cmd.Parameters.Add(new AdomdParameter("CountryName", "United Kingdom"));
CellSet res = cmd.ExecuteCellSet();
for (int i = 0; i < res.Axes[0].Positions.Count; i++)
{
Debug.WriteLine("");
for (int j = 0; j < res.Axes[1].Positions.Count; j++)
Debug.Write(res.Cells[i, j].FormattedValue);
}
cnn.Close();
}
}
Скрипт 2
В данном случае название базы перешло из элемента Catalog родительского элемента PropertyList родительского элемента Properties
<Properties>
<PropertyList>
<Catalog>Adventure Works DW 2008R2</Catalog>
</PropertyList>
</Properties>
(Скрипт 1) в член коллекции cmd.Properties["Catalog"] - см.Скрипт 2, а параметр запроса - из элемента
<Parameters>
<Parameter>
<Name>CountryName</Name>
<Value>'United Kingdom'</Value>
</Parameter>
</Parameters>
(Скрипт 1) в член коллекции cmd.Parameters["CountryName"]. Можно посмотреть на результат и убедиться, что он совпадает с рис.2 с точностью до форматирования.
Рис.3
В данном примере по-прежнему используется доступ к Analysis Services по HTTP. Если дело происходит в пределах одного домена, то, как отмечалось в одном из предыдущих постов, можно заменить строку соединения на «Data Source= 192.168.0.29». Тогда бы SOAP шел непосредственно по ТСР.
Возникает вопрос, неужели верхнеуровневость ADOMD.NET по сравнению с SOAP не позволит выполнить из нее полноценный XMLA просто как он есть? Без того, чтобы предварительно сепарировать его на команду, свойства, параметры и т.д. и рассовывать это хозяйство по разным объектам ADOMD.NET. Смотрите следующую серию.
Алексей Шуленин