Creare tabelle, partizioni e colonne in un modello tabulare
Si applica a:
SQL Server 2016 e versioni successive Analysis Services
Azure Analysis Services
Power BI Premium
In un modello tabulare una tabella è costituita da righe e colonne. Le righe sono organizzate in partizioni per supportare l'aggiornamento incrementale dei dati. Una soluzione tabulare può supportare diversi tipi di tabelle, a seconda della posizione di origine dei dati:
Tabelle regolari, in cui i dati provengono da un'origine dati relazionale, tramite il provider di dati.
Tabelle con push, in cui i dati vengono "inseriti" nella tabella a livello di codice.
Tabelle calcolate, in cui i dati provengono da un'espressione DAX che fa riferimento a un altro oggetto all'interno del modello per i relativi dati.
Nell'esempio di codice seguente verrà definita una tabella normale.
Elementi obbligatori
Una tabella deve avere almeno una partizione. Una tabella normale deve avere anche almeno una colonna definita.
Ogni partizione deve avere un'origine che specifica l'origine dei dati, ma l'origine può essere impostata su Null. In genere, l'origine è un'espressione di query che definisce una sezione di dati nel linguaggio di query del database pertinente.
Esempio di codice: creare una tabella, una colonna, una partizione
Le tabelle sono rappresentate dalla classe Table (nello spazio dei nomi Microsoft.AnalysisServices.Tabular).
Nell'esempio seguente verrà definita una tabella normale con una partizione collegata a un'origine dati relazionale e alcune colonne normali. Verranno inoltre inviate le modifiche al server e verrà attivato un aggiornamento dei dati che porta i dati nel modello. Ciò rappresenta lo scenario più tipico quando si vogliono caricare dati da un database SQL Server relazionale in una soluzione tabulare.
using System;
using Microsoft.AnalysisServices;
using Microsoft.AnalysisServices.Tabular;
namespace TOMSamples
{
class Program
{
static void Main(string[] args)
{
//
// Connect to the local default instance of Analysis Services
//
string ConnectionString = "DataSource=localhost";
//
// The using syntax ensures the correct use of the
// Microsoft.AnalysisServices.Tabular.Server object.
//
using (Server server = new Server())
{
server.Connect(ConnectionString);
//
// Generate a new database name and use GetNewName
// to ensure the database name is unique.
//
string newDatabaseName =
server.Databases.GetNewName("Database with a Table Definition");
//
// Instantiate a new
// Microsoft.AnalysisServices.Tabular.Database object.
//
var dbWithTable = new Database()
{
Name = newDatabaseName,
ID = newDatabaseName,
CompatibilityLevel = 1200,
StorageEngineUsed = StorageEngineUsed.TabularMetadata,
};
//
// Add a Microsoft.AnalysisServices.Tabular.Model object to the
// database, which acts as a root for all other Tabular metadata objects.
//
dbWithTable.Model = new Model()
{
Name = "Tabular Data Model",
Description = "A Tabular data model at the 1200 compatibility level."
};
//
// Add a Microsoft.AnalysisServices.Tabular.ProviderDataSource object
// to the data Model object created in the previous step. The connection
// string of the data source object in this example
// points to an instance of the AdventureWorks2014 SQL Server database.
//
string dataSourceName = "SQL Server Data Source Example";
dbWithTable.Model.DataSources.Add(new ProviderDataSource()
{
Name = dataSourceName,
Description = "A data source definition that uses explicit Windows credentials for authentication against SQL Server.",
ConnectionString = "Provider=SQLNCLI11;Data Source=localhost;Initial Catalog=AdventureWorks2014;Integrated Security=SSPI;Persist Security Info=false",
ImpersonationMode = Microsoft.AnalysisServices.Tabular.ImpersonationMode.ImpersonateAccount,
Account = @".\Administrator",
Password = "P@ssw0rd",
});
//
// Add a table called Individual Customers to the data model
// with a partition that points to a [Sales].[vIndividualCustomer] view
// in the underlying data source.
//
dbWithTable.Model.Tables.Add(new Table()
{
Name = dbWithTable.Model.Tables.GetNewName("Individual Customers"),
Description = "Individual customers (names and email addresses) that purchase Adventure Works Cycles products online.",
Partitions = {
//
// Create a single partition with a QueryPartitionSource for a query
// that imports all customer rows from the underlying data source.
//
new Partition() {
Name = "All Customers",
Source = new QueryPartitionSource() {
DataSource = dbWithTable.Model.DataSources[dataSourceName],
Query = @"SELECT [FirstName]
,[MiddleName]
,[LastName]
,[PhoneNumber]
,[EmailAddress]
,[City]
FROM [Sales].[vIndividualCustomer]",
}
}
},
Columns =
{
//
// DataColumn objects refer to regular table columns.
// Each DataColumn object corresponds to a column in the underlying data source query.
//
new DataColumn() {
Name = "FirstName",
DataType = DataType.String,
SourceColumn = "FirstName",
},
new DataColumn() {
Name = "MiddleName",
DataType = DataType.String,
SourceColumn = "MiddleName",
},
new DataColumn() {
Name = "LastName",
DataType = DataType.String,
SourceColumn = "LastName",
},
new DataColumn() {
Name = "PhoneNumber",
DataType = DataType.String,
SourceColumn = "PhoneNumber",
},
new DataColumn() {
Name = "EmailAddress",
DataType = DataType.String,
SourceColumn = "EmailAddress",
},
new DataColumn() {
Name = "City",
DataType = DataType.String,
SourceColumn = "City",
},
}
});
//
// Add the new database object to the server's
// Databases connection and submit the changes
// with full expansion to the server.
//
server.Databases.Add(dbWithTable);
//
// Request a full refresh to import the data from the data source and
// and perform any necessary recalculations.
// The refresh operation will be performed with the next
// invocation of Model.SaveChanges() or Database.Update(UpdateOptions.ExpandFull).
dbWithTable.Model.RequestRefresh(Microsoft.AnalysisServices.Tabular.RefreshType.Full);
dbWithTable.Update(UpdateOptions.ExpandFull);
Console.Write("Database ");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(dbWithTable.Name);
Console.ResetColor();
Console.WriteLine(" created successfully.");
Console.WriteLine("The data model includes the following table definitions:");
Console.ForegroundColor = ConsoleColor.Yellow;
foreach (Table tbl in dbWithTable.Model.Tables)
{
Console.WriteLine("\tTable name:\t\t{0}", tbl.Name);
Console.WriteLine("\ttbl description:\t{0}", tbl.Description);
}
Console.ResetColor();
Console.WriteLine();
}
Console.WriteLine("Press Enter to close this console window.");
Console.ReadLine();
}
}
}
Partizioni in una tabella
Le partizioni sono rappresentate da una classe Partition (nello spazio dei nomi Microsoft.AnalysisServices.Tabular). La classe Partition espone una proprietà Source di tipo P artitionSource, che fornisce un'astrazione sui diversi approcci per l'inserimento dei dati nella partizione. Un'istanza partition può avere una proprietà Source come Null, che indica che i dati verranno inseriti nella partizione inviando blocchi di dati al server come parte dell'API dei dati push esposta da Analysis Services. In SQL Server 2016, la classe PartitionSource ha due classi derivate che rappresentano i modi per associare i dati a una partizione: QueryPartitionSource e CalculatedPartitionSource.
Colonne in una tabella
Le colonne sono rappresentate da diverse classi derivate dalla classe Column di base (nello spazio dei nomi Microsoft.AnalysisServices.Tabular):
- DataColumn (per le colonne normali nelle tabelle regolari)
- CalculatedColumn (per le colonne supportate dall'espressione DAX)
- CalculatedTableColumn (per le colonne normali nelle tabelle calcolate)
- RowNumberColumn (tipo speciale di colonna creata da SSAS per ogni tabella).
Numeri di riga in una tabella
Ogni oggetto Table in un server ha un oggetto RowNumberColumn usato a scopo di indicizzazione. Non è possibile crearlo o aggiungerlo in modo esplicito. La colonna viene creata automaticamente quando si salva o si aggiorna l'oggetto:
Db. Savechanges
Db. Update(ExpandFull)
Quando si chiama uno dei due metodi, il server creerà automaticamente la colonna del numero di riga, che sarà visibile come RowNumberColumn della raccolta Columns della tabella.
Tabelle calcolate
Le tabelle calcolate derivano da un'espressione DAX che ri-utilizza i dati da strutture di dati esistenti nel modello o da associazioni out-of-line. Per creare una tabella calcolata a livello di codice, eseguire le operazioni seguenti:
Creare una tabella generica.
Aggiungere una partizione con Source di tipo CalculatedPartitionSource, dove l'origine è un'espressione DAX. L'origine della partizione è ciò che distingue una tabella normale da una tabella calcolata.
Quando si salvano le modifiche nel server, il server restituirà l'elenco inferito di CalculatedTableColumns (le tabelle calcolate sono costituite da colonne di tabella calcolate), visibili tramite la raccolta Columns della tabella.
Passaggio successivo
Esaminare le classi usate per la gestione delle eccezioni in TOM: Gestione degli errori in TOM