Optimierungen des Berichtsdatendiensts für benutzerdefinierte Felder

Letzte Aktualisierung: Dezember 2009

 

Letztes Änderungsdatum des Themas: 2015-02-27

In diesem Artikel wird beschrieben, wie benutzerdefinierte Berichterstellungslösungen für die Berichtsdatenbank von Microsoft Office Project Server 2007 optimiert werden. Wenn Sie benutzerdefinierte Sichten erstellen oder benutzerdefinierte Indizes auf beliebige Sichten in der Berichtsdatenbank anwenden möchten, finden Sie hier Informationen zu gespeicherten Hilfsprozeduren, die in Verbindung mit Ihren Lösungen verwendet werden können.

Wenn Sie noch nicht mit der allgemeinen Funktionsweise der Berichtsdatenbank vertraut sind, finden Sie Informationen in folgenden Hintergrundartikeln:

Zunächst wird dargestellt, wie Daten für benutzerdefinierte Felder in der Berichtsdatenbank gespeichert werden. Office Project Server 2007 verfügt über mehrere vordefinierte benutzerdefinierte Felder. Mit zunehmendem Umfang der Instanz werden neue benutzerdefinierte Enterprise-Felder hinzugefügt, und vorhandene werden während der regelmäßigen Wartung gelöscht. Der Mechanismus zur Speicherung benutzerdefinierter Felder in der Berichtsdatenbank wurde so entwickelt, dass die Hinzufügung und Entfernung von Feldern dynamisch behandelt wird. Er wurde zur Optimierung von Cubeerstellungs- und Berichtsvorgängen denormalisiert. Benutzerdefinierte Felder werden in folgenden Spaltenpooltabellen mit mehreren Spalten gespeichert: MSP_EpmCPPrj*, MSP_EpmCPRes*, MSP_EpmCPTask* und MSP_EpmCPAssn* für Projekt-, Ressourcen-, Vorgangs- bzw. Zuordnungsdaten. Wenn neue benutzerdefinierte Felder erstellt werden, werden Spaltenpooltabellen neue Spalten vom entsprechenden Entitätstyp hinzugefügt. Wenn die vorhandenen Tabellen eine bestimmte Anzahl von Spalten erreichen, werden neue Tabellen erstellt. Eine detailliertere Beschreibung der Speicherung von benutzerdefinierten Feldern in der Berichtsdatenbank finden Sie unter Benutzerdefinierte lokale und Enterprise-Felder (in englischer Sprache) (https://go.microsoft.com/fwlink/?linkid=123368\&clcid=0x407) in der MSDN Library.

Das Infrastrukturupdate für Microsoft Office Server enthält die folgenden Sichten, in denen Daten benutzerdefinierter Felder in der Berichtsdatenbank für jede der vier Kernentitäten zusammengefasst sind:

  • MSP_EpmProject_UserView

  • MSP_EpmTask_UserView

  • MSP_EpmAssignment_UserView

  • MSP_EpmResource_UserView

Diese Benutzersichten werden von Office Project Server verwaltet und enthalten alle für die entsprechende Entität definierten benutzerdefinierten Felder. Wenn ein benutzerdefiniertes Feld hinzugefügt wird, wird der entsprechenden Sicht automatisch eine neue Spalte hinzugefügt. Wenn ein benutzerdefiniertes Feld gelöscht wird, wird die entsprechende Spalte aus der Sicht entfernt.

Sie können auch eigene Sichten entsprechend den Anforderungen Ihrer Organisation erstellen. Wird z. B. im einem Bericht nur eine kleine Teilmenge der Felder verwendet, können Sie eigene benutzerdefinierte Sichten mit ausschließlich den relevanten Daten erstellen, statt die Standardsichten zu verwenden.

Erstellen benutzerdefinierter Sichten

Zum Erstellen eigener benutzerdefinierter Sichten müssen Sie zunächst ermitteln, wo die Feldwerte gespeichert werden. Wenn Sie die Spaltenpooltabelle und die Spaltennummer kennen, die auf das betreffende Feld verweisen, können Sie mit einer Join-Anweisung Werte für die Sicht abrufen. Alle Spaltenpooltabellen weisen eine EntityUID-Spalte auf, die den eindeutigen Bezeichner der Entität enthält, auf die eine bestimmten Datenzeile verweist.

Hilfsfunktion

Die folgende Funktion gibt interessante Informationen zu allen benutzerdefinierten Feldern zurück.

FUNCTION MFN_Epm_GetAllCustomFieldsInformation();

Rückgabewerte

Die Funktion gibt ein Dataset mit Informationen zu benutzerdefinierten Feldern zurück (eine Zeile für jedes benutzerdefinierte Feld). Wird kein benutzerdefiniertes Feld gefunden, wird ein leeres Dataset zurückgegeben.

Das zurückgegebene Dataset enthält für jedes benutzerdefinierte Feld eine Zeile mit den folgenden Spalten:

Wert Beschreibung

EntityTypeUID

Der eindeutige Bezeichner der übergeordneten Entität für jedes benutzerdefinierte Feld. (Beispiel: Für benutzerdefinierte Projektfelder wird in der Spalte der Projects entsprechende Wert angezeigt.)

EntityName

Der Name der übergeordneten Entität jedes benutzerdefinierten Felds (im obigen Beispiel: Projects).

CustomFieldTypeUID

Der eindeutige Bezeichner des benutzerdefinierten Felds.

CustomFieldName

Der Name des benutzerdefinierten Felds.

SecondaryCustomFieldTypeUID

Die Nummer des entsprechenden benutzerdefinierten Felds.

DataType

Der Datentyp des benutzerdefinierten Felds.

IsMultiValueEnabled

Die Spalte enthält den Wert 1, wenn das benutzerdefinierte Feld mehrere Werte aufweisen kann.

IsRollDown

Die Spalte enthält den Wert 1, wenn die Werte des benutzerdefinierten Felds abwärts zugeordnet werden.

LookupTableUID

Wenn das benutzerdefinierte Feld eine Nachschlagetabelle aufweist, zeigt diese Spalte deren eindeutigen Bezeichner an. Andernfalls hat die Spalte den Wert NULL.

LookupTableName

Wenn das benutzerdefinierte Feld eine Nachschlagetabelle aufweist, zeigt diese Spalte deren Namen an. Andernfalls hat die Spalte den Wert NULL.

LookupTableMembersViewName

In Project Server wird für jede definierte Nachschlagetabelle eine Sicht definiert. Es gibt eine Sicht, in der alle zugehörigen Elemente ausgewählt werden. Diese Spalte enthält den Namen der Sicht mit den Mitgliedern der von dem benutzerdefinierten Feld verwendeten Nachschlagetabelle.

LookupTableHasMultipleLevels

Diese Spalte enthält den Wert 1, wenn die Werte der Nachschlagetabelle auf mehr als einer Ebene definiert sind.

ColumnPoolColumnName

Der Name der Spalte, in der die Werte benutzerdefinierter Felder gespeichert sind.

ColumnPoolTableName

Die Tabelle, in der die Werte benutzerdefinierter Felder gespeichert sind.

EntityNonTimephasedTableName

Die Tabelle, in der Daten ohne Zeitphasen für die übergeordnete Entität des benutzerdefinierten Felds gespeichert sind. (Beispiel: Für ein benutzerdefiniertes Projektfeld zeigt die Spalte MSP_EpmProject an.)

CreatedDate

Das Datum, an dem das benutzerdefinierte Feld erstellt wurde.

ModificationDate

Das Datum, an dem das benutzerdefinierte Feld zuletzt geändert wurde.

Beispiel

Im Folgenden finden Sie ein Beispiel dafür, wie eine einfache benutzerdefinierte Sicht mit zwei benutzerdefinierten Projektfeldern erstellt wird.

In diesem Beispiel wird angenommen, dass zwei vordefinierte benutzerdefinierte Ressourcenfelder (RBS und Cost Type) in der Sicht zusammen mit dem Ressourcennamen, der Ressourcennummer, dem Standardsatz der Ressource, dem Überstundensatz der Ressource sowie dem Windows NT-Kontonamen angezeigt werden sollen. Wenn Sie sicher sind, dass die benutzerdefinierten Feldnamen eindeutig sind und nicht geändert werden, können Sie mit der CustomFieldName-Spalte filtern. Allerdings wäre es günstiger, zunächst einen SELECT-Vorgang wie den folgenden auszuführen.

SELECT * FROM MFN_EpmGetAllCustomFieldsInformation() WHERE EntityName='Resource'

Identifizieren Sie in den Ergebnissen die gewünschten benutzerdefinierten Felder, und notieren Sie dann deren CustomFieldTypeUID-Werte. (Dies sind die eindeutigen Bezeichner.)

Für dieses Beispiel sei angenommen, Sie finden die beiden folgenden eindeutigen Bezeichner:

  • {0000783FDE84434B9564284E5B7B3F49} für RBS

  • {000039B78BBE4CEB82C4FA8C0C400284} für Cost Type

Mit den beiden eindeutigen Bezeichnern für RBS und Cost Type aus dem obigen Beispiel können Sie das folgende Skript erstellen:

--Declare the variables used
DECLARE @CommandTextnvarchar(4000)-- This is the buffer where 
--  the command will be created

-- Declare the variables used 
DECLARE
-- This is the information necessary about each custom field:
DECLARE @TableNameForCF1 nvarchar(100) 
DECLARE @ColumnNameForCF1 nvarchar(100) 
DECLARE @TableNameForCF2 nvarchar(100) 
DECLARE @ColumnNameForCF2 nvarchar(100) 
-- Get the information about RBS custom field: 
SELECT
@TableNameForCF1  = ColumnPoolTableName,
@ColumnNameForCF1 = ColumnPoolColumnName
FROMMFN_Epm_GetAllCustomFieldsInformation()
WHERE
CustomFieldTypeUID = '{0000783F-DE84-434B-9564-284E5B7B3F49}'--RBS ID
-- Get the information about Cost Type custom field: 
SELECT
@TableNameForCF2 = ColumnPoolTableName, 
@ColumnNameForCF2 = ColumnPoolColumnName
FROMMFN_Epm_GetAllCustomFieldsInformation()
WHERE 
CustomFieldTypeUID = '{000039B7-8BBE-4CEB-82C4-FA8C0C400284}'-- Cost Type ID
--Now we can build the SELECT command that will get the data in the view
SET @CommandText = 'SELECT ResourceUID, ResourceName, ResourceNTAccount, '  +
'ResourceStandardRate, ResourceOvertimeRate,'
--If both custom fields are allocated in the same column pool table, 
--  we just need to join with it once 
IF @TableNameForCF1 = @TableNameForCF2 
SET @CommandText = @CommandText + ' RCFV.' + @ColumnNameForCF1 + ', ' +
'RCFV.'+ @ColumnNameForCF2 + '' +
'FROM MSP_EpmResource' +
'INNER JOIN ' + @TableNameForCF1 + ' AS RCFV' +
'  ON MSP_EpmResource.ResourceUID = RCFV.EntityUID'
ELSE 
SET @CommandText = @CommandText + ' RCF1V.' + @ColumnNameForCF1 + ', ' +
'RCF2V.'+ @ColumnNameForCF2 + '' +
'FROM MSP_EpmResource' +
'INNER JOIN ' + @TableNameForCF1 + ' AS RCFV1' +
'  ON MSP_EpmResource.ResourceUID = RCFV1.EntityUID' +
'INNER JOIN ' + @TableNameForCF2 + ' AS RCFV2' +
'ON MSP_EpmResource.ResourceUID = RCFV2.EntityUID'
--Now we have the command, we can execute it 
SET @CommandText = 'CREATE VIEW MySampleView AS ' + @CommandText 
EXECsp_executesql @CommandText

Erstellen von Indizes für benutzerdefinierte Felder

Es kann kompliziert sein, herauszufinden, in welcher Spalte welcher Tabelle die Werte eines bestimmten benutzerdefinierten Felds gespeichert werden. Daher verfügt Project Server über zwei gespeicherte Prozeduren, mit denen ein Index für die entsprechende Spalte erstellt wird. Als Eingabe der Prozeduren werden das benutzerdefinierte Feld und die Indexparameter übergeben.

Gespeicherte Hilfsprozeduren

Wenn Sie feststellen, dass für ein benutzerdefiniertes Feld ein Index erforderlich ist, um die Leistung der von einigen Berichten verwendeten Abfragen zu verbessern, können Sie die folgenden Methoden verwenden:

Methode 1:

PROCEDURE MSP_CreateCustomFieldIndexByUID(@CustomFieldTypeUIDuniqueidentifier, @PadIndex bit= NULL,@FillFactorsmallint= NULL,@NoRecomputeStatistics bit= NULL,@SortInTempDB bit= NULL,@FileGroupnvarchar(400)= NULL);

Methode 2:

PROCEDURE MSP_CreateCustomFieldIndexByName(@customFieldName [NAME], @customFieldEntityName [NAME] = NULL,@PadIndex bit= NULL,@FillFactorsmallint= NULL,@NoRecomputeStatistics bit= NULL,@SortInTempDB bit= NULL,@FileGroupnvarchar(400)= NULL);

Parameter für "MSP_Epm_CreateCustomFieldIndexByUID"

Mit dem folgenden Parameter wird das benutzerdefinierte Feld identifiziert:

Parameter Beschreibung

@CustomFieldTypeUID

Die eindeutige Nummer des benutzerdefinierten Felds, für das der Index erstellt wird.

Die folgenden Parameter definieren den Index:

Parameter Beschreibung

@PadIndex

Optional. Gibt den auf jeder Seite auf den Zwischenebenen des Indexes frei zu lassenden Speicherplatz an.

@FillFactor

Optional. Gibt an, zu welchem Prozentsatz die Blattebene jeder Indexseite bei der Indexerstellung von Microsoft SQL Server gefüllt werden soll. Der Wert des Parameters muss zwischen 1 und 100 liegen.

@NoRecomputeStatistics

Optional. Ist der Wert 1, werden veraltete Indexstatistiken nicht automatisch neu berechnet.

@SortInTempDB

Optional. Ist der Wert 1, werden die Zwischenergebnisse der Sortierung zur Erstellung des Indexes in der tempdb-Datenbank gespeichert.

@FileGroup

Optional. Der Index wird für die angegebene Dateigruppe erstellt.

Parameter für "MSP_Epm_CreateCustomFieldIndexByName"

Mit den folgenden Parametern wird das benutzerdefinierte Feld identifiziert:

Parameter Beschreibung

@CustomFieldName

Der Name des benutzerdefinierten Felds, für das der Index erstellt wird.

@CustomFieldEntityName

Optional. Der Name der Entität, für die das benutzerdefinierte Feld definiert ist (z. B. Project für benutzerdefinierte Projektfelder oder Resource für benutzerdefinierte Ressourcenfelder usw.).

Die folgenden Parameter definieren den Index:

Parameter Beschreibung

@PadIndex

Optional. Gibt den auf jeder Seite auf den Zwischenebenen des Indexes frei zu lassenden Speicherplatz an.

@FillFactor

Optional. Gibt an, zu welchem Prozentsatz die Blattebene jeder Indexseite bei der Indexerstellung von SQL Server gefüllt werden soll. Der Wert des Parameters muss zwischen 1 und 100 liegen.

@NoRecomputeStatistics

Optional. Ist der Wert 1, werden veraltete Indexstatistiken nicht automatisch neu berechnet.

@SortInTempDB

Optional. Ist der Wert 1, werden die Zwischenergebnisse der Sortierung zur Erstellung des Indexes in der tempdb-Datenbank gespeichert.

@FileGroup

Optional. Der Index wird für die angegebene Dateigruppe erstellt.

Weitere Informationen zu den Parametern, die die Indexerstellung definieren, finden Sie in einer Beschreibung des CREATE INDEX-Befehls in der MSDN Library: CREATE INDEX (Transact-SQL) (https://go.microsoft.com/fwlink/?linkid=94749\&clcid=0x407).

Rückgabewerte für beide Verfahren

Im Folgenden sind die Rückgabewerte für die vorherigen Verfahren aufgeführt:

Wert Beschreibung

0

Erfolg. Der Index wurde erfolgreich erstellt.

-1

Der Index wurde nicht erstellt, da das angefragte benutzerdefinierte Feld nicht gefunden wurde.

-2

Der Index ist bereits vorhanden.

-3

Der Index wurde nicht erstellt. Fehler bei der CREATE INDEX-Anweisung.

-4

Fehler beim Generieren der CREATE INDEX-Anweisung. Die Anweisung wird in einer Textvariablen generiert und dann dynamisch ausgeführt. Dieser Fehler wird zurückgegeben, wenn beim Erstellen der Befehlszeichenfolge ein Fehler auftritt.

-5

Das angegebene benutzerdefinierte Feld konnte mit dieser Methode nicht indiziert werden. Einige Typen von benutzerdefinierten Feldern können mit den angegebenen gespeicherten Prozeduren nicht indiziert werden (z. B. mehrwertige benutzerdefinierte Felder).

-6

Der Index konnte nicht erstellt werden, da mehrere benutzerdefinierte Felder mit den angegebenen Kriterien übereinstimmen. Das Problem kann auftreten, wenn es zwei oder mehr benutzerdefinierte Felder mit demselben Namen (für verschiedene Entitäten) gibt und die Methode zum Indizieren eines benutzerdefinierten Felds nach Namen nur mit dem benutzerdefinierten Feldnamen und ohne Angabe eines Entitätsnamens aufgerufen wird.

Beispiel

Im folgenden Beispiel wird eines der beiden vordefinierten benutzerdefinierten Ressourcenfelder verwendet: Cost Type. Es gibt zwei Methoden zum Identifizieren der benutzerdefinierten Felder: nach Nummer oder nach Namen. Im Folgenden sind Verwendungsbeispiele für beide Methoden angegeben. Die empfohlene Vorgehensweise ist jedoch die Verwendung der Nummer, um benutzerdefinierte Felder zu identifizieren.

Verwenden Sie folgenden Aufruf, um einen Index für das benutzerdefinierte Ressourcenfeld Cost Type nach Namen zu erstellen:

EXECMSP_Epm_CreateCustomFieldIndexByName'Cost Type', 'Resource'

Verwenden Sie folgenden Aufruf, um einen Index für dieses benutzerdefinierte Feld nach Nummer zu erstellen (Informationen zum Abrufen der UID des benutzerdefinierten Felds mithilfe der MFN_EpmGetAllCustomFieldsInformation-Funktion finden Sie vorherigen Abschnitt):

EXECMSP_Epm_CreateCustomFieldIndexByUID'{000039B7-8BBE-4CEB-82C4-FA8C0C400284}'

Aufrechterhalten der Gültigkeit von Sichten und Indizes

Sie können die Berichterstellung mithilfe der oben genannten Methoden optimieren, indem Sie Indizes für benutzerdefinierte Felder anwenden und auf die Benutzer zugeschnittene Sichten erstellen, wie in den vorherigen Abschnitten beschrieben. Beachten Sie jedoch, dass bei einer Aktualisierung der Berichtsdatenbank Indizes und benutzerdefinierte Sichten, die benutzerdefinierte Felder verwenden, ungültig werden können.

Der Grund ist, dass bei einer Aktualisierung alle Spaltenpooltabellen für benutzerdefinierte Felder gelöscht werden und alle benutzerdefinierten Felder aus der Berichtsdatenbank gelöscht werden. Bei der Neusynchronisierung kann sich die Zuordnungsreihenfolge der benutzerdefinierten Felder ändern. Dies bedeutet, dass die Werte für ein benutzerdefiniertes Feld möglicherweise in einer anderen Spalte oder sogar in einer anderen Tabelle gespeichert werden.

Angenommen, zwei benutzerdefinierte Felder wurden in der folgenden Reihenfolge erstellt: zuerst CF1, dann CF2. Bei CF1 und CF2 handelt es sich um benutzerdefinierte Textfelder. CF1 erhält in der Tabelle die CFVal0-Spalte, CF2 die CFVal1-Spalte. Die Spaltenpooltabelle sieht etwa folgendermaßen aus:

EntityUID CFVal0 CFVal1 CFVal2 CFVal3 …

AF129A8C-DCB5-4FB0- 9E30-406458614A31

Budget unterschritten

Termingerecht

15

NULL

4D607B14-E40C-4549- 8E92-45A3A96D6892

Kein Basisplan

Kein Basisplan

NULL

NULL

8496EA23-4B25-4DBE- B68A-755A27246842

Budget überschritten

Termingerecht

15

NULL

Wenn CF1 gelöscht wird, sieht die Tabelle folgendermaßen aus:

EntityUID CFVal0 CFVal1 CFVal2 CFVal3 …

AF129A8C-DCB5-4FB0- 9E30-406458614A31

NULL

Termingerecht

15

NULL

4D607B14-E40C-4549- 8E92-45A3A96D6892

NULL

Kein Basisplan

NULL

NULL

8496EA23-4B25-4DBE- B68A-755A27246842

NULL

Termingerecht

15

NULL

Nach einer Aktualisierung werden die Spalten in der Spaltenpooltabelle jedoch neu aufgefüllt (CF1 ist nicht mehr vorhanden, und CF2 belegt jetzt die CFVal0-Spalte). Die Tabelle sieht folgendermaßen aus:

EntityUID CFVal0 CFVal1 CFVal2

AF129A8C-DCB5-4FB0- 9E30-406458614A31

Termingerecht

15

NULL

4D607B14-E40C-4549- 8E92-45A3A96D6892

Termingerecht

NULL

NULL

8496EA23-4B25-4DBE- B68A-755A27246842

Termingerecht

15

NULL

Wenn Sie zuvor eine benutzerdefinierte Sicht oder einen Index erstellt haben, die bzw. der auf CFVal1 verweist, wird nach einer Aktualisierung der Berichtsdatenbank anstatt auf CF2 auf ein anderes benutzerdefiniertes Feld verwiesen. Das Fazit ist, dass in solchen Fällen der Index auf die falsche Spalte verweist, was nicht wünschenswert ist. Zur Lösung des Problems haben Sie folgende Möglichkeit: Wenn Sie zur Leistungsoptimierung der Berichterstellung benutzerdefinierte Sichten oder Indizes erstellen, sollten Sie erwägen, auch folgende gespeicherte Prozedur zu erstellen:

PROCEDURE MSP_OnRefreshCompleted();

Wenn diese gespeicherte Prozedur vorhanden ist, wird sie nach einer erfolgreichen Aktualisierung der Berichtsdatenbank automatisch aufgerufen. Dadurch werden die Indizes und/oder benutzerdefinierten Sichten für benutzerdefinierte Felder neu erstellt.

Beispiel

Sollen die Änderungen aus den beiden obigen Beispielen nach einer Aktualisierung der Berichtsdatenbank gültig bleiben, müssen Sie die beiden Skripts in eine gespeicherte Prozedur konvertieren und mit MSP_OnRefreshCompleted benennen. Außerdem müssen Sie sicherstellen, dass die gespeicherte Prozedur eintrittsinvariant ist (das bedeutet, dass sie ordnungsgemäß ausgeführt wird, wenn sie mehrmals hintereinander aufgerufen wird).

CREATE PROCEDUREMSP_OnRefreshCompleted 
AS 
BEGIN
-- Declare the variables used
DECLARE @CommandTextnvarchar(4000)-- This is the buffer where the commandwill be created
-- This is the information necessary about each custom field: 
DECLARE @TableNameForCF1 nvarchar(100)
DECLARE @ColumnNameForCF1 nvarchar(100)
DECLARE @TableNameForCF2 nvarchar(100)
DECLARE @ColumnNameForCF2 nvarchar(100) 
DECLARE@ViewNamenvarchar(100)SET @ViewName ='MySampleView'
--Drop the old view, if one exists 
IFEXISTS(SELECT*FROMdbo.sysobjects WHEREid =OBJECT_ID('[dbo].['+@ViewName +']') AND 
OBJECTPROPERTY(id,'IsView')= 1) 
BEGIN 
SET@CommandText ='DROP VIEW [dbo].['+ @ViewName +']' 
EXECsp_executesql@CommandText 
END
-- Get the information about RBS custom field: 
SELECT
@TableNameForCF1  = ColumnPoolTableName,    
@ColumnNameForCF1 = ColumnPoolColumnName
FROMMFN_Epm_GetAllCustomFieldsInformation()
WHERE 
CustomFieldTypeUID = '{0000783F-DE84-434B-9564-284E5B7B3F49}'--RBS ID
-- Get the information about Cost Type custom field:
SELECT
@TableNameForCF2 = ColumnPoolTableNam
@ColumnNameForCF2 = ColumnPoolColumnName e, 
FROMMFN_Epm_GetAllCustomFieldsInformation()
WHERE
CustomFieldTypeUID = '{000039B7-8BBE-4CEB-82C4-FA8C0C400284}'-- Cost Type ID
--Now we can build the SELECT command that will get the data in the view
SET @CommandText = 'SELECT ResourceUID, ResourceName, ResourceNTAccount, '  +
'ResourceStandardRate, ResourceOvertimeRate,'
--If both custom fields are allocated in the same column pool table, we just need to join with it once 
IF @TableNameForCF1 = @TableNameForCF2 
SET @CommandText = @CommandText + ' RCFV.' + @ColumnNameForCF1 + ', ' +
'RCFV.'+ @ColumnNameForCF2 + '' +
'FROM MSP_EpmResource' +
'INNER JOIN ' + @TableNameForCF1 + ' AS RCFV' +
'  ON MSP_EpmResource.ResourceUID = RCFV.EntityUID' 
ELSE 
SET @CommandText = @CommandText + ' RCF1V.' + @ColumnNameForCF1 + ', ' +
'RCF2V.'+ @ColumnNameForCF2 + '' +
'FROM MSP_EpmResource' +
'INNER JOIN ' + @TableNameForCF1 + ' AS RCFV1' +
'  ON MSP_EpmResource.ResourceUID = RCFV1.EntityUID' +
'INNER JOIN ' + @TableNameForCF2 + ' AS RCFV2' +
'ON MSP_EpmResource.ResourceUID = RCFV2.EntityUID'
--Now we have the command, we can execute it 
SET @CommandText = 'CREATE VIEW MySampleView AS ' + @CommandText 
EXECsp_executesql @CommandText
-- Clear all the custom field indexes
EXECMSP_Epm_ClearAllCustomFieldIndexes
-- Re-Create all the indexes
EXECMSP_Epm_CreateCustomFieldIndexByUID'{000039B7-8BBE-4CEB-82C4-FA8C0C400284}' 
END 
GO 
GRANTEXECONdbo.MSP_OnRefreshCompleted_TestTOProjectServerRole 
GO

Jetzt werden die benutzerdefinierte Sicht MySampleView und der Index für das benutzerdefinierte Feld Cost Type nach einer Aktualisierung der Berichtsdatenbank automatisch erneut angewendet.