Category Archives: Uncategorized

Chapter 7

Administration Using SQL Server 2008 Tools

Let ’ s just jump in and get our feet wet, shall we? In Chapter 2 you used SSMS to view the objects found in an Analysis Services 2008 database. We ’ ll start here on a similar footing: 1. Launch SSMS from All Programs Microsoft SQL Server 2008 SQL Server Management Studio.

2. Using Object Explorer, connect to the Analysis Services instance.
3. Open the Databases folder.

You will see a tree view of those databases you have saved on the server to date, as shown in Figure 7 – 1 . One of those databases should be titled AnalysisServices2008Tutorial — you should take a moment to review the tree nodes and what they contain because you will be learning the administrative tasks associated with those objects.

Figure 7-1

Managing Analysis Servers

SSMS, the integrated management environment for SQL Server 2008 products, provides you the flexibility of managing several Analysis Services instances. In this chapter we use the word “ server ” to denote an instance of Analysis Services, and “ servers ” to denote one or more. If you have a set of production servers that are being used by customers and a set of test servers that are being used for development and testing purposes, you typically want to manage them differently. The most logical thing is to group these servers. Using the Register Servers window of SQL Server Management Studio, you can group a set of Analysis Services servers to form a Server group as shown in Figure 7 – 2 . You can register Analysis Services servers and organize them into groups using the New Server Group and New Server Registration dialogs that can be launched by right – clicking the Local Server Groups folder under the Analysis Services folder in the Registered Servers window of SSMS.

Some of the common tasks of starting, stopping, restarting, and configuring Analysis Services servers can also be accomplished from the Registered Servers window. You can right – click the specific Analysis Services instance and choose the appropriate operation. In addition, you can switch to the Object Explorer window of the connected SSAS instance, or launch the MDX query editor or SQL Server Configuration Manager dialog from this window.

 

Figure 7-2

Once you are connected to an Analysis Services server in the Object Explorer window, you can accomplish various administrative tasks on that server, such as creating new databases, providing permissions, processing objects, and moving databases from test servers to production servers. First and foremost for the Analysis Server admin is providing access permissions to the users who will be administering the server. The following steps show how to add a user as an administrator of an Analysis Services server by making them part of the object called Server Role:

1. In the Object Explorer window right – click the Analysis Services instance and select Properties. You will now see the Analysis Services Properties dialog.
2. Click Security in the page as shown in Figure 7 – 3 .

3. Click the Add button to add a user to the Analysis Services administrators group. You can add domain users, local machine users, or groups as part of the administrator group for Analysis Services. If your user is a local user you can specify < machinename > \username or just the username to add the user to this server administrator group.

 

Figure 7-3
Another important management task is to set appropriate Analysis Server properties so that Analysis Services performs optimally. You can do this using the Analysis Server Properties dialog shown in Figure 7 – 4 . Analysis Services needs to be restarted for certain properties to take effect. This is indicated by a “ yes ” in the Restart column for those properties in the Analysis Services Properties dialog. Some of the most important properties involve control of parallelism for processing and querying and changing the read buffer size for faster query response time. Equally important are the maximum amount of memory used by the Analysis Services processes, the maximum number of connections to the server, and the ability to turn certain features on or off. You learn some of these properties in this chapter and others in Chapter 14 . The properties dialog has a checkbox that enables you to view and modify the advanced properties of the Analysis Services server. Adding users to the Server role or Database role and setting properties are considered part of securing your Analysis Services server. You learn more about managing security at the end of this chapter.

Figure 7-4

Managing Analysis Services Objects

Several management tasks can be performed on Analysis Services objects. Some of the most important tasks are processing cubes and dimensions, providing access permissions to various objects within a database, managing the partitions of a cube based on usage, and adding assemblies to databases. Even though the SQL Server Management Studio provides a great interface to manage Analysis Services 2008 and abstracts all the internal details, it is beneficial to understand the underlying operations that take place when you perform the management operations. Knowledge of these server internals gives you an edge in better understanding its operation and helps you more effectively manage the server when unforeseen problems occur.

All communications to Analysis Services is through XML for Analysis (XMLA). The management tasks executed through SSMS use the management object model AMO (Analysis Management Objects), which in turn sends XMLA Execute commands to the Analysis Services instance. You will see some of the commands sent to the Analysis Services server when performing management tasks in this chapter.

Database Creation

SQL Server Analysis Services 2008 allows a server administrator to create databases and assign database administrative permissions to a user. The following steps show how to do this:
1. In the SSMS Object Explorer, right – click the Databases folder and select New Database as shown in Figure 7 – 5 .
Figure 7-5

2. Enter a new database name called DBATest as shown in Figure 7 – 6 and click OK. SSMS sends an XMLA command to SSAS to create the new database called DBATest. SSMS then refreshes the Databases folder by retrieving the list of Databases from SSAS. You should see the DBATest database as shown in Figure 7 – 7 . If you are an administrator of SSAS, your account is a member of the Analysis Services server administrator role as seen in Figure 7 – 3 . If you want to provide a user with database administrator privileges and not Analysis Services server- wide privileges, you need to provide appropriate permissions at the database level. Follow the next steps to provide database administrator permissions for a user.

 

Figure 7-6

Figure 7-7

3. Expand the folder DBATest. You will see the various folders under DBATest.
4. Right – click the folder Roles and select “ New Role ” as shown in Figure 7 – 7 .

5. In the Create Role dialog, check the “ Full control (Administrator) ” checkbox (shown in Figure 7 8 ) to provide full database administrator privileges.

Figure 7-8
6. Select the Membership page in the dialog as shown in Figure 7 – 9 .

 

7. Click the Add button on the Membership page to bring up the Select Users or Groups dialog.

8. Enter the user or users for whom you want to provide database permissions as shown in Figure 7 – 10 and click OK. You should now see the user you specified in the list of users who will have database permissions listed in the Create Role dialog.

Figure 7-10
9. Click OK in the Create Role dialog.

You have successfully created a database called DBATest and provided full database permissions to a specific user. The user listed under the role Role will have full permissions to modify any of the objects that are part of the database DBATest including deleting the database. This user does not have permissions to perform any database operations outside of the DBATest database unless the same user is part of the Analysis Server administrator role. To create data sources, Data Source Views, cubes, dimensions, and mining models we recommend creating/modifying the objects in the DBATest using the online mode in Business Intelligence Development Studio (BIDS). You learn to work with SSAS databases using the online mode of BIDS later in this chapter.

Processing Analysis Services Database Objects

One of the important jobs of an Analysis Services DBA (database administrator) is to process the objects (such as Cubes, Dimensions, and Mining Models) in an Analysis Services database. Analysis Services 2008 provides fine – grain control to the Analysis Services DBA to process the objects within an Analysis Services database using the Process dialog. You can launch the Process dialog by right – clicking the object folders such as Cubes, Dimensions, and Mining Structures — this works just as well on individual objects or groups of objects too. Based on the location from which the Process dialog is launched, the options for processing the object or group of objects will vary. In addition to this you can select an object and launch the Process dialog. To process the database AnalysisServices2008Tutorial, do the following:

1. Right – click the database AnalysisServices2008Tutorial and select Process as shown in Figure 7 – 11 .
Figure 7-11

You will see the Process dialog as shown in Figure 7 – 12 . This dialog shows the name of the object to be processed along with the type of object. Several processing options are available for each object. The default option for the database object is Process Full. As the name implies, the Process Full option allows you to process the selected object completely even if the object had been processed earlier. It will clear any data that was processed earlier.

 

2. When you click the OK button the Process dialog sends an XMLA command to the Analysis

Services instance to process the selected object. If you click on the Script button shown in Figure 7 – 12 and then select Script Action to New Query Window, you can see the Process XMLA command to be sent to the Analysis Services instance. You will see the following script command:

< Batch xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine” > < Parallel >

< Process xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:ddl2=”http://schemas.microsoft.com/analysisservices/
2003/engine/2” xmlns:ddl2_2=”http://schemas.microsoft.com/
analysisservices/2003/engine/2/2” xmlns:ddl100_100=”http://
schemas.microsoft.com/analysisservices/2008/engine/100/100” >

< Object >
< DatabaseID > AnalysisServices2008Tutorial < /DatabaseID >
< /Object >
< Type > ProcessFull < /Type >
< WriteBackTableCreation > UseExisting < /WriteBackTableCreation >
< /Process >
< /Parallel >
< /Batch >

3. Click OK in this dialog to process the AnalysisServices2008Tutorial database. When you click OK the Process dialog uses AMO to send the Process command to the Analysis Services instance.

The Process XMLA script contains several commands that are interpreted by Analysis Services. Because the medium of communication to Analysis Services is an XMLA request, the script is embedded within SOAP Envelope tags. This script can be executed from the XMLA editor within SQL Server Management Studio. SSMS adds the appropriate SOAP envelope tags to send the script to Analysis Services. The commands in the script are Batch, Parallel, and Process. The Process command is part of a set of commands that manipulate the data in Analysis Services. These commands that change the data in Analysis Services databases are called the DML (data manipulation language). The Batch command allows multiple commands to be executed within a single statement. The Parallel command allows you to instruct the Analysis Services instance to execute all the commands within the command in parallel. The Process command is used to process an Analysis Services object and needs several properties such as DatabaseID, Process Type, and processing options (not shown in the above XMLA script) such as parallelism for processing objects, and actions to be taken during dimension key errors that can be changed using the Change Settings button in the Process dialog . You learn the processing options provided by the Process dialog in this chapter.

As mentioned earlier, when you click OK in the Process dialog, a Process command with appropriate options is sent to the Analysis Services instance. This command requests the server to process the database. When processing the objects within a database, the server needs to read data from the data source, which is done by issuing queries to it. You will now see the Process Progress dialog that shows details of each processing operation on the server. As you can see from Figure 7 – 13 , the operations on each object within the database that is being processed are reported along with the timing information and whether the operation succeeded or failed. You can also see the query sent to the relational data source to retrieve the data. The detailed information returned from Analysis Services is very helpful if you need to investigate any issues in processing including the performance of processing an object.

 

Figure 7-13

Once all the objects have been processed you will see the results of the processing command. If all the objects were successfully processed, you will see Process succeeded in the status as shown in Figure 7 – 13 . If there were errors during processing, the status bar will show an appropriate message. The operations that resulted in an error are shown in red in the tree view of the Process Progress dialog. You can drill down into the details of the processing to understand the reasons for failure.

Several operations take place in the preceding processing command. All the objects within the database are processed in parallel based on the settings of the Analysis Services instance. If there are dependencies, the dependent objects are processed first. For example, the dimensions that are part of a cube need to be processed before the cube can be processed. Analysis Services processes all the objects of the database under a single transaction. What this means is that if one of the objects failed during processing, the remaining objects will not be processed and the effects of any previous operations will be rolled back. For example, if all the dimensions of a cube were successfully processed and if there were errors while processing the cube, the processing of the dimension objects will be rolled back. Once all the objects have been successfully processed, the server commits the transaction, which means that the objects are marked as processed and are available for querying.

Assume an Analysis Services object has been processed and is being queried by users. At the time users are querying the object, you can initiate processing on the same object. Because a version of the object is currently being queried, Analysis Services stores the uncommitted processed object in a temporary file. At the time of commit, the server first ensures that the user is not using the objects, removes the previous version of the processed objects, and then marks the temporary files as primary. You see this in detail in the following section.

Processing a Cube

An Analysis Services database can contain several cubes and dimensions. You have the flexibility to control the processing of individual cubes and dimensions by launching the Process dialog from appropriate cube or dimension objects. There are several processing options for processing a cube, as shown in Figure 7 – 14 . All of the same processing options available for partitions and measure groups are available for the cube because a cube is a collection of measure groups, which in turn is a collection of partitions.

Figure 7-14

When a cube is created you will typically do a full process ( Process Full in the Process dialog) of it so that you can browse the cube. Usually the cube structure will not change after the initial design is completed. In this case, you will be processing in order to get additional fact data that you would want to add to the cube. For example, you might have a Sales cube that you have created and you might be getting sales fact data from each store every month. Processing the entire cube whenever new data comes in will take a considerable amount of time, causing end users to have to wait for a long period to see the most up – to – date data. Analysis Services 2008 provides you with an option to process only the new fact data instead of the entire cube. This is called incremental processing. In order to add new fact data to the cube you can add a new partition to the cube and process that partition. Alternately, you can use the Process Incremental option in the Process dialog and specify the query that provides the new fact data that needs to be processed. Process Incremental is a common management task for data warehouses. If you specify the Process Default option in the Process dialog, the server checks for all the objects that have not been processed and only processes those objects. If the cube data has been processed and if aggregations and indexes are not processed, then those are processed.
When you choose the Process Full option for processing a cube, the server performs three internal operations. If the storage mode for the cube is MOLAP, the server first reads the data from the relational data and stores it in a compact format. If there were aggregations defined for the cube, the server will build those aggregations during this processing. Finally, the server creates indexes for the data that helps speed access to data during querying. Even if there were no aggregations specified for the cube, the server still creates the indexes. The Process Data option actually is the first step of the Process Full option where the server reads data from relational data sources and stores it in proprietary format. The second and third steps of processing aggregations and indexes can be separately accomplished by the Process Index option. You might be wondering why you have the Process Data and Process Index options when the Process Full and Process Default options actually accomplish the same task. These options provide the administrator with a fine grain of control. These are especially important when you have limited time to access the relational data source and want to optimize the processing on your machine. Having multiple processing operations running in parallel can require more system resources. Specifically on a 32 – bit (X86 machines) system, a large cube that fails on Process Full may be able to be successfully processed by sending Process Data and Process Index commands one after another. In such instances, we recommend you first get the data from your relational backend into SSAS using the Process Data option. Once you have all the data in the Analysis Services instance, you can then create your aggregations and indexes, which do not need access to the relational data source.

If you choose the Process Structure option, the server processes all the cube ’ s dimensions and the cube definitions so that the cube ’ s structure is processed without any processing of the data. The server will not process the partitions or measure groups of the cube, therefore you cannot see any of the fact data; however, you can browse the cube because the cube definitions are processed. You can retrieve metadata information about the cube (measure names, measure groups, dimensions, KPIs, actions, and so on) after processing the cube ’ s structure. However, you will not be able to query the cube data. For a cube that has been processed with Process Structure, you can see the cube in the SQL Server Management Studio MDX query editor when you select the drop – down list for the cube. If your cube contains linked measure groups and if they have been processed successfully, processing the cube with the Process Structure option will allow you to query the measures in linked measure groups. Often when you design your UDM you will want to make sure your design is correct and your customers are able to see the right measures and dimensions. Process Structure is helpful in validating your design. As soon as the data for the cube is available the cube can be processed with the Process Default option so that end users can query the data from the cube.

You can clear the data in the cube using the Unprocess option. The processing options provided in the Process dialog are different than the process types that are specified in the process command sent to Analysis Services. The following table shows how the various processing options map to the process types sent to Analysis Services:

Process Options in Process Dialog Process Type in Process Command

Pr ocess Full
Process Default
Process Data
Process Structure Unprocess
Process Index
Process Incremental Process Script Cache ProcessFull
ProcessDefault
ProcessData
ProcessStructure ProcessClear
ProcessIndexes
ProcessAdd
ProcessScriptCache

The processed data of a cube are stored in a hierarchical directory structure that is equivalent to the structure you see in the Object Explorer. Figure 7 – 15 shows the directory structure of the processed data of the AnalysisServices2008Tutorial database in Analysis Services 2008. The directory also shows the files within a partition. The metadata information about the cubes and dimensions are stored as XML files, and the data is stored in a proprietary format. Every time an object is processed, a new version number is appended to the object. For example, the files shown in Figure 7 – 15 are under a specific partition directory. The file info. < versionnumber > .xml is used to store the metadata information about the partition. Similar metadata files are stored within the directories of each object, cube, dimension, and measure group. We recommend you browse through each object folder to see the metadata information. The fact data is stored in the file with extension .data. The key to an OLAP database is the fast access to data. You learned about a cell, which was represented by a tuple. A tuple is the intersection of various dimension members. For fast data access, Analysis Services builds indexes to access data across multiple dimensions. The index files in Analysis Services have the extension “ map ” . In Figure 7 – 15 you can see the .map files that have the format < version > . < Dimension > . < Hierarchy > .fact.map. There is an associated header file for each map file. Analysis Services stores the data as blocks called segments for fast access. The associated header file contains offsets to the various segments for fast access during queries.

Figure 7-15

The processing dialog provides you the flexibility of processing objects in parallel or within the same transaction. If errors are encountered during processing, you can set options to handle these errors. You can configure the parallelism and error options by selecting the Change Settings button in the Process dialog. You will see the Change Settings dialog as shown in Figure 7 – 16 , which enables you to configure certain processing options and error settings during processing. Setting the parallelism option is as simple as selecting the appropriate option in the Processing Order section of the dialog. By default all the objects are processed in parallel and within the same transaction. If you do want failure of one object to impact other objects, you should process the objects under different transactions by choosing the sequential option.

 

Figure 7-16

You might encounter errors while processing your Analysis Services objects due to incorrect design or referential integrity problems in the relational data source. For example, if you have a fact record that contains a dimension id that is not available in the dimension table, you will see a “ Key not found ” error while processing the cube. By default, when an error is encountered during processing, the processing operation fails. You can change the settings in the processing dialog to take appropriate action other than failing the processing operation. The Dimension Key Errors page of the Change Settings dialog shown in Figure 7 – 17 allows changing the error configuration settings for all the objects selected for processing. Whenever you encounter key errors you can either convert the values to unknown or discard the erroneous records. You can run into key errors while processing facts or dimensions. If you encounter a key error while processing a cube, that means Analysis Services was unable to find a corresponding key in the dimension. You can assign the fact value to a member called the Unknown Member for that specific dimension. You can encounter key errors while processing a snowflake dimension when an attribute defined as a foreign key does not exist in the foreign table or when there are duplicate entries. The two most common types of key errors that you might encounter during dimension processing are key not found and duplicate key errors.

 

Figure 7-17

Processing a Dimension

You can process dimensions independent of the cubes they are a part of. After the initial processing of a dimension, you might process the dimensions on a periodic basis if additional records are added in the dimension table or there were changes to columns of an existing row. An example of additions to a dimension is new products being added to the products dimension. You would want this information to be reflected in the dimensions so that you can see the sales information for the new products. Another example of changes in dimension is when an employee moves from one city to another city; the attributes of the employee will need to change. Therefore the Process dialog provides you with various options for processing the dimension, as shown in Figure 7 – 18 .

 

Figure 7-18

While processing a dimension, Analysis Services reads data from the dimensions tables. When a dimension is processed, each attribute of the dimension is processed separately. Based on the parallelism specified on Analysis Services, these attributes can be processed in parallel. Each dimension contains an attribute called the All attribute. This is not exposed to the user but used internally by Analysis Services. You can see the files associated with this attribute as < version > .(All). < extension > in Figure 7 – 19 . When each attribute is processed, several files are created. Similar to fact data, dimension data is stored in a proprietary format. Each attribute of a dimension has a key column and a named column. These directly map into two different files with the extensions kstore and sstore, which refer to key store and string store, respectively. In addition, there are additional files that get created for each attribute of the dimension, which help in fast access to name, key, and levels of attributes and hierarchies. Files with the extension .map are created when indexes are processed for each attribute and help in fast retrieval of related attributes of the dimension for a dimension member.

 

Figure 7-19

The amount of time it takes to process a dimension depends on the number of attributes and hierarchies in the dimension as well as the number of members in each hierarchy. When a processing command is sent to the Analysis Services instance, the server reads the data from the relational data source and updates the dimension. When a dimension is processed, each attribute of the dimension is processed separately. Some attributes can be processed in parallel, whereas some cannot. The order of processing of various attributes is dependent on the relationships between the attributes in the dimensions and resources available on the machine. The relationships between attributes are defined at the dimension design time using the Attribute Relationships tab of the dimension designer, which you learned about in Chapter 5 . For example, say you have a Customer dimension that contains the attributes Customer Name, SSN, City, State, and Country. Assume SSN is the Key attribute for this dimension and by default all attributes within the dimension are related to the key attribute. In addition, assume additional attribute relationships have been established. They are Country State, State City, City Customer Name, State Customer Name, and Country Customer Name. Based on the preceding relationships, the order of processing of the attributes in the Customer dimension is Country, State, City, Customer Name, and SSN. This is because Analysis Services needs to have information about Country in order to establish the member property relationship while processing the State, Customer Name, or SSN. The key attribute is always the last attribute processed within a dimension.

When the Process Default option is chosen for processing, the dimension ’ s data or indexes are processed if they have not been processed or are out-of-date. If the Process Full option is chosen, the entire dimension is re – processed. When the Process Full option is used, dimension data and indexes that have been processed initially will be dropped and data is retrieved from the data source. The dimension processing time depends on the dimension size (number of dimension members as well as number of attributes and hierarchies in the dimension) and your machine resources.

Similar to incremental processing of the cubes you can incrementally process dimensions using the Process Update option. The Process Update option in the Process dialog maps to the ProcessUpdate process type in the process command, which is applied only to dimensions. Some dimensions such as Employees or Customers or Products can potentially contain a large number of members. Additional members may have been added to these dimensions or some attributes of these dimension members might have changed. Often a full processing of any dimension is not only unnecessary but cannot be afforded due to business needs. Under these circumstances incremental processing of the dimension or an update of the attributes of the dimension should be sufficient. When you choose the Process Update option for the dimension, the server scans all the dimensions in the dimension table. If there were changes to the dimension ’ s properties, such as caption or description, they are updated. If new members are added to the dimension table, these members are added to the existing dimension using incremental processing. The attributes of each dimension member will also be updated. The key of each dimension member is assumed to be the same, but expect some attributes to be updated. The most important attribute that is updated is the member property for each member. When you have a parent – child hierarchy in a dimension and if the parent attribute has been changed, that information is updated during the Process Update processing option.

The Process Data option for dimensions is used to process the dimension data. The indexes will not be processed when the Process Data option is used. The Process Index option is used to create indexes for attributes in the dimensions. If the ProcessMode dimension property is set to LazyAggregations, Analysis Services builds indexes for new attributes of the dimension as a lazy operation in the background thread. If you want to rebuild these indexes immediately you can do so by choosing the Process Index option. The Unprocess option is used to clear the data within the dimension.

Managing Partitions

Partitions enable you to distribute fact data within Analysis Services and aggregate data so that the resources on a machine can be efficiently utilized. When there are multiple partitions on the same server, you will reap the benefits of partitions because Analysis Services reads/writes data in parallel across multiple partitions. Fact data on the data source can be stored as several fact tables — Sales_Fact_2002, Sales_Fact_2003, and so on — or as a single large fact table called Sales Fact. You can create multiple partitions within a measure group; one for each fact table in the data source or by splitting data from a single large fact table through several queries. Partitions also allow you to split the data across two or more machines running Analysis Services, which are called Remote partitions. As an administrator you might be thinking what the size of each partition should be to achieve the best results. Microsoft recommends each partition to be 3 – 5GB or 20 million records. You learn more about optimizing partitions in Chapter 14 .

A sales cube ’ s partitions usually contain data spread across time, that is, a new partition might be created for every month or a quarter. As an administrator you would create a new partition from SQL Server Management Studio and process it so that it is available for users. To create a new partition, perform the following steps in BIDS:

1. Open the AnalysisServices2008Tutorial project you have used in previous chapters. 2. Change the FactInternetSales table to a named query so that there is a where condition DueDateKey < 20020101. In case you don ’ t recall how this is done, we ’ ve included the steps here: a. Open Adventure Works DW.dsv under the Data Source Views folder.
b. Right – click the FactInternetSales table in diagram view and select Replace Table With New Named Query menu item.

c. In the Create Named Query dialog, in the DueDateKey Filter text entry box, enter < 20020101. Your change will automatically be reflected in the query window as shown in Figure 7 – 20 . Click OK to continue.

 

Figure 7-20

3. In the DSV, right – click in the diagram view and select Add/Remove Tables from the context menu.

4. Add the FactInternetSales table to “ Included objects: ” list and click OK.
5. In the diagram view, replace the FactInternetSales table with a named query.
6. In the named query, set Filter to DueDateKey > =20020101.
7. Rename the named query as FactInternetSalesNew.
8. Deploy the AnalysisServices2008Tutorial project to your Analysis Services instance.
9. Connect to the AnalysisServices2008Tutorial database using SSMS.
10. Navigate to the measure group FactInternetSales.
11. Right – click the Partitions folder and select New Partition as shown in Figure 7 – 21 .

 

Figure 7-21

12. Click Next on the welcome screen of the Partition Wizard.

13. Choose the named query FactInternetSalesNew to create a new partition as shown in Figure 7 – 22 and click Next. Select the checkbox “ Specify a query to restrict rows ” . As suggested by the warning in the Restrict Rows page (Figure 7 – 23 ) you may need to specify a restriction on the query to filter appropriate data for a partition. In this example FactInternetSalesNew already has the appropriate query restriction.

 

Figure 7-23

14. Click the Next button.

15. One way Analysis Services provides scalability is by use of remote partitions, where the partitions reside in two or more Analysis Services instances. On the Processing and Storage Locations page, as shown in Figure 7 – 24 , you can specify where to store the partition. You can specify the remote Analysis Services instance on this page, but the data source to the remote Analysis Services instance should have been defined in this database. You can also change the storage location where you want the data for the partition to reside on any of the Analysis Services instances. Choose the default options as shown in Figure 7 – 24 and click Next.

16. In the final page of the Partition Wizard, select Design aggregations later, Process Now as shown in Figure 7 – 25 and click Finish.
17. In the Process Partition dialog, click OK to process the FactInternetSalesNew partition.
Figure 7-25

The partition will be processed and you can browse the cube data. The number of partitions for a specific cube typically increases over time. Users might not be browsing historical data with the same granularity as that of the recent data. For example, you might be more interested in comparing Sales data for the current month to that of the previous month rather than data from five years ago. However, you might want to compare year- over- year data for several years. By merging the partition data you can see some benefits during query performance. You learn about the considerations you should take into account to merge partitions in Chapter 14 .

There are two main requirements to merge partitions: The partitions should be of the same storage type, and they need to be on the same Analysis Services instance. Therefore if you have remote partitions, they can be merged together only if they are on the same Analysis Services instance. To merge partitions, do the following:

1. Launch the Merge Partition dialog by right – clicking the Partitions folder under the Fact Internet Sales measure group.
2. In the Merge Partition dialog shown in Figure 7 – 26 , select the Target partition that will contain the merged data and the list of partitions to merge data and click OK.
Figure 7-26

All the data from the source partitions will merge into the target partition, and the source partitions are deleted due to this operation. SSMS sends the following command to Analysis Services to merge the partitions:

< MergePartitions xmlns=”http://schemas.microsoft.com/analysisservices/ 2003/engine” >

< Sources >
< Source >
< DatabaseID > AnalysisServices2008Tutorial < /DatabaseID >
< CubeID > Adventure Works DW < /CubeID >
< MeasureGroupID > Fact Internet Sales < /MeasureGroupID >
< PartitionID > Fact Internet Sales < /PartitionID >

< /Source >
< /Sources >
< Target >

< DatabaseID > AnalysisServices2008Tutorial < /DatabaseID >
< CubeID > Adventure Works DW < /CubeID >
< MeasureGroupID > Fact Internet Sales < /MeasureGroupID >
< PartitionID > Fact Internet Sales New < /PartitionID >

< /Target >
< /MergePartitions >

Managing Assemblies

Assemblies, also called stored procedures, help you in performing specific tasks on the Analysis Services database or across the server. For example, Analysis Services has four assemblies installed that provide you with the functionality of calling Excel or VBA functions within your MDX queries. The System Assembly is used for operations such as Backup or Restore in retrieving information such as folders containing Analysis Services backup files, as well as supporting data mining algorithm requests. Analysis Services 2008 supports two types of assemblies: COM user- defined functions (UDFs) and .NET assemblies. COM UDFs are primarily supported for backwards compatibility with Analysis Services 2000. You learn about .NET and COM assemblies and how to build and deploy them in Chapter 11 . In this section you learn about managing assemblies on your Analysis Services instance.

Assemblies can be added only by Analysis Services administrators. You need to make sure your instance of Analysis Services is safe and secure irrespective of the operations done by the stored procedures. Security is always a concern, and you do not want any assemblies to bring down the server. Because hackers try to hack servers, most software products now are built to be secure by default. The administrator needs to enable certain components and options to make them available to users. By default, Analysis Services does not allow execution of stored procedures. The administrator first needs to enable the server property Feature\ComUdfEnabled to true (value of 1 in the Analysis Services config file) for enabling COM UDFs. This is accomplished using the Analysis Server Properties dialog.

The key to managing assemblies is to understand the nature of the assembly and setting appropriate properties while adding assemblies to your Analysis Services server. Figure 7 – 27 shows the dialog used to add assemblies to the server or to a specific database. This dialog can be launched by right – clicking the Assemblies folder under a specific database and choosing New Assembly.

 

Figure 7-27
Analysis Services supports two types of assemblies: COM and .NET CLR assemblies. Once you specify the type and name of the assemblies in the Register Assembly dialog, you need to specify the security information for these assemblies. Two parameters control the security of these stored procedures: Impersonation and Permissions. Permissions allow you to define the scope of access for the assembly, such as accessing the file system, accessing the network, and accessing unmanaged code. There are three different values for permissions. They are:

Safe: The most secure of the three permissions. When the Safe permission set is specified for an assembly, it means that the assembly is intended only for computation and the assembly cannot access any protected resource. It guarantees protection against information leaks and elevation attacks by malicious code.

External access: This permission value allows access to external resources by the assembly without compromising reliability, but does not offer any specific security guarantees. You can use this if you as the DBA trust the programmer’ s ability to write good code and if there is a need to access external resources such as data from an external file.

Unrestricted: This set value is primarily intended for people who have a very good understanding of programming on servers and need access to all resources. This permission set does not guarantee any code security or reliability. Unrestricted access should only be allowed to assemblies that have been written by users who absolutely need access to external resources and have a very good understanding of all security issues, such as denial of service attacks and information leakage, and are able to handle all these within the stored procedures. We recommend you use this option only when it is absolutely essential and you have full confidence in the programming abilities of the developer who has developed the assembly.

All COM DLLs will have the Permissions parameter set to Unrestricted. The Impersonation parameter allows you to specify the account under which the stored procedure will be executed. There are five different values for Impersonation:

Default: The Default value allows you to execute the stored procedure under a secure mode with the minimum privileges. If the assembly is of type COM the default value is “ Use the credentials of the current user. ” For a .NET assembly, the default value depends on the permission set defined. If the permission set is Safe, the Impersonation mode will be Impersonate Service Account, but if the permission set is External Access or Unrestricted, the Impersonation mode will be Impersonate Current User.

Anonymous: If you want the stored procedure to be executed as an anonymous user, you need to select Impersonate Anonymous. You will have limited access when the stored procedure is executed under this setting.

Use the credentials of the current user: This impersonation mode is typically used when you want the stored procedure to be executed with the user’ s credentials. This is a safe option to select. If the stored procedure accesses external resources and the current user executing the stored procedure does not have permissions, execution of the stored procedure will not cause any ill effects. A use of this impersonation mode is to define dynamic data security where the current user’ s credential is needed to access external resources.

Use the service account: If you choose to use the service account, whenever the stored procedure is executed it will be executed under the credentials of service startup account for Analysis Services. An example of a stored procedure that would need this impersonation mode is an AMO stored procedure that does management operations on the server.

Use a specific Windows username and password: If your business needs a stored procedure to always be executed in the context of a specific user, you need to choose this option. You need to specify a Windows account name and password for this impersonation mode. A typical example where you might use this option is when you access an external data source or web service to retrieve data with this account and utilize that value within the stored procedure for computation. If you choose this option, you will need to make sure you update the password on the account when there is a password change.

We recommend that COM assemblies use the credentials of the current user impersonation, whereas for .NET CLR assemblies you should use the appropriate impersonation mode based on your customer scenario. As an administrator of Analysis Services, you need to choose the impersonation and permission setting that suits your business needs and does not compromise the security of your Analysis Services instance.

When you register an assembly with a specific Analysis Services database or for the server using the Register Assembly dialog, AMO will be used to set up the correct properties. This, in turn, sends a Create command to the Analysis Services instance as shown here:

< Create AllowOverwrite=”true” xmlns=”http://schemas.microsoft.com/
analysisservices/2003/engine” >

< ParentObject >
< DatabaseID > AnalysisServices2008Tutorial < /DatabaseID >
< /ParentObject >
< ObjectDefinition >
< Assembly xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:ddl2=”http://schemas.microsoft.com/analysisservices/2003/ engine/2” xmlns:ddl2_2=”http://schemas.microsoft.com/analysisservices/ 2003/engine/2/2” xmlns:ddl100_100=”http://schemas.microsoft.com/ analysisservices/2008/engine/100/100” xsi:type=”ClrAssembly” > < ID > AmoSproc < /ID >
< Name > AmoSproc < /Name >
< Description / >
< ImpersonationInfo >
< ImpersonationMode > Default < /ImpersonationMode >
< /ImpersonationInfo >
< Files >
< File >
< Name > AmoSproc.dll < /Name >
< Type > Main < /Type >
< Data >
< Block > ————Content about the stored procedure—–< /Block >
< Block > ————Content about the stored procedure—–< /Block >
< Block > ————Content about the stored procedure—–< /Block >
< Block > ————Content about the stored procedure—–< /Block >
< /Data >
< /File >
< /Files >
< PermissionSet > Safe < /PermissionSet >
< /Assembly >
< /ObjectDefinition >
< /Create >
The information within the BLOCK tag is a large amount of text content, which for illustration purposes has been restricted to a single line. This text within the BLOCK tag is the assembly to be registered that will be stored within the Analysis Services instance. When queries use functions within the assembly, Analysis Services loads the assembly within the same process and executes the CLR assembly with appropriate parameter passing. The results from the assembly are appropriately passed back to Analysis Services for further evaluation of a query.

Backup and Restore

Backup is an operation that is part of every individual ’ s life. If you have an important document, you make a photocopy as a backup. Similarly, backup is an extremely critical operation for any data warehouse. There are several reasons why you should periodically back up your Analysis Services database. One reason is for disaster recovery; another is for auditing purposes. Irrespective of purpose, it is always a good idea to back up your database on a periodic basis. You can back up databases on your Analysis Services instance through SSMS. Follow these steps to back up the AnalysisServices2008Tutorial database:

1. Connect to the Analysis Services instance using SSMS.
2. Navigate to the database AnalysisServices2008Tutorial in the Object Explorer window.
3. Right – click the database and select Back Up.

You will see the Backup dialog shown in Figure 7 – 28 . By default the dialog chooses the database name as the backup name. By default the backup file will be created in the Backup folder of your Analysis Services installation. If you want the backup to be stored in a location on a different drive or directory, you first need to change the Analysis Services server property AllowedBrowsingFolder by adding the appropriate directory. You can then choose the folder by clicking Browse in the Backup Database dialog.

You have the option to encrypt the database and specify a password. You ’ ll need that password to restore the database. If you have remote partitions in the database, you have the option of specifying the backup location for each remote partition. Backup of these partitions is done on respective Analysis Services instances on that machine.

4. Disable the option to Encrypt the backup file.
5. Select the option “ Allow file overwrite ” to overwrite any existing backup files with the same name.
6. Choose the default backup file name and click OK.
The following command is sent to the Analysis Services instance by SSMS to back up the database AnalysisServices2008Tutorial:
< Backup xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine” > < Object >

< DatabaseID > AnalysisServices2008Tutorial < /DatabaseID >
< /Object >
< File > AnalysisServices2008Tutorial.abf < /File >
< AllowOverwrite > true < /AllowOverwrite >

< /Backup >
Figure 7-28

If you have specified a password, an Analysis Services 2008 backup file with the extension .abf will be created in the Backup folder. Backing up Analysis Services 2005 databases of sizes greater than 10GB used to take a long time. Analysis Services 2008 has made specific enhancements to backup performance intended to result in shorter backup times for databases of any size. Analysis Services 2008 also allows you to back up multiple databases at the same time. Through the SQL Server Management Studio you can launch the backup command from multiple databases and run backups in parallel. Alternatively, you can create a DDL that will execute backup of multiple databases within the same command.

Whenever you want to restore an Analysis Services database for which you have a backup, you can do so using the Restore Database dialog. Follow these steps to restore the AnalysisServices2008Tutorial backup:

1. In SSMS Object Explorer, right – click the AnalysisServices2008Tutorial and select Delete.
2. In the Delete Objects dialog shown in Figure 7 – 29 , click OK.

 

Figure 7-29

3. In the SSMS Object Explorer, right – click the Databases folder as shown in Figure 7 – 30 and select Restore.
Figure 7-30
4. In the Restore Database dialog (see Figure 7 – 31 ) click the Browse button next to Backup File.
Figure 7-31
5. In the Locate Database Files dialog, navigate to the Backup folder and select the AnalysisServices2008Tutorial.abf file as shown in Figure 7 – 32 and click OK. Figure 7-32
6. Type AnalysisServices2008Tutorial in the combo box next to Restore Database and click OK. SSMS now sends the following XMLA command to restore the database on your Analysis Services instance:
< Restore xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine” > < File > C:\Program Files\Microsoft SQL Server\MSAS10.MSSQLSERVER\OLAP\Backup\ AnalysisServices2008Tutorial.abf < /File >
< DatabaseName > AnalysisServices2008Tutorial < /DatabaseName >
< /Restore >

If you refresh the list of databases on your Analysis Services instance, you should now see the AnalysisServices2008Tutorial database in the SSMS Object Explorer. If a database with the same name and ID exists on your Analysis Services instance, you can restore the newer database by clicking the Allow Database Overwrite checkbox in the Restore dialog.

Once the database has been restored you can query the database. You can take a backup of a database from your test servers and restore it on your production server. In such a circumstance you might choose to skip the security information if the security defined on production servers is different from those on your test servers. In such a circumstance you would need to ensure you secure the database by defining the right security on production servers. In a circumstance where the backup was taken on your production server and you are restoring the database on an upgraded production machine we do expect users to restore the database with the security information.

Detach and Attach

Analysis Services provides you the functionality to detach and attach a complete database from an Analysis Services instance. These detach and attach commands differ from backup and restore commands. The attach operation allows you to mark a specific database read – only, and the database ’ s data files do not have to be stored in the default Data folder path of your Analysis Services instance. The read – only feature allows you to have a shared scalable architecture of Analysis Services for situations where you have a need to scale out the server to multiple users who are querying a specific Analysis Services database.

Follow these steps to detach the AnalysisServices2008Tutorial database:
1. In SSMS right – click the AnalysisServices2008Tutorial database and select Detach as shown in Figure 7 – 33 .
Figure 7-33
2. In the Detach Database dialog shown in Figure 7 – 34 , click OK. Figure 7-34
SSMS sends the following XMLA command to the Analysis Services instance:
< Detach xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine” > < Object >
< DatabaseID > AnalysisServices2008Tutorial < /DatabaseID >
< /Object >
< /Detach >

After receiving the detach command, Analysis Services first takes a write lock on the database to be detached. Taking a write lock means all existing DDL operations must complete before the detach command is started. The Analysis Services instance creates a detach log file that contains the version information, the key used for encrypting the database (if specified), and a few additional pieces of information about the database with the name AnalysisServices2008Tutorial.detach_log. This log file is created within the database folder as shown in Figure 7 – 35 . Analysis Services then commits and deletes the database. The entire database folder is now independent and can be copied and attached to another Analysis Services instance.

 

Figure 7-35

You can now attach the detached database to your Analysis Services instance. Follow these steps to attach the database in read – only mode:

1. Move the AnalysisServices2008Tutorial database folder that was detached from its original location under %Program Files%\Microsoft SQL Server\MSAS10.SQLServer\OLAP\ Data to %Program Files%\Microsoft SQL Server\MSAS10.SQLServer\OLAP.

2. If prompted by the operating system to provide administrative privileges to move the folder, provide the permissions.
3. In the SSMS Object Explorer, right – click the Databases folder and select Attach as shown in Figure 7 – 36 .
4. In the Attach Database dialog, specify the full path of the AnalysisServices2008Tutorial database as shown in Figure 7 – 37 .
Figure 7-37

5. Enable the checkbox next to Read – only and click OK.
6. Refresh the Databases folder in the SSMS Object Explorer.

You will now see that the AnalysisServices2008Tutorial database has been attached to the Analysis Services instance. Because you attached the database as read – only, you will notice that this database has been marked in gray in the SSMS Object Explorer as shown in Figure 7 – 38 . You can also confirm that the database is read – only by right – clicking the database and selecting Properties. You will see the Read – Write Mode property set to ReadOnly in the Database Properties dialog. The read – only database feature in Analysis Services helps in having a shared scalable database architecture where you can have a single database folder on a Storage Area Network (SAN) attached to multiple Analysis Services instances. You learn how this is helpful in query performance in Chapter 15 .

 

Figure 7-38

Synchronization

Synchronization sounds like a sophisticated, highly technical area of endeavor, but actually, it couldn ’ t be simpler; consider synchronization as just replication for Analysis Services 2008 databases. The name actually is suitable because it allows you to “ synchronize ” the Analysis Services database resident on one Analysis Services instance to the same database on another Analysis Services instance. Typically we expect Analysis Services DBAs to test the designed Analysis Services database in a test environment before they move them to their production servers. The DBAs often have to back up their database on test servers and restore them on production servers. However, through the synchronization feature in Analysis Services 2008 one can move well – tested databases from test servers to production servers with ease.

If you have an Analysis Services instance actively supporting a population of users, you want to be able to update the database they ’ re querying against without taking the system down to do so. Using the Synchronize Database Wizard, you can accomplish the database update seamlessly. The wizard will copy both data and metadata from your development and test machine (staging server) to the production server and automatically switch users to the newly copied data and metadata based on conditions defined on production server. To try this out, you need to have two instances of Analysis Services installed on another machine, or have a second instance of Analysis Services installed on your current machine. We recommend you install another instance called SS2008 on the same machine. Follow these steps to synchronize a database from the default instance to the new named instance SS2008:

1. Launch SSMS and connect to your default instance (localhost) and named instance (localhost\ SS2008) of Analysis Services as shown in Figure 7 – 39 .
2. Right – click the Databases folder of the named instance and select Synchronize as shown in Figure 7 – 39 .
3. If you see the welcome screen click Next.

4. In the Select Database to Synchronize page of the Synchronize Database Wizard, type the default instance localhost as the Source server and select the Source database AnalysisServices2008Tutorial as shown in Figure 7 – 40 and click Next. In the Specify Locations for Local Partitions page you can change locations of the partitions during synchronizations if the destination server allows it. In Figure 7 – 41 you can see that all the partitions of AnalysisServices2008Tutorial will be restored in the default location.

 

Figure 7-40

 

5. Click Next in the Specify Locations for Local Partitions page. On the Synchronization Options page you can specify the level of security information to copy when you synchronize as shown in Figure 7 – 42 . You can choose to copy all the roles and members, skip the membership information for the roles, or skip all the security information. Analysis Services 2008 has been designed to provide these options because customers might choose to synchronize databases from test servers to production servers. While synchronizing databases from test to production servers you can choose to keep all roles if the security permissions in the test environment are identical to the ones in the production environment. If the security permissions have been defined in such a way that they can be utilized in the production environment but the users in the production environment are different, you can use the Ignore all option. If you choose the Ignore all option you will need to define membership after synchronization.

6. Select the Skip membership option as shown in Figure 7 – 42 and click Next. In the Select Synchronization Method page you can choose to start the synchronization process immediately or script the command to a file and later send the command to the destination server using SSMS or through other programs.

Figure 7-42
7. Select the Synchronize now method as shown in Figure 7 – 43 and click Next. Figure 7-43
8. Review the synchronization options you have selected in the Completing the Wizard page and click Finish.
SSMS sends the following XMLA command to the Analysis Services SS2008 instance to synchronize the AnalysisServices2008Tutorial database from the SQLServer2008 instance:

< Synchronize xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine” >

< Source >
< ConnectionString > Provider=MSOLAP.4;Data Source=localhost\SQLServer2008; ConnectTo=10.0;Integrated Security=SSPI;
Initial Catalog=AnalysisServices2008Tutorial < /ConnectionString >

< Object >
< DatabaseID > AnalysisServices2008Tutorial < /DatabaseID >
< /Object >
< /Source >
< SynchronizeSecurity > SkipMembership < /SynchronizeSecurity >
< ApplyCompression > true < /ApplyCompression >
< /Synchronize >

< PropertyList xmlns=”urn:schemas-microsoft-com:xml-analysis” >
< LocaleIdentifier > 1033 < /LocaleIdentifier >
< /PropertyList >

You should be aware that the destination server contacts the source server for synchronization using the credentials of the service startup account and not the user who initiated the synchronize operation from SSMS. You do need to make sure the service startup account of the destination server has credentials to access the databases on the source server. The source server creates a backup of the objects that have changed in the source server, compresses them, and then sends them to the destination server. On the destination server these objects are first restored under a temporary name. If there are active queries being executed against the database on the destination server, the server waits for those queries to complete and then updates the objects. On the source server, the objects are locked during synchronization. Until the time the objects are sent to the destination server you cannot perform operations, such as processing, or other actions that will modify the objects.

9. You will see the progress of the synchronization operation in the Database Synchronization Progress dialog as shown in Figure 7 – 44 . You will see the progress percentage of the synchronization shown on this page, which gets updated periodically. After the synchronization completes, you will see the message in the page as shown in Figure 7 – 44 . Click Close.

Figure 7-44

You can use the synchronization wizard periodically to synchronize the database from source server to destination server. We typically expect the source server to be your test environment and the destination server to be the production environment. Synchronization is a pull model operation where the destination server pulls data from the source server. If a version of the database exists on the destination server, the source server only sends the data. Typically on the destination server you might have established new membership or security permissions. If you choose appropriate options to skip membership or ignore roles during synchronization, security permissions on the destination servers will not be changed.

There is an important security requirement you must implement to complete a s uccessful synchronization. The destination server’s service startup account must have access to the databases on the source server that are expected to be synchronized.

Managing Security

As an administrator, managing security is the most critical operation for the Analysis Services database. The phrase “ managing security ” can mean several things: managing the roles of Analysis Services databases, using the Analysis Services security features dimension and cell security, enabling and disabling features in Analysis Services, and setting up Analysis Services with appropriate firewall protection. The latter will ensure your Analysis Services instance can appropriately communicate via Internet and intranet.

Server and Database Roles

Roles are of vital importance to securing databases on your Analysis Services instance. You will deal with two kinds of roles when using the product: the server role and database roles. The server role is required for use by a login that performs administrative functions through the user interface (SSMS) or programmatically using AMO. The database roles are defined on an as – needed basis. You can provide read/write permissions to users for all objects in the database or as fine grain as certain cells in a cube. You learned about the server role and how to specify membership earlier in this chapter. In Chapters 9 and 22 you learn to define read/write access for dimensions and cubes in a database.

The Create Role dialog, accessed by right – clicking the Roles folder under a database node in Object Explorer, has the ability to provide full database access to a user as seen earlier in this chapter. In addition, Roles objects in a database help the DBA define fine – grain access to various database objects. The pages in the Create Role dialog are identical to the Role designer, which you learn more about in Chapter 22 . Please see Chapter 9 for more details on granting dimension and cube access to Analysis Services users. Chapter 22 provides extensive coverage of database role management through a scenario that shows how to restrict access to specific dimension members (dimension security) or cells in a cube (cell security).

To recap briefly, you as the database administrator can add roles to a specific database, add members to a role, and provide read, write, or read/write access to a role. In addition, you can specify the cell security and dimension security for this role using MDX expressions to limit access to specific cell data or dimension members. When a user is part of multiple roles, Analysis Services provides you access to data in a least restrictive manner. If a user has been restricted access to members of a dimension in one role and has been provided access to the same members in another role, the user will be able to access the members.

Enabling or Disabling Features

Managing database roles is one aspect of securing data in Analysis Services. You can add users to the server role so that you can have several administrators for your Analysis Services instance. Administrators can define appropriate levels of access to databases and objects within a database. However, there is another level of protection that Analysis Services 2008 provides. You can disable features that are not used by your users. One of the most common ways to protect your server from security attacks is to reduce your attack surface by running your server or application with minimum functionality. For example, you can turn off unused services of an operating system that listens for requests from users by default. As and when features are needed, they can be enabled by an administrator. Similarly, Analysis Services allows you to enable or disable certain features to prevent security attacks, thereby making your Analysis Services installation more secure. The following is the list of server properties that can be used to enable or disable certain features or services of your Analysis Services instance:

❑ Feature\ManagedCodeEnabled
❑ Feature\LinkInsideInstanceEnabled
❑ Feature\LinkToOtherInstanceEnabled
❑ Feature\LinkFromOtherInstanceEnabled
❑ Feature\COMUDFEnabled
❑ Feature\ConnStringEncryptionEnabled
❑ Datamining\AllowAdhocOpenRowSetQueries
❑ Security\RequireClientAuthentication

The properties LinkInsideInstanceEnabled, LinkToOtherInstanceEnabled, and
LinkFromOtherInstanceEnabled enable or disable linked objects (measure groups and dimensions) within the same instance and between instances of Analysis Services. The properties ManagedCodeEnabled and COMUDFEnabled allow/disallow loading assemblies to Analysis Services. You can allow or deny ad – hoc open row set data mining queries using the property Datamining\ AllowAdhocOpenRowSetQueries. The server property Security\RequireClientAuthentication allows or denies anonymous connections to Analysis Services. You can force clients to connect using encryption using the ConnStringEncryptionEnabled property. You can change these properties using the properties dialog for an Analysis Services instance.

Online Mode

As an administrator, you need to ensure that databases and their objects are kept up to date. Otherwise, your end users will query out – of – date information. After creating an OLAP database in SSMS you can use the Create Role dialog to create roles and provide permissions to specific users that allow them to be database administrators. To reduce confusion, deployed Analysis Services projects should be named the same as the database created by the server administrator. Once the database is created, the server or the database administrator can perform administrative operations using SSMS such as adding new roles, adding assemblies, or processing objects periodically. There might be certain design changes that you will have to make to the database based on additional requirements from the end users. In such a circumstance you would not be able to make the changes in the original project and deploy that project to the Analysis Services instance because the new objects added to the database will likely be deleted. Analysis Services 2008 provides you two ways to make additional changes. You can connect to the Analysis Services database on the server directly through BIDS and then make the changes in a mode called “ online mode. ” The second option is to import the database into your Analysis Services instance using the Import Analysis Services 2008 Database project (one of the Business Intelligence Project templates that can be used from BIDS), make changes to the database in project mode, and then re – deploy the project to the Analysis Services instance. We recommend the former because you can not only make changes directly on the server, which updates the objects immediately, but you can also perform processing tasks on objects. Instead of designing your Analysis Services database in project mode and then deploying it to the Analysis Services instance you can design the entire database by connecting to the database in online mode. Follow these steps to connect to an Analysis Services database in online mode using BIDS:

1. Launch BIDS from All Programs Microsoft SQL Server 2008 SQL Server Business Intelligence Development Studio.

2. To open an Analysis Services database in online mode select File Open Analysis Services Database as shown in Figure 7 – 45 . In the Connect To Database dialog you have the choice of opening an existing database or creating a new database on the Analysis Services instance. You need to be a server administrator to create a database on the Analysis Services instance.

 

Figure 7-45

3. Type the Analysis Services instance name and select a database to open in online mode as shown in Figure 7 – 46 and click OK.

 

BIDS connects to the Analysis Services instance and retrieves all the database objects. You will see all the objects of the database in the Solution Explorer similar to the project mode as shown in Figure 7 – 47 . Notice that with the database connected in online mode the Analysis Services instance name is indicated next to the database name in the Solution Explorer. All the operations that you were able to perform on the objects within a database in the project mode can be performed in the online mode. You do not have the deployment option for the database. Instead, you save all your changes directly to the server. We recommend that you explore making changes or adding new objects in the online mode and then saving the changes directly on the Analysis Services instance.

 

Summary

In this chapter you learned to administer SQL Server Analysis Services 2008 using SSMS. You learned the various management operations that can be accomplished on the Analysis Services databases. If you ’ re a database administrator experienced with administering Analysis Services 2000, this chapter may have been largely about getting used to the new management console SSMS. If you have been a database administrator with Analysis Services 2005, you will notice the most important administration feature is being able to detach and attach databases. You have seen that SSMS provides the ability to manage your Analysis Services instances effectively. In addition to learning the various management operations from SSMS, you also learned what XMLA commands are sent by SSMS to the Analysis Services instance, and you have a better understanding of the interactions between SSMS and an Analysis Services instance.

In this chapter you learned that for each administrative task there is a way to execute it through the user interface using SSMS or BIDS. You learn to perform Analysis Services management operations programmatically using the AMO (Analysis Services Management Object) object model in Chapter 13 .

You learned how useful backup and restore can be for auditing purposes — specifically by providing snapshots in time of cubes to auditors and analysts. And how security is configured for administrative versus user access to the server; this by using server and database roles, respectively. Finally, in this chapter you were exposed to properties. In the next chapter you learn some of the advanced topics in creating dimensions.

 

AdventureWorks DB Script

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [ddlDatabaseTriggerLog]
ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
BEGIN
    SET NOCOUNT ON

    DECLARE @data XML;
    DECLARE @schema sysname;
    DECLARE @object sysname;
    DECLARE @eventType sysname;

    SET @data = EVENTDATA();
    SET @eventType = @data.value(‘(/EVENT_INSTANCE/EventType)[1]‘, ‘sysname’);
    SET @schema = @data.value(‘(/EVENT_INSTANCE/SchemaName)[1]‘, ‘sysname’);
    SET @object = @data.value(‘(/EVENT_INSTANCE/ObjectName)[1]‘, ‘sysname’)

    IF @object IS NOT NULL
        PRINT ‘  ‘ + @eventType + ‘ – ‘ + @schema + ‘.’ + @object;
    ELSE
        PRINT ‘  ‘ + @eventType + ‘ – ‘ + @schema;

    IF @eventType IS NULL
        PRINT CONVERT(nvarchar(max), @data);

    INSERT [dbo].[DatabaseLog]
        (
        [PostTime],
        [DatabaseUser],
        [Event],
        [Schema],
        [Object],
        [TSQL],
        [XmlEvent]
        )
    VALUES
        (
        GETDATE(),
        CONVERT(sysname, CURRENT_USER),
        @eventType,
        CONVERT(sysname, @schema),
        CONVERT(sysname, @object),
        @data.value(‘(/EVENT_INSTANCE/TSQLCommand)[1]‘, ‘nvarchar(max)’),
        @data
        );
END;

GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
DISABLE TRIGGER [ddlDatabaseTriggerLog] ON DATABASE
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimDepartmentGroup]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimDepartmentGroup](
    [DepartmentGroupKey] [int] IDENTITY(1,1) NOT NULL,
    [ParentDepartmentGroupKey] [int] NULL,
    [DepartmentGroupName] [nvarchar](50) NULL,
 CONSTRAINT [PK_DimDepartmentGroup] PRIMARY KEY CLUSTERED
(
    [DepartmentGroupKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimProductCategory]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimProductCategory](
    [ProductCategoryKey] [int] IDENTITY(1,1) NOT NULL,
    [ProductCategoryAlternateKey] [int] NULL,
    [EnglishProductCategoryName] [nvarchar](50) NOT NULL,
    [SpanishProductCategoryName] [nvarchar](50) NOT NULL,
    [FrenchProductCategoryName] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_DimProductCategory_ProductCategoryKey] PRIMARY KEY CLUSTERED
(
    [ProductCategoryKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [AK_DimProductCategory_ProductCategoryAlternateKey] UNIQUE NONCLUSTERED
(
    [ProductCategoryAlternateKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimSalesReason]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimSalesReason](
    [SalesReasonKey] [int] IDENTITY(1,1) NOT NULL,
    [SalesReasonAlternateKey] [int] NOT NULL,
    [SalesReasonName] [nvarchar](50) NOT NULL,
    [SalesReasonReasonType] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_DimSalesReason_SalesReasonKey] PRIMARY KEY CLUSTERED
(
    [SalesReasonKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimSalesTerritory]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimSalesTerritory](
    [SalesTerritoryKey] [int] IDENTITY(1,1) NOT NULL,
    [SalesTerritoryAlternateKey] [int] NULL,
    [SalesTerritoryRegion] [nvarchar](50) NOT NULL,
    [SalesTerritoryCountry] [nvarchar](50) NOT NULL,
    [SalesTerritoryGroup] [nvarchar](50) NULL,
 CONSTRAINT [PK_DimSalesTerritory_SalesTerritoryKey] PRIMARY KEY CLUSTERED
(
    [SalesTerritoryKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [AK_DimSalesTerritory_SalesTerritoryAlternateKey] UNIQUE NONCLUSTERED
(
    [SalesTerritoryAlternateKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimScenario]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimScenario](
    [ScenarioKey] [int] IDENTITY(1,1) NOT NULL,
    [ScenarioName] [nvarchar](50) NULL,
 CONSTRAINT [PK_DimScenario] PRIMARY KEY CLUSTERED
(
    [ScenarioKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimTime]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimTime](
    [TimeKey] [int] IDENTITY(1,1) NOT NULL,
    [FullDateAlternateKey] [datetime] NULL,
    [DayNumberOfWeek] [tinyint] NULL,
    [EnglishDayNameOfWeek] [nvarchar](10) NULL,
    [SpanishDayNameOfWeek] [nvarchar](10) NULL,
    [FrenchDayNameOfWeek] [nvarchar](10) NULL,
    [DayNumberOfMonth] [tinyint] NULL,
    [DayNumberOfYear] [smallint] NULL,
    [WeekNumberOfYear] [tinyint] NULL,
    [EnglishMonthName] [nvarchar](10) NULL,
    [SpanishMonthName] [nvarchar](10) NULL,
    [FrenchMonthName] [nvarchar](10) NULL,
    [MonthNumberOfYear] [tinyint] NULL,
    [CalendarQuarter] [tinyint] NULL,
    [CalendarYear] [char](4) NULL,
    [CalendarSemester] [tinyint] NULL,
    [FiscalQuarter] [tinyint] NULL,
    [FiscalYear] [char](4) NULL,
    [FiscalSemester] [tinyint] NULL,
 CONSTRAINT [PK_DimTime_TimeKey] PRIMARY KEY CLUSTERED
(
    [TimeKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [AK_DimTime_FullDateAlternateKey] UNIQUE NONCLUSTERED
(
    [FullDateAlternateKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[ProspectiveBuyer]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[ProspectiveBuyer](
    [ProspectAlternateKey] [nvarchar](15) NULL,
    [FirstName] [nvarchar](50) NULL,
    [MiddleName] [nvarchar](50) NULL,
    [LastName] [nvarchar](50) NULL,
    [BirthDate] [datetime] NULL,
    [MaritalStatus] [nchar](1) NULL,
    [Gender] [nvarchar](1) NULL,
    [EmailAddress] [nvarchar](50) NULL,
    [YearlyIncome] [money] NULL,
    [TotalChildren] [tinyint] NULL,
    [NumberChildrenAtHome] [tinyint] NULL,
    [Education] [nvarchar](40) NULL,
    [Occupation] [nvarchar](100) NULL,
    [HouseOwnerFlag] [nchar](1) NULL,
    [NumberCarsOwned] [tinyint] NULL,
    [AddressLine1] [nvarchar](120) NULL,
    [AddressLine2] [nvarchar](120) NULL,
    [City] [nvarchar](30) NULL,
    [StateProvinceCode] [nvarchar](3) NULL,
    [PostalCode] [nvarchar](15) NULL,
    [Phone] [nvarchar](20) NULL,
    [Salutation] [nvarchar](8) NULL,
    [Unknown] [int] NULL
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimPromotion]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimPromotion](
    [PromotionKey] [int] IDENTITY(1,1) NOT NULL,
    [PromotionAlternateKey] [int] NULL,
    [EnglishPromotionName] [nvarchar](255) NULL,
    [SpanishPromotionName] [nvarchar](255) NULL,
    [FrenchPromotionName] [nvarchar](255) NULL,
    [DiscountPct] [float] NULL,
    [EnglishPromotionType] [nvarchar](50) NULL,
    [SpanishPromotionType] [nvarchar](50) NULL,
    [FrenchPromotionType] [nvarchar](50) NULL,
    [EnglishPromotionCategory] [nvarchar](50) NULL,
    [SpanishPromotionCategory] [nvarchar](50) NULL,
    [FrenchPromotionCategory] [nvarchar](50) NULL,
    [StartDate] [datetime] NOT NULL,
    [EndDate] [datetime] NULL,
    [MinQty] [int] NULL,
    [MaxQty] [int] NULL,
 CONSTRAINT [PK_DimPromotion_PromotionKey] PRIMARY KEY CLUSTERED
(
    [PromotionKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [AK_DimPromotion_PromotionAlternateKey] UNIQUE NONCLUSTERED
(
    [PromotionAlternateKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[udfMinimumDate]‘) AND type in (N’FN’, N’IF’, N’TF’, N’FS’, N’FT’))
BEGIN
execute dbo.sp_executesql @statement = N’
CREATE FUNCTION [dbo].[udfMinimumDate] (
    @x DATETIME,
    @y DATETIME
) RETURNS DATETIME
AS
BEGIN
    DECLARE @z DATETIME

    IF @x <= @y
        SET @z = @x
    ELSE
        SET @z = @y

    RETURN(@z)
END

END

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DatabaseLog]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DatabaseLog](
    [DatabaseLogID] [int] IDENTITY(1,1) NOT NULL,
    [PostTime] [datetime] NOT NULL,
    [DatabaseUser] [sysname] NOT NULL,
    [Event] [sysname] NOT NULL,
    [Schema] [sysname] NULL,
    [Object] [sysname] NULL,
    [TSQL] [nvarchar](max) NOT NULL,
    [XmlEvent] [xml] NOT NULL
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[AdventureWorksDWBuildVersion]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[AdventureWorksDWBuildVersion](
    [DBVersion] [nvarchar](50) NULL,
    [VersionDate] [datetime] NULL
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimAccount]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimAccount](
    [AccountKey] [int] IDENTITY(1,1) NOT NULL,
    [ParentAccountKey] [int] NULL,
    [AccountCodeAlternateKey] [int] NULL,
    [ParentAccountCodeAlternateKey] [int] NULL,
    [AccountDescription] [nvarchar](50) NULL,
    [AccountType] [nvarchar](50) NULL,
    [Operator] [nvarchar](50) NULL,
    [CustomMembers] [nvarchar](300) NULL,
    [ValueType] [nvarchar](50) NULL,
    [CustomMemberOptions] [nvarchar](200) NULL,
 CONSTRAINT [PK_DimAccount] PRIMARY KEY CLUSTERED
(
    [AccountKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimCurrency]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimCurrency](
    [CurrencyKey] [int] IDENTITY(1,1) NOT NULL,
    [CurrencyAlternateKey] [nchar](3) NOT NULL,
    [CurrencyName] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_DimCurrency_CurrencyKey] PRIMARY KEY CLUSTERED
(
    [CurrencyKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [AK_DimCurrency_CurrencyAlternateKey] UNIQUE NONCLUSTERED
(
    [CurrencyAlternateKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[FactInternetSales](
    [ProductKey] [int] NOT NULL,
    [OrderDateKey] [int] NOT NULL,
    [DueDateKey] [int] NOT NULL,
    [ShipDateKey] [int] NOT NULL,
    [CustomerKey] [int] NOT NULL,
    [PromotionKey] [int] NOT NULL,
    [CurrencyKey] [int] NOT NULL,
    [SalesTerritoryKey] [int] NOT NULL,
    [SalesOrderNumber] [nvarchar](20) NOT NULL,
    [SalesOrderLineNumber] [tinyint] NOT NULL,
    [RevisionNumber] [tinyint] NULL,
    [OrderQuantity] [smallint] NULL,
    [UnitPrice] [money] NULL,
    [ExtendedAmount] [money] NULL,
    [UnitPriceDiscountPct] [float] NULL,
    [DiscountAmount] [float] NULL,
    [ProductStandardCost] [money] NULL,
    [TotalProductCost] [money] NULL,
    [SalesAmount] [money] NULL,
    [TaxAmt] [money] NULL,
    [Freight] [money] NULL,
    [CarrierTrackingNumber] [nvarchar](25) NULL,
    [CustomerPONumber] [nvarchar](25) NULL,
 CONSTRAINT [AK_FactInternetSales_SalesOrderNumber_SalesOrderLineNumber] UNIQUE NONCLUSTERED
(
    [SalesOrderNumber] ASC,
    [SalesOrderLineNumber] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[FactFinance]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[FactFinance](
    [TimeKey] [int] NULL,
    [OrganizationKey] [int] NULL,
    [DepartmentGroupKey] [int] NULL,
    [ScenarioKey] [int] NULL,
    [AccountKey] [int] NULL,
    [Amount] [float] NULL
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[FactResellerSales](
    [ProductKey] [int] NOT NULL,
    [OrderDateKey] [int] NOT NULL,
    [DueDateKey] [int] NOT NULL,
    [ShipDateKey] [int] NOT NULL,
    [ResellerKey] [int] NOT NULL,
    [EmployeeKey] [int] NOT NULL,
    [PromotionKey] [int] NOT NULL,
    [CurrencyKey] [int] NOT NULL,
    [SalesTerritoryKey] [int] NOT NULL,
    [SalesOrderNumber] [nvarchar](20) NOT NULL,
    [SalesOrderLineNumber] [tinyint] NOT NULL,
    [RevisionNumber] [tinyint] NULL,
    [OrderQuantity] [smallint] NULL,
    [UnitPrice] [money] NULL,
    [ExtendedAmount] [money] NULL,
    [UnitPriceDiscountPct] [float] NULL,
    [DiscountAmount] [float] NULL,
    [ProductStandardCost] [money] NULL,
    [TotalProductCost] [money] NULL,
    [SalesAmount] [money] NULL,
    [TaxAmt] [money] NULL,
    [Freight] [money] NULL,
    [CarrierTrackingNumber] [nvarchar](25) NULL,
    [CustomerPONumber] [nvarchar](25) NULL,
 CONSTRAINT [AK_FactResellerSales_SalesOrderNumber_SalesOrderLineNumber] UNIQUE NONCLUSTERED
(
    [SalesOrderNumber] ASC,
    [SalesOrderLineNumber] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[FactSalesQuota]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[FactSalesQuota](
    [EmployeeKey] [int] NULL,
    [TimeKey] [int] NULL,
    [CalendarYear] [char](4) NULL,
    [CalendarQuarter] [tinyint] NULL,
    [SalesAmountQuota] [money] NULL
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimReseller]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimReseller](
    [ResellerKey] [int] IDENTITY(1,1) NOT NULL,
    [GeographyKey] [int] NULL,
    [ResellerAlternateKey] [nvarchar](15) NULL,
    [Phone] [nvarchar](25) NULL,
    [BusinessType] [varchar](20) NOT NULL,
    [ResellerName] [nvarchar](50) NOT NULL,
    [NumberEmployees] [int] NULL,
    [OrderFrequency] [char](1) NULL,
    [OrderMonth] [tinyint] NULL,
    [FirstOrderYear] [int] NULL,
    [LastOrderYear] [int] NULL,
    [ProductLine] [nvarchar](50) NULL,
    [AddressLine1] [nvarchar](60) NULL,
    [AddressLine2] [nvarchar](60) NULL,
    [AnnualSales] [money] NULL,
    [BankName] [nvarchar](50) NULL,
    [MinPaymentType] [tinyint] NULL,
    [MinPaymentAmount] [money] NULL,
    [AnnualRevenue] [money] NULL,
    [YearOpened] [int] NULL,
 CONSTRAINT [PK_DimReseller_ResellerKey] PRIMARY KEY CLUSTERED
(
    [ResellerKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [AK_DimReseller_ResellerAlternateKey] UNIQUE NONCLUSTERED
(
    [ResellerAlternateKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimCustomer]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimCustomer](
    [CustomerKey] [int] IDENTITY(1,1) NOT NULL,
    [GeographyKey] [int] NULL,
    [CustomerAlternateKey] [nvarchar](15) NOT NULL,
    [Title] [nvarchar](8) NULL,
    [FirstName] [nvarchar](50) NULL,
    [MiddleName] [nvarchar](50) NULL,
    [LastName] [nvarchar](50) NULL,
    [NameStyle] [bit] NULL,
    [BirthDate] [datetime] NULL,
    [MaritalStatus] [nchar](1) NULL,
    [Suffix] [nvarchar](10) NULL,
    [Gender] [nvarchar](1) NULL,
    [EmailAddress] [nvarchar](50) NULL,
    [YearlyIncome] [money] NULL,
    [TotalChildren] [tinyint] NULL,
    [NumberChildrenAtHome] [tinyint] NULL,
    [EnglishEducation] [nvarchar](40) NULL,
    [SpanishEducation] [nvarchar](40) NULL,
    [FrenchEducation] [nvarchar](40) NULL,
    [EnglishOccupation] [nvarchar](100) NULL,
    [SpanishOccupation] [nvarchar](100) NULL,
    [FrenchOccupation] [nvarchar](100) NULL,
    [HouseOwnerFlag] [nchar](1) NULL,
    [NumberCarsOwned] [tinyint] NULL,
    [AddressLine1] [nvarchar](120) NULL,
    [AddressLine2] [nvarchar](120) NULL,
    [Phone] [nvarchar](20) NULL,
    [DateFirstPurchase] [datetime] NULL,
    [CommuteDistance] [nvarchar](15) NULL,
 CONSTRAINT [PK_DimCustomer_CustomerKey] PRIMARY KEY CLUSTERED
(
    [CustomerKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [IX_DimCustomer_CustomerAlternateKey] UNIQUE NONCLUSTERED
(
    [CustomerAlternateKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimProductSubcategory]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimProductSubcategory](
    [ProductSubcategoryKey] [int] IDENTITY(1,1) NOT NULL,
    [ProductSubcategoryAlternateKey] [int] NULL,
    [EnglishProductSubcategoryName] [nvarchar](50) NOT NULL,
    [SpanishProductSubcategoryName] [nvarchar](50) NOT NULL,
    [FrenchProductSubcategoryName] [nvarchar](50) NOT NULL,
    [ProductCategoryKey] [int] NULL,
 CONSTRAINT [PK_DimProductSubcategory_ProductSubcategoryKey] PRIMARY KEY CLUSTERED
(
    [ProductSubcategoryKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [AK_DimProductSubcategory_ProductSubcategoryAlternateKey] UNIQUE NONCLUSTERED
(
    [ProductSubcategoryAlternateKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimProduct]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimProduct](
    [ProductKey] [int] IDENTITY(1,1) NOT NULL,
    [ProductAlternateKey] [nvarchar](25) NULL,
    [ProductSubcategoryKey] [int] NULL,
    [WeightUnitMeasureCode] [nchar](3) NULL,
    [SizeUnitMeasureCode] [nchar](3) NULL,
    [EnglishProductName] [nvarchar](50) NOT NULL,
    [SpanishProductName] [nvarchar](50) NOT NULL,
    [FrenchProductName] [nvarchar](50) NOT NULL,
    [StandardCost] [money] NULL,
    [FinishedGoodsFlag] [bit] NOT NULL,
    [Color] [nvarchar](15) NOT NULL,
    [SafetyStockLevel] [smallint] NULL,
    [ReorderPoint] [smallint] NULL,
    [ListPrice] [money] NULL,
    [Size] [nvarchar](50) NULL,
    [SizeRange] [nvarchar](50) NULL,
    [Weight] [float] NULL,
    [DaysToManufacture] [int] NULL,
    [ProductLine] [nchar](2) NULL,
    [DealerPrice] [money] NULL,
    [Class] [nchar](2) NULL,
    [Style] [nchar](2) NULL,
    [ModelName] [nvarchar](50) NULL,
    [LargePhoto] [varbinary](max) NULL,
    [EnglishDescription] [nvarchar](400) NULL,
    [FrenchDescription] [nvarchar](400) NULL,
    [ChineseDescription] [nvarchar](400) NULL,
    [ArabicDescription] [nvarchar](400) NULL,
    [HebrewDescription] [nvarchar](400) NULL,
    [ThaiDescription] [nvarchar](400) NULL,
    [StartDate] [datetime] NULL,
    [EndDate] [datetime] NULL,
    [Status] [nvarchar](7) NULL,
 CONSTRAINT [PK_DimProduct_ProductKey] PRIMARY KEY CLUSTERED
(
    [ProductKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [AK_DimProduct_ProductAlternateKey_StartDate] UNIQUE NONCLUSTERED
(
    [ProductAlternateKey] ASC,
    [StartDate] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[FactInternetSalesReason]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[FactInternetSalesReason](
    [SalesOrderNumber] [nvarchar](20) NOT NULL,
    [SalesOrderLineNumber] [tinyint] NOT NULL,
    [SalesReasonKey] [int] NOT NULL,
 CONSTRAINT [AK_FactInternetSalesReason_SalesOrderNumber_SalesOrderLineNumber_SalesReasonKey] UNIQUE NONCLUSTERED
(
    [SalesOrderNumber] ASC,
    [SalesOrderLineNumber] ASC,
    [SalesReasonKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimEmployee]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimEmployee](
    [EmployeeKey] [int] IDENTITY(1,1) NOT NULL,
    [ParentEmployeeKey] [int] NULL,
    [EmployeeNationalIDAlternateKey] [nvarchar](15) NULL,
    [ParentEmployeeNationalIDAlternateKey] [nvarchar](15) NULL,
    [SalesTerritoryKey] [int] NULL,
    [FirstName] [nvarchar](50) NOT NULL,
    [LastName] [nvarchar](50) NOT NULL,
    [MiddleName] [nvarchar](50) NULL,
    [NameStyle] [bit] NOT NULL,
    [Title] [nvarchar](50) NULL,
    [HireDate] [datetime] NULL,
    [BirthDate] [datetime] NULL,
    [LoginID] [nvarchar](256) NULL,
    [EmailAddress] [nvarchar](50) NULL,
    [Phone] [nvarchar](25) NULL,
    [MaritalStatus] [nchar](1) NULL,
    [EmergencyContactName] [nvarchar](50) NULL,
    [EmergencyContactPhone] [nvarchar](25) NULL,
    [SalariedFlag] [bit] NULL,
    [Gender] [nchar](1) NULL,
    [PayFrequency] [tinyint] NULL,
    [BaseRate] [money] NULL,
    [VacationHours] [smallint] NULL,
    [SickLeaveHours] [smallint] NULL,
    [CurrentFlag] [bit] NOT NULL,
    [SalesPersonFlag] [bit] NOT NULL,
    [DepartmentName] [nvarchar](50) NULL,
    [StartDate] [datetime] NULL,
    [EndDate] [datetime] NULL,
    [Status] [nvarchar](50) NULL,
 CONSTRAINT [PK_DimEmployee_EmployeeKey] PRIMARY KEY CLUSTERED
(
    [EmployeeKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimGeography]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimGeography](
    [GeographyKey] [int] IDENTITY(1,1) NOT NULL,
    [City] [nvarchar](30) NULL,
    [StateProvinceCode] [nvarchar](3) NULL,
    [StateProvinceName] [nvarchar](50) NULL,
    [CountryRegionCode] [nvarchar](3) NULL,
    [EnglishCountryRegionName] [nvarchar](50) NULL,
    [SpanishCountryRegionName] [nvarchar](50) NULL,
    [FrenchCountryRegionName] [nvarchar](50) NULL,
    [PostalCode] [nvarchar](15) NULL,
    [SalesTerritoryKey] [int] NULL,
 CONSTRAINT [PK_DimGeography_GeographyKey] PRIMARY KEY CLUSTERED
(
    [GeographyKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[FactCurrencyRate]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[FactCurrencyRate](
    [CurrencyKey] [int] NOT NULL,
    [TimeKey] [int] NOT NULL,
    [AverageRate] [float] NOT NULL,
    [EndOfDayRate] [float] NOT NULL
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[DimOrganization]‘) AND type in (N’U’))
BEGIN
CREATE TABLE [dbo].[DimOrganization](
    [OrganizationKey] [int] IDENTITY(1,1) NOT NULL,
    [ParentOrganizationKey] [int] NULL,
    [PercentageOfOwnership] [nvarchar](16) NULL,
    [OrganizationName] [nvarchar](50) NULL,
    [CurrencyKey] [int] NULL,
 CONSTRAINT [PK_DimOrganization] PRIMARY KEY CLUSTERED
(
    [OrganizationKey] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N’[dbo].[vDMPrep]‘))
EXEC dbo.sp_executesql @statement = N’
– vDMPrep will be used as a data source by the other data mining views.  
– Uses DW data at customer, product, day, etc. granularity and
– gets region, model, year, month, etc.
CREATE VIEW [dbo].[vDMPrep]
AS
    SELECT
        pc.[EnglishProductCategoryName]
        ,Coalesce(p.[ModelName], p.[EnglishProductName]) AS [Model]
        ,c.[CustomerKey]
        ,s.[SalesTerritoryGroup] AS [Region]
        ,CASE
            WHEN Month(GetDate()) < Month(c.[BirthDate])
                THEN DateDiff(yy,c.[BirthDate],GetDate()) – 1
            WHEN Month(GetDate()) = Month(c.[BirthDate])
            AND Day(GetDate()) < Day(c.[BirthDate])
                THEN DateDiff(yy,c.[BirthDate],GetDate()) – 1
            ELSE DateDiff(yy,c.[BirthDate],GetDate())
        END AS [Age]
        ,CASE
            WHEN c.[YearlyIncome] < 40000 THEN ”Low”
            WHEN c.[YearlyIncome] > 60000 THEN ”High”
            ELSE ”Moderate”
        END AS [IncomeGroup]
        ,t.[CalendarYear]
        ,t.[FiscalYear]
        ,t.[MonthNumberOfYear] AS [Month]
        ,f.[SalesOrderNumber] AS [OrderNumber]
        ,f.SalesOrderLineNumber AS LineNumber
        ,f.OrderQuantity AS Quantity
        ,f.ExtendedAmount AS Amount  
    FROM
        [dbo].[FactInternetSales] f
    INNER JOIN [dbo].[DimTime] t
        ON f.[OrderDateKey] = t.[TimeKey]
    INNER JOIN [dbo].[DimProduct] p
        ON f.[ProductKey] = p.[ProductKey]
    INNER JOIN [dbo].[DimProductSubcategory] psc
        ON p.[ProductSubcategoryKey] = psc.[ProductSubcategoryKey]
    INNER JOIN [dbo].[DimProductCategory] pc
        ON psc.[ProductCategoryKey] = pc.[ProductCategoryKey]
    INNER JOIN [dbo].[DimCustomer] c
        ON f.[CustomerKey] = c.[CustomerKey]
    INNER JOIN [dbo].[DimGeography] g
        ON c.[GeographyKey] = g.[GeographyKey]
    INNER JOIN [dbo].[DimSalesTerritory] s
        ON g.[SalesTerritoryKey] = s.[SalesTerritoryKey]
;

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N’[dbo].[vTargetMail]‘))
EXEC dbo.sp_executesql @statement = N’
– vTargetMail supports targeted mailing data model
– Uses vDMPrep to determine if a customer buys a bike and joins to DimCustomer
CREATE VIEW [dbo].[vTargetMail]
AS
    SELECT
        c.[CustomerKey],
        c.[GeographyKey],
        c.[CustomerAlternateKey],
        c.[Title],
        c.[FirstName],
        c.[MiddleName],
        c.[LastName],
        c.[NameStyle],
        c.[BirthDate],
        c.[MaritalStatus],
        c.[Suffix],
        c.[Gender],
        c.[EmailAddress],
        c.[YearlyIncome],
        c.[TotalChildren],
        c.[NumberChildrenAtHome],
        c.[EnglishEducation],
        c.[SpanishEducation],
        c.[FrenchEducation],
        c.[EnglishOccupation],
        c.[SpanishOccupation],
        c.[FrenchOccupation],
        c.[HouseOwnerFlag],
        c.[NumberCarsOwned],
        c.[AddressLine1],
        c.[AddressLine2],
        c.[Phone],
        c.[DateFirstPurchase],
        c.[CommuteDistance],
        x.[Region],
        x.[Age],
        CASE x.[Bikes]
            WHEN 0 THEN 0
            ELSE 1
        END AS [BikeBuyer]
    FROM
        [dbo].[DimCustomer] c INNER JOIN (
            SELECT
                [CustomerKey]
                ,[Region]
                ,[Age]
                ,Sum(
                    CASE [EnglishProductCategoryName]
                        WHEN ”Bikes” THEN 1
                        ELSE 0
                    END) AS [Bikes]
            FROM
                [dbo].[vDMPrep]
            GROUP BY
                [CustomerKey]
                ,[Region]
                ,[Age]
            ) AS [x]
        ON c.[CustomerKey] = x.[CustomerKey]
;

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N’[dbo].[vAssocSeqOrders]‘))
EXEC dbo.sp_executesql @statement = N’
– vAssocSeqOrders supports assocation and sequence clustering data mmining models.
–      – Limits data to FY2004.
–      – Creates order case table and line item nested table.
CREATE VIEW [dbo].[vAssocSeqOrders]
AS
    SELECT DISTINCT
        [OrderNumber]
        ,[CustomerKey]
        ,[Region]
        ,[IncomeGroup]
    FROM
        [dbo].[vDMPrep]
    WHERE
        [FiscalYear] = ”2004”

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N’[dbo].[vAssocSeqLineItems]‘))
EXEC dbo.sp_executesql @statement = N’
CREATE VIEW [dbo].[vAssocSeqLineItems]
AS
    SELECT
        OrderNumber
        ,LineNumber
        ,Model
    FROM
        [dbo].[vDMPrep]
    WHERE
        FiscalYear = ”2004”
;

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N’[dbo].[vTimeSeries]‘))
EXEC dbo.sp_executesql @statement = N’
– vTimeSeries view supports time series data mining model.
–      – Replaces predecessor model with successor model.
–      – Abbreviates model names to improve view in mining model viewer
–        concatenates model and region so that table only has one input.
CREATE VIEW [dbo].[vTimeSeries]
AS
    SELECT
        CASE [Model]
            WHEN ”Mountain-100” THEN ”M200”
            WHEN ”Road-150” THEN ”R250”
            WHEN ”Road-650” THEN ”R750”
            WHEN ”Touring-1000” THEN ”T1000”
            ELSE Left([Model], 1) + Right([Model], 3)
        END + ” ” + [Region] AS [ModelRegion]
        ,(Convert(Integer, [CalendarYear]) * 100) + Convert(Integer, [Month]) AS [TimeIndex]
        ,Sum([Quantity]) AS [Quantity]
        ,Sum([Amount]) AS [Amount]
    FROM
        [dbo].[vDMPrep]
    WHERE
        [Model] IN (”Mountain-100”, ”Mountain-200”, ”Road-150”, ”Road-250”,
            ”Road-650”, ”Road-750”, ”Touring-1000”)
    GROUP BY
        CASE [Model]
            WHEN ”Mountain-100” THEN ”M200”
            WHEN ”Road-150” THEN ”R250”
            WHEN ”Road-650” THEN ”R750”
            WHEN ”Touring-1000” THEN ”T1000”
            ELSE Left(Model,1) + Right(Model,3)
        END + ” ” + [Region],
        (Convert(Integer, [CalendarYear]) * 100) + Convert(Integer, [Month])
;

GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimDepartmentGroup_DimDepartmentGroup]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimDepartmentGroup]‘))
ALTER TABLE [dbo].[DimDepartmentGroup]  WITH CHECK ADD  CONSTRAINT [FK_DimDepartmentGroup_DimDepartmentGroup] FOREIGN KEY([ParentDepartmentGroupKey])
REFERENCES [dbo].[DimDepartmentGroup] ([DepartmentGroupKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimAccount_DimAccount]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimAccount]‘))
ALTER TABLE [dbo].[DimAccount]  WITH CHECK ADD  CONSTRAINT [FK_DimAccount_DimAccount] FOREIGN KEY([ParentAccountKey])
REFERENCES [dbo].[DimAccount] ([AccountKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSales_DimCurrency]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘))
ALTER TABLE [dbo].[FactInternetSales]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSales_DimCurrency] FOREIGN KEY([CurrencyKey])
REFERENCES [dbo].[DimCurrency] ([CurrencyKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSales_DimCustomer]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘))
ALTER TABLE [dbo].[FactInternetSales]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSales_DimCustomer] FOREIGN KEY([CustomerKey])
REFERENCES [dbo].[DimCustomer] ([CustomerKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSales_DimProduct]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘))
ALTER TABLE [dbo].[FactInternetSales]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSales_DimProduct] FOREIGN KEY([ProductKey])
REFERENCES [dbo].[DimProduct] ([ProductKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSales_DimPromotion]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘))
ALTER TABLE [dbo].[FactInternetSales]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSales_DimPromotion] FOREIGN KEY([PromotionKey])
REFERENCES [dbo].[DimPromotion] ([PromotionKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSales_DimSalesTerritory]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘))
ALTER TABLE [dbo].[FactInternetSales]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSales_DimSalesTerritory] FOREIGN KEY([SalesTerritoryKey])
REFERENCES [dbo].[DimSalesTerritory] ([SalesTerritoryKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSales_DimTime]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘))
ALTER TABLE [dbo].[FactInternetSales]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSales_DimTime] FOREIGN KEY([OrderDateKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSales_DimTime1]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘))
ALTER TABLE [dbo].[FactInternetSales]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSales_DimTime1] FOREIGN KEY([DueDateKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSales_DimTime2]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSales]‘))
ALTER TABLE [dbo].[FactInternetSales]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSales_DimTime2] FOREIGN KEY([ShipDateKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactFinance_DimAccount]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactFinance]‘))
ALTER TABLE [dbo].[FactFinance]  WITH CHECK ADD  CONSTRAINT [FK_FactFinance_DimAccount] FOREIGN KEY([AccountKey])
REFERENCES [dbo].[DimAccount] ([AccountKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactFinance_DimDepartmentGroup]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactFinance]‘))
ALTER TABLE [dbo].[FactFinance]  WITH CHECK ADD  CONSTRAINT [FK_FactFinance_DimDepartmentGroup] FOREIGN KEY([DepartmentGroupKey])
REFERENCES [dbo].[DimDepartmentGroup] ([DepartmentGroupKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactFinance_DimOrganization]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactFinance]‘))
ALTER TABLE [dbo].[FactFinance]  WITH CHECK ADD  CONSTRAINT [FK_FactFinance_DimOrganization] FOREIGN KEY([OrganizationKey])
REFERENCES [dbo].[DimOrganization] ([OrganizationKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactFinance_DimScenario]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactFinance]‘))
ALTER TABLE [dbo].[FactFinance]  WITH CHECK ADD  CONSTRAINT [FK_FactFinance_DimScenario] FOREIGN KEY([ScenarioKey])
REFERENCES [dbo].[DimScenario] ([ScenarioKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactFinance_DimTime]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactFinance]‘))
ALTER TABLE [dbo].[FactFinance]  WITH CHECK ADD  CONSTRAINT [FK_FactFinance_DimTime] FOREIGN KEY([TimeKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimCurrency]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimCurrency] FOREIGN KEY([CurrencyKey])
REFERENCES [dbo].[DimCurrency] ([CurrencyKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimEmployee]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimEmployee] FOREIGN KEY([EmployeeKey])
REFERENCES [dbo].[DimEmployee] ([EmployeeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimProduct]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimProduct] FOREIGN KEY([ProductKey])
REFERENCES [dbo].[DimProduct] ([ProductKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimPromotion]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimPromotion] FOREIGN KEY([PromotionKey])
REFERENCES [dbo].[DimPromotion] ([PromotionKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimReseller]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimReseller] FOREIGN KEY([ResellerKey])
REFERENCES [dbo].[DimReseller] ([ResellerKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimSalesTerritory]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimSalesTerritory] FOREIGN KEY([SalesTerritoryKey])
REFERENCES [dbo].[DimSalesTerritory] ([SalesTerritoryKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimTime]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimTime] FOREIGN KEY([OrderDateKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimTime1]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimTime1] FOREIGN KEY([DueDateKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactResellerSales_DimTime2]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactResellerSales]‘))
ALTER TABLE [dbo].[FactResellerSales]  WITH CHECK ADD  CONSTRAINT [FK_FactResellerSales_DimTime2] FOREIGN KEY([ShipDateKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactSalesQuota_DimEmployee]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactSalesQuota]‘))
ALTER TABLE [dbo].[FactSalesQuota]  WITH CHECK ADD  CONSTRAINT [FK_FactSalesQuota_DimEmployee] FOREIGN KEY([EmployeeKey])
REFERENCES [dbo].[DimEmployee] ([EmployeeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactSalesQuota_DimTime]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactSalesQuota]‘))
ALTER TABLE [dbo].[FactSalesQuota]  WITH CHECK ADD  CONSTRAINT [FK_FactSalesQuota_DimTime] FOREIGN KEY([TimeKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimReseller_DimGeography]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimReseller]‘))
ALTER TABLE [dbo].[DimReseller]  WITH CHECK ADD  CONSTRAINT [FK_DimReseller_DimGeography] FOREIGN KEY([GeographyKey])
REFERENCES [dbo].[DimGeography] ([GeographyKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimCustomer_DimGeography]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimCustomer]‘))
ALTER TABLE [dbo].[DimCustomer]  WITH CHECK ADD  CONSTRAINT [FK_DimCustomer_DimGeography] FOREIGN KEY([GeographyKey])
REFERENCES [dbo].[DimGeography] ([GeographyKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimProductSubcategory_DimProductCategory]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimProductSubcategory]‘))
ALTER TABLE [dbo].[DimProductSubcategory]  WITH CHECK ADD  CONSTRAINT [FK_DimProductSubcategory_DimProductCategory] FOREIGN KEY([ProductCategoryKey])
REFERENCES [dbo].[DimProductCategory] ([ProductCategoryKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimProduct_DimProductSubcategory]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimProduct]‘))
ALTER TABLE [dbo].[DimProduct]  WITH CHECK ADD  CONSTRAINT [FK_DimProduct_DimProductSubcategory] FOREIGN KEY([ProductSubcategoryKey])
REFERENCES [dbo].[DimProductSubcategory] ([ProductSubcategoryKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSalesReason_DimSalesReason]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSalesReason]‘))
ALTER TABLE [dbo].[FactInternetSalesReason]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSalesReason_DimSalesReason] FOREIGN KEY([SalesReasonKey])
REFERENCES [dbo].[DimSalesReason] ([SalesReasonKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactInternetSalesReason_FactInternetSales]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactInternetSalesReason]‘))
ALTER TABLE [dbo].[FactInternetSalesReason]  WITH CHECK ADD  CONSTRAINT [FK_FactInternetSalesReason_FactInternetSales] FOREIGN KEY([SalesOrderNumber], [SalesOrderLineNumber])
REFERENCES [dbo].[FactInternetSales] ([SalesOrderNumber], [SalesOrderLineNumber])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimEmployee_DimEmployee]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimEmployee]‘))
ALTER TABLE [dbo].[DimEmployee]  WITH CHECK ADD  CONSTRAINT [FK_DimEmployee_DimEmployee] FOREIGN KEY([ParentEmployeeKey])
REFERENCES [dbo].[DimEmployee] ([EmployeeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimEmployee_DimSalesTerritory]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimEmployee]‘))
ALTER TABLE [dbo].[DimEmployee]  WITH CHECK ADD  CONSTRAINT [FK_DimEmployee_DimSalesTerritory] FOREIGN KEY([SalesTerritoryKey])
REFERENCES [dbo].[DimSalesTerritory] ([SalesTerritoryKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimGeography_DimSalesTerritory]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimGeography]‘))
ALTER TABLE [dbo].[DimGeography]  WITH CHECK ADD  CONSTRAINT [FK_DimGeography_DimSalesTerritory] FOREIGN KEY([SalesTerritoryKey])
REFERENCES [dbo].[DimSalesTerritory] ([SalesTerritoryKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactCurrencyRate_DimCurrency]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactCurrencyRate]‘))
ALTER TABLE [dbo].[FactCurrencyRate]  WITH CHECK ADD  CONSTRAINT [FK_FactCurrencyRate_DimCurrency] FOREIGN KEY([CurrencyKey])
REFERENCES [dbo].[DimCurrency] ([CurrencyKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_FactCurrencyRate_DimTime]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[FactCurrencyRate]‘))
ALTER TABLE [dbo].[FactCurrencyRate]  WITH CHECK ADD  CONSTRAINT [FK_FactCurrencyRate_DimTime] FOREIGN KEY([TimeKey])
REFERENCES [dbo].[DimTime] ([TimeKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimOrganization_DimCurrency]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimOrganization]‘))
ALTER TABLE [dbo].[DimOrganization]  WITH CHECK ADD  CONSTRAINT [FK_DimOrganization_DimCurrency] FOREIGN KEY([CurrencyKey])
REFERENCES [dbo].[DimCurrency] ([CurrencyKey])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N’[dbo].[FK_DimOrganization_DimOrganization]‘) AND parent_object_id = OBJECT_ID(N’[dbo].[DimOrganization]‘))
ALTER TABLE [dbo].[DimOrganization]  WITH CHECK ADD  CONSTRAINT [FK_DimOrganization_DimOrganization] FOREIGN KEY([ParentOrganizationKey])
REFERENCES [dbo].[DimOrganization] ([OrganizationKey])

CUBE Design

Cube Design

In Chapter 5 you learned to create dimensions using the Dimension Wizard and to refine and enhance dimensions using the Dimension Designer. Dimensions eventually need to be part of your cube for you to analyze data across various dimension members. In previous chapters, you read about the Unified Dimensional Model (UDM). Now, prepare yourself for significantly more detail because all the fact and dimension tables you see when you ’ re looking at a DSV in the Cube Designer comprise the UDM. Yes, the UDM is more than a multiple data – source cube on steroids, but to make it as clear as possible, think of the UDM as a cube for now. In this chapter you learn how to create cubes using the Cube Wizard and enhance the cube using the Cube Designer. You learn to add calculations to your cube that facilitate effective data analysis followed by analyzing the cube data itself in the Cube Designer.

The Unified Dimensional Model

To generate profits for a business, key strategic decisions need to be made based on likely factors such as having the right business model, targeting the right consumer group, pricing the product correctly, and marketing through optimal channels. To make the right decisions and achieve targeted growth you need to analyze data. The data can be past sales, expected sales, or even information from competitors. The phrase “ Knowledge is power ” is very fitting here because in the world of business, analyzing and comparing current sales against the expected sales helps executives make decisions directly aligned with the goals of the company. Such sales information is typically stored in a distributed fashion and must be collected from various sources. Executives making the business decisions typically do not have the capability to access the raw sales data spread across various locations and subsequently optimize it for their use. The decision – makers typically rely on the data that has already been aggregated into a form that is easy to understand and that facilitates the decision – making process. Presenting aggregated data to the decision makers quickly is a key challenge for business intelligence providers. Analysis Services 2008 enables you to design a model that bridges the gap between the raw data and the information content that can be used for making business decisions. This model is called the Unified Dimensional Model (UDM).

The UDM is central to your Analysis Services database architecture. UDM is your friend because it helps you narrow the gap between end users and the data they need. Analysis Services provides you with features that help you design a model that will serve the needs of end users. UDM, as the name suggests, provides you with a way to bring data from multiple heterogeneous sources into a single model. The UDM buffers you from the difficulties of managing the integration of various data sources so you can build your model easily. It provides you with the best of the OLAP and relational worlds, exposing rich data and metadata for exploration and analysis.

Figur e 6 – 1 shows the architecture of the Unified Dimensional Model that is implemented in Analysis Services 2008. As shown in the figure, the UDM helps you to integrate data from various data sources such as Oracle, SQL Server, DB2, Teradata, and flat files into a single model that merges the underlying schemas into a single schema. The end users do not necessarily have to view the entire schema of the UDM. Instead, they can view sections of the UDM relevant to their needs through the functionality provided by Analysis Services 2008 called perspectives.

Analysis Services 2008
Oracle
Data Store Administrator SQL Server Management Studio
SQL Server Data Store
Business Analyst OLAP Client Tool

Unified
Dimensional
Model

DB2
Data Store
Report Analyst Reporting Tools
Teradata Data Store
OLAP Browser OLAP Client Tool
Automatic MOLAP Cache

Figure 6 – 1 In the OLAP world, data analyzed by end users is often historical data that might be a few days, months, or even years old. However, the responses to the OLAP queries are typically returned within a few seconds. In the relational world the end users have instant access to the raw data but the responses to queries can take much longer, on the order of minutes. As mentioned earlier, the UDM merges the best of both the OLAP and relational worlds and provides the end users with real – time data with the query performance of the OLAP world. The UDM is able to provide the query performance of the OLAP world with the help of a feature in Analysis Services 2008 that creates a cache of the relational data source that also aggregates the data into an Analysis Services instance. During the time the cache is being built, the UDM retrieves the data directly from the data sources. As soon as the cache is available, the results are retrieved from the cache in response to relevant queries. Whenever there is a change in the underlying data source, the UDM receives a notification and appropriate updates are made to the cache based on the settings defined for cache updates.

The UDM also provides rich, high – end analytic support through which complex business calculations can be exploited. Such complex calculations can be extremely difficult to formulate in the relational world at the data – source level. Even if such calculations are defined on the relational data source, responses from OLAP – style queries against the relational data source might be really slow compared to responses from Analysis Services.

UDM natively interfaces to end – user clients through the XML for Analysis (XMLA) standard, which allows client tools to retrieve data from Analysis Services. Client tools such as Office Web Components (OWC) and Excel pivot tables allow the end users to create ad – hoc queries for data analysis. In addition, the UDM supports rich analytic features such as Key Performance Indicators (KPIs), Actions, and Translations that help surface the status of your business at any given time so that appropriate actions can be taken.

The UDM provides an efficient interface for detail – level reporting through dimension attributes that are common in the relational world. In addition to that, the UDM is easily understandable by a relational user. The ability to transform the UDM results into views that are helpful to end users and the ability to perform ad – hoc queries on data from high – level aggregations data to detail – level items make the UDM a powerful construct indeed. The UDM also allows you to design the model in the end user’ s language, which is needed in a global market.

Creating a Cube Using the Cube Wizard

Cubes are the principal objects of an OLAP database that help in data analysis. Cubes are multidimensional structures that are primarily composed of dimensions and facts. The data from a fact table that is stored within the cube for analysis are called measures. In Analysis Services 2008 you can store data from multiple fact tables within the same cube. In Chapter 2 you became familiar with the Cube Wizard and in this chapter you see more details of the Cube Wizard followed by refinements to your cube in the Cube Designer.

Similar to the Dimension Wizard you used in Chapter 5 , the Cube Wizard facilitates creation of cube objects from the DSV. For this exercise, you continue with the AnalysisServices2008Tutorial project you created in Chapter 5 , which contained the dimensions [Dim Geography], [Dim Employee], and [Dim Date]. To start with a clean slate, please delete the existing cube Adventure Works DW if it is still there from Chapter 2 . To completely understand the functionality of the Cube Wizard, follow these steps to build a new cube:

1. Open the AnalysisServices2008Tutorial project from Chapter 5 . If the Adventure Works DW cube exists, delete the cube by right – clicking it in the Solution Explorer and selecting Delete. 2. Right – click the Cubes folder and select New Cube, as shown in Figure 6 – 2 . Click Next on the introduction page to proceed.
Figure 6 – 2

3. In the Select Creation Method page you have the option to build a cube from existing tables, create an empty cube, or create a cube based on a template and generate new tables in the data source. In this tutorial you build the cube from the existing tables in the Adventure Works DW data source. Click Next to proceed to the next step in the Cube Wizard.

4. The next page of the Cube Wizard is the Measure Group Tables selection page. If you have multiple DSVs, you need to select the DSV upon which you are creating the cube. In the current project you only have the Adventure Works DW DSV. You now must select one or more tables that will serve as fact tables for your Measure Group. The Suggest button on this screen can be used to have the Cube Wizard scan the DSV to detect the fact tables in the DSV and detect fact tables. Click the Suggest button to have the Cube Wizard automatically select potential Measure Group tables.

The Cube Wizard now scans the DSV to detect the fact and dimension tables in the DSV, automatically selects the candidate tables, and updates the list as shown in Figure 6 – 3 . Any table that has an outgoing relationship is identified as a candidate fact table, whereas a table that has an incoming relationship is detected as a dimension table.

Figure 6 – 3

5. You have the option to select or deselect a table as a fact or dimension table. The wizard has identified the FactInternetSales, FactResellerSales, and DimReseller tables as measure group tables. The DimReseller table was detected as a measure group table because there is an outgoing relationship from it. However, it will not be used as a measure group table in this example. Deselect the DimReseller table from being a fact table and click Next.

6. On the Select Measures page, the Cube Wizard shows all the columns from the fact tables that it detects as potential measures of the cube as shown in Figure 6 – 4 . The Cube Wizard does not select the primary and foreign keys in a table as measures. There is a one – to – one mapping between a column in the fact table and a measure in the cube. The Cube Wizard groups measures from a fact table under an object called a measure group. Therefore, by default, there will be one measure group for each fact table included in the cube. In the DSV you are using there are two fact tables, and therefore two measure groups named Fact Internet Sales and Fact Reseller Sales are created. You can select or deselect the measures you want to be part of the cube in this page. Use the default selection and click Next.

Figure 6 – 4

7. In the Select Existing Dimensions page (Figure 6 – 5 ), the Cube Wizard displays a list of all existing dimensions defined in the project. Accept the selection of all the dimensions and click Next.

Figure 6-5
8. The Cube Wizard asks you to select any new dimensions to be created from existing tables in the data source that are not already used for dimensions in the project as shown in Figure 6 – 6 . You can deselect dimensions that are not needed for your cube on this page. This illustration will use the Fact tables only as measure groups and not for dimensions. Deselect the Fact Reseller Sales and Fact Internet Sales dimensions on this page and click Next.

Figure 6-6

9. In the final page of the Cube Wizard (shown in Figure 6 – 7 ) you can specify the name of the cube to be created and review the measure groups, measures, dimensions, attributes, and hierarchies. Use the default name Adventure Works DW suggested by the Cube Wizard and click Finish.

Figure 6-7

The Cube Wizard creates the cube after you click the Finish button. The created Adventure Works DW cube is opened within the Cube Designer as shown in Figure 6 – 8 . The Cube Designer contains several pages that help perform specific operations that will refine the initial cube created by the Cube Wizard. The default page is the Cube Structure page as shown in Figure 6 – 8 . In the Cube Structure page you can see three panes that show the Measures, Dimensions, and the Data Source View. The Data Source View contains all the tables that are part of the cube. Operations such as adding or deleting tables in the DSV and zooming in or out with the DSV Designer are possible within the cube Data Source View pane. The Dimensions pane shows the dimensions that are part of the current cube and the Measures pane shows the cube ’ s measure groups and measures. You can add or delete measures and dimensions in the Cube Structure view. The dimensions within the cube shown in the Dimensions pane are called cube dimensions. You can have multiple instances of the shared dimensions of the database within a cube. For example, the fact tables FactInternetSales, and FactResellerSales have a relationship with the Dim Date dimension through Order Date, Ship Date, and Due Date. Hence you can see three cube dimensions Ship Date, Due Date, and Order Date in the Dimensions pane, which refer to the Dim Date dimension. A dimension such as Dim Date, which plays the role of three cube dimensions, is called a role playing dimension. You learn more about role playing dimensions in Chapters 8 and 9 . Within the Dimensions pane you can see the Hierarchies and Attributes of each dimension under separate folders when you expand each dimension.

Figure 6-8

So far you have created an Analysis Services database containing the Adventure Works DW cube. You have to deploy the project to the Analysis Services instance so that you can analyze the data within the cube. You can deploy the project to the server in one of the following ways:

1. Select Debug Start Debugging from the menu.
2. Right – click the database AnalysisServices2008Tutorial in the Solution Explorer and select Deploy.
3. Right – click the Adventure Works DW cube and choose Process — from which you will first be prompted to deploy the project, followed by Process dialog to process the cube. 4. Use the shortcut key F5 to deploy and process.

When you deploy the project to the Analysis Services instance, BIDS sends an XMLA request containing object definitions to the instance of the Analysis Services server selected in the project. By default the Analysis Services project is deployed to the default instance of Analysis Services on your machine. The object definitions are of the cubes and dimensions you created. If you have installed Analysis Services 2008 as a named instance, you need to change the deployment server name. Then BIDS sends another request to process the objects within the database.

Browsing Cubes

Now that you deployed the cube to an Analysis Services instance, switch the BIDS Cube Designer view to the Browser page. In the Browser page you will see three panes: a Measure Group pane, a Filter pane, and a Data pane along with a toolbar as shown in Figure 6 – 9 .

Figure 6-9

The Measure Group pane, at the left – side of the Cube Browser, shows the measure groups (includes measures) and the dimensions that are related to each measure group (includes attributes and hierarchies) of the cube. The Data pane, at the bottom right, uses the Office Web Components (OWC) control used for analyzing multidimensional data. You can drag and drop hierarchies on the rows and/ or columns and measures in the data area to analyze the data. Indeed, you can have multiple hierarchies in the row and column areas. The OWC also has a filter area (above the column area) that can be used to filter the data being analyzed. You can slice the data you want to analyze based on specific members of a hierarchy.

The top – right pane also allows you to filter your multidimensional data for analysis, but it has additional filtering options above those provided by the OWC control. Whereas the filter area in OWC allows you to select or deselect members of a hierarchy, the Filter pane allows you to perform comparison operations like equal, not equal, contains, in, not in, begins with, range operations, and any MDX expression. With the help of the filter functionality in the Filter pane and OWC, you will be able to analyze your multidimensional data.

Suppose you want to analyze the Internet sales of products based on the promotions offered to customers and the marital status of those customers. First you would need to drag and drop [Dim Promotion].[English Promotion Type] from the Measure Group pane to the OWC rows area. You will learn the MDX statements that are generated by the OWC in this section. SQL Server Profiler in SQL Server 2008 has the ability to trace the MDX statements that are sent to Analysis Services instances. For more information on how to obtain traces please refer to the section on using SQL Server Profiler in Chapter 15 .

The first statement sent from OWC to Analysis Service instance is:
DROP VISUAL TOTALS for [Adventure Works DW]

When you drag and drop members of a hierarchy on a row (or column), or a measure in the fields area, OWC creates a row (or column) called Grand Total, which will automatically provide totals of the measure value for that hierarchy. By default the OWC in the Cube Browser shows you the totals of visible members of the hierarchy in the OWC. This is called Visual Totals because the total is calculated only for the members that are visible in the Browser. You have the option of disabling Visual Totals in the OWC. To do so, right – click OWC, select Commands and Options, click the Report tab, and select the “ All Items (including hidden items) ” option for the “ Calculate totals based on ” section. When the OWC calculates totals based on visual items only, it uses Visual Totals. The preceding MDX statement, DROP VISUAL TOTALS for [Adventure Works DW], removes references to visual totals from cells and clears the memory cache for visual totals thereby ensuring that values for current members selected will be accurate. The full syntax for the Drop Visual Totals statement is shown in the following code snippet. You can optionally specify the MDX set upon which the visual totals will be dropped. If the MDX set expression is not specified, visual totals are dropped for the entire cube.

DROP VISUAL TOTALS FOR < cube name > [ON ‘ < MDX set expression > ’]
The second statement sent to the Analysis Services server by OWC is:

CREATE SESSION
SET [Adventure Works DW].[ {7868741D-072F-458A-8A8D-EA3FED4A3FA7} Pivot0Axis1Set0] AS

{ { [Dim Promotion].[English Promotion Type].[All] },
AddCalculatedMembers([Dim Promotion].[English Promotion Type].[English

Promotion Type].MEMBERS)
}

This statement creates a set called {7868741D – 072F – 458A – 8A8D – EA3FED4A3FA7}Pivot0Axis1Set0, which contains the members of the hierarchy [Dim Promotion].[English Promotion Type]. Because OWC creates the queries in an automated manner, it dynamically creates a session name that includes a descriptive name (Pivot0Axis1Set0) and the session ID. The Analysis Services instance allows you to create sets and other MDX objects within a specific scope. You can create objects within the scope of the database or within the scope of your connection. In the preceding statement OWC creates the set within the scope of the current session and the set will be available only for this specific session.

Finally, OWC sends the following query to retrieve and show the members of the hierarchy [Dim Promotion].[English Promotion Type]:
SELECT
NON EMPTY [{7868741D-072F-458A-8A8D-EA3FED4A3FA7}

Pivot0Axis1Set0]
DIMENSION PROPERTIES MEMBER_NAME, PARENT_UNIQUE_NAME ON COLUMNS
FROM [Adventure Works DW]

CELL PROPERTIES VALUE, FORMATTED_VALUE, FORE_COLOR, BACK_COLOR

Next, drag and drop [Dim Customer].[Marital Status] from the Measure Group pane to the OWC columns area. OWC now sends a series of MDX statements followed by an MDX query to retrieve the members on rows and columns. The following code shows the sequence of MDX statements sent by the OWC to the Analysis Services instance. First the OWC drops visual totals followed by creating two sets for the members of the hierarchies selected on rows and columns of the OWC. OWC then queries the members from the created sets and finally drops the earlier set Pivot0Axis1Set0 because OWC has created new sets for members on rows and columns of the OWC.

Drop visual totals for [Adventure Works DW]
CREATE SESSION

SET [Adventure Works DW].[{7868741D-072F-458A-8A8D-EA3FED4A3FA7}
Pivot1Axis0Set0] AS

{ { [Dim Customer].[Marital Status].[All] },
AddCalculatedMembers([Dim Customer].[ Marital Status].[ Marital Status].MEMBERS)
}

(continued) (continued)

SET [Adventure Works DW].[{7868741D-072F-458A-8A8D-EA3FED4A3FA7} Pivot1Axis1Set0] AS

{ { [Dim Promotion].[English Promotion Type].[All] },
AddCalculatedMembers([Dim Promotion].[English Promotion Type].[English

Promotion Type].MEMBERS)
}

SELECT
NON EMPTY [{7868741D-072F-458A-8A8D-EA3FED4A3FA7}Pivot1Axis0Set0] DIMENSION PROPERTIES MEMBER_NAME, PARENT_UNIQUE_NAME ON COLUMNS, NON EMPTY [{7868741D-072F-458A-8A8D-EA3FED4A3FA7}Pivot1Axis1Set0] DIMENSION PROPERTIES MEMBER_NAME, PARENT_UNIQUE_NAME ON ROWS FROM [Adventure Works DW]

CELL PROPERTIES VALUE, FORMATTED_VALUE, FORE_COLOR, BACK_COLOR
DROP SET [Adventure Works DW].[{7868741D-072F-458A-8A8D
EA3FED4A3FA7}Pivot0Axis1Set0]

Finally, drag and drop the measure [Sales Amount] from the Fact Internet Sales measure group to the Drop Totals or Detail Fields Here area of the OWC pane. The OWC once again generates statements to drop existing sets and create new sets for members on rows and columns. These sets are used in the query to retrieve the measure data along with the properties of the cells. The cell properties returned by the instance of Analysis Services are used by the OWC to display values. From the query you can see that the properties of formatted values, foreground colors, and background colors are being retrieved by the OWC. The OWC uses the formatted value to display the cell values. The statements and query sent to Analysis Services by the OWC are shown here:

Drop visual totals for [Adventure Works DW]
CREATE SESSION
SET [Adventure Works DW].[{7868741D-072F-458A-8A8D-EA3FED4A3FA7} Pivot2Axis0Set0] AS

{ { [Dim Customer].[Marital Status].[All] },
AddCalculatedMembers([Dim Customer].[ Marital Status].[ Marital

Status].MEMBERS)
}

SET [Adventure Works DW].[{7868741D-072F-458A-8A8D-EA3FED4A3FA7}

Pivot2Axis1Set0] AS

{ { [Dim Promotion].[English Promotion Type].[All] },
AddCalculatedMembers([Dim Promotion].[English Promotion Type].[English

Promotion Type].MEMBERS)
}

SELECT
NON EMPTY [{7868741D-072F-458A-8A8D-EA3FED4A3FA7}Pivot2Axis0Set0] DIMENSION PROPERTIES MEMBER_NAME, PARENT_UNIQUE_NAME ON COLUMNS, NON EMPTY [{7868741D-072F-458A-8A8D-EA3FED4A3FA7}Pivot2Axis1Set0] DIMENSION PROPERTIES MEMBER_NAME, PARENT_UNIQUE_NAME ON ROWS, {

[Measures].[Sales Amount]
}
ON PAGES
FROM [Adventure Works DW]

CELL PROPERTIES VALUE, FORMATTED_VALUE, FORE_COLOR, BACK_COLOR
DROP SET [Adventure Works DW].[{7868741D-072F-458A-8A8DEA3FED4A3FA7}Pivot1Axis0Set0]
DROP SET [Adventure Works DW].[{7868741D-072F-458A-8A8D
EA3FED4A3FA7}Pivot1Axis1Set0]
If you hover over a particular cell you can see the cell values without formatting, along with the row and column member values that correspond to that cell as shown in Figure 6 – 9 .

Cube Dimensions

The Cube Wizard helps you create your cube object from the DSV by creating appropriate dimension objects. The wizard detects the relationships between dimension tables and fact tables in the DSV, creates appropriate dimensions if needed, and establishes appropriate relationships between the dimensions and measure groups within the cube. As mentioned in the previous section, a cube contains an instance of the database dimension referred to as cube dimension. There can be multiple instances of a database dimension within a cube. There exists a relationship between the cube dimension and the measure groups within the cube. In this section you learn about various types of relationships between the cube dimensions and the measure groups within, as well as refine the Adventure Works DW cube created by Cube Wizard by adding a new dimension.

The Cube Wizard establishes relationships between the measure groups and cube dimensions based on its analysis of relationships in the DSV. You might have to refine these relationships based on your business needs. You can change these relationships in the Dimension Usage tab of the cube editor. If you switch to the Dimension Usage tab you will see the dimensions, measure groups of the cube, and the relationships between them, as shown in Figure 6 – 10 .

The cube dimensions and measure groups are represented in a matrix format as rows and columns, respectively, where the relationship between them corresponds to the intersection cell. The intersection cell shows the dimension type along with the attribute that is used in the relationship to join.

Figure 6-10

Relationship Types

Six different types of relationships can exist between a dimension and a measure group: No Relationship, Regular, Fact, Referenced, Many – to – Many, and Data Mining. In Figure 6 – 10 you see three of the six relationship types: No Relationship, Referenced, and Regular. Cells corresponding to a specific dimension and measure group can have an attribute specified that indicates that the dimension type is Regular. Further, such attributes can be used in the join condition between the dimension and the measure group. Often this attribute is the key attribute of the dimension and is called the granularity attribute. The granularity attribute can be an attribute that is above the key attribute of the dimension. When you browse a dimension along with measures of a measure group where the dimension and measure group have a regular relationship, Analysis Services aggregates the data appropriately. If you have your granularity attribute above the key attribute of your dimension, it is critical that you define appropriate attribute relationships in your dimension to make sure the data that is getting aggregated is accurate. The relationship between Dim Customer and Fact Internet Sales measure group is a regular relationship. The granularity attribute is shown in the cell intersecting the dimension and measure group as shown in Figure 6 – 10 .

Cells that are shaded gray indicate there is no relationship between the dimension and measure group. Whenever there is no relationship between a dimension and measure group, the measure group property IgnoreUnrelatedDimension controls the results of queries involving any hierarchy of that dimension and any measure from the measure group. The measure values will either be null (IgnoreUnrelatedDimensio n=False) or the same value for each member of the dimension (IgnoreUnrelatedDimension=True). For example, there is no relationship between the dimension [Dim Employee] and the [Fact Internet Sales] measure group. If you browse the Gender hierarchy of [Dim Employee] and the measure [Sales Amount], you see that the measure values for each member of Gender hierarchy are the same value as the Grand Total as shown in Figure 6 – 11 . This is because the IgnoreUnrelatedDimension value is set to True by the Cube Wizard as a default. You learn more about properties of measure groups and measures later in this chapter.

Figure 6-11

When a table is used as both a fact and dimension table, it constitutes a unique relationship between the dimension and measure group called the fact relationship. The relationship is similar to that of the regular dimension, but specifying it as a fact dimension helps improve query performance for a certain class of MDX queries. You learn more about fact dimensions in Chapter 9 .

Typically there is a one – to – many relationship between a fact and a dimension member for regular relationships. When you have a one – to – one relationship between a fact and a dimension member, you typically have a fact relationship. When there is a many – to – many relationship between a fact and a dimension member, the dimension member has a one – to – many relationship with various facts and a single fact is associated with multiple dimension members. The definition for a many – to – many relationship can be well understood via an example. Assume you have a fact table (for sales of books) that is related to a dimension table containing author information. There is another fact table that contains authors ’ salary information, which is related to the Authors dimension table as well as the geographical information of the publisher who is paying the authors. In this example you have a one – to many relationship between authors and books. The salary fact data is related to the publisher’ s geographical information and the authors. If you want to analyze the book sales based on the geographical information of the publisher, the Geography dimension of publishers acts as a many – to many relationship with the fact Book Sales. You learn about the usage of fact and many – to – many relationships in Chapter 9 .

Data Mining dimensions are another item type in the list of relationships; these are used to establish linkage between a cube and a dimension created from a Data Mining model. You learn more about this in Chapters 9 and 16 .

When a dimension is related to the fact data through another dimension, you define this indirect relationship between the measure group and the dimension as a reference relationship. In Figure 6 – 10 the Dim Sales Territory (Dim Employee – Sales Territory) dimension is related to the Fact Reseller Sales measure group through the Employee dimension. The icon at the intersection of the dimension and measure group indicates this reference relationship. You might also recall that you added the Dim Geography dimension in the Select Existing Dimensions page of the Cube Wizard. However, the Cube Wizard was not smart enough to figure out there is a relationship between the Fact tables and the Dim Geography dimension table through other dimension tables. Hence the Cube Wizard did not add the Dim Geography dimension as a cube dimension. Because the relationship between the Dim Geography dimension and the measure groups in the Adventure Works DW cube is through another dimension, you can say that there is an indirect relationship between the Dim Geography dimension and the measure groups.

Follow these steps to add the Dim Geography dimension to the cube and establish the reference relationship:
1. To add the Dim Geography database dimension to the cube, right – click in the Dimension pane of the Dimension Usage tab and select Add Cube Dimension, as shown in Figure 6 – 12 . 2. A dialog showing all the shared dimensions within the project launches, as shown in Figure 6 – 13 . Select the Dim Geography dimension and click OK.
Figure 6-12
Figure 6-13

The cube editor is unable to identify a relationship through an attribute between the existing measure groups and the Geography dimension and as a result leaves the relationship definition up to you. There exists an indirect relationship between the [Dim Geography] dimension and [Fact Internet Sales] measure group through the [Dim Customer] dimension. There is an indirect relationship between the [Dim Geography] dimension and the Fact Reseller measure group through the [Dim Reseller] dimension. You need to define these reference relationships. 3. To define the relationship between [Dim Geography] and the [Fact Internet Sales] measure

group, select the corresponding cell in the matrix and you will see an ellipsis in that cell. Click the ellipsis ( “ . . . ” ).

4. This opens the Define Relationship dialog shown in Figure 6 – 14 . Select Referenced from the Select relationship type drop – down list box. The [Dim Geography] dimension forms an indirect or reference relationship with the [Fact Internet Sales] measure group through the [Dim Customer] dimension. You define the intermediate dimension through the Intermediate Dimension field in the wizard. Once you have defined the intermediate dimension, you need to select the attributes that are involved in the join of the relationship. The “ Reference dimension attribute ” is the attribute in the reference dimension that is used in the join between the intermediate dimension ([Dim Customer]) and the reference dimension ([Dim Geography]). The “ Intermediate dimension attribute ” is the attribute of the intermediate dimension that is involved in the join between the reference dimension and the intermediate dimension. Define the Intermediate dimension as [Dim Customer], Reference dimension attribute as [Geography Key], and Intermediate dimension attribute as [Geography Key] as shown in Figure 6 – 14 and click OK. In Figure 6 – 14 you see a checkbox with the text Materialize. This checkbox is enabled by default in SQL Server Analysis Services 2008. By enabling this checkbox you are ensuring Analysis Services will build appropriate indexes to get improved query performance while querying fact data along with reference dimension hierarchies.

5. Similar to step 4, establish a referenced relationship between the [Dim Geography] dimension and the [Fact Reseller Sales] measure group through the [Dim Reseller] dimension. Once you have completed specifying the relationship between [Dim Geography] and the two measure groups of the cube, your Dimension Usage tab will resemble Figure 6 – 15 .

Figure 6-15

The reference relationship between a dimension and a measure group is indicated by an arrow pointing to the intermediate dimension as shown in Figure 6 – 15 . This graphical view of the reference relationship helps you identify the type of relationship between a dimension and measure group when you are looking at the Dimension Usage tab of the cube editor. Similar graphical representations are available for fact, many – to – many, and Data Mining dimensions, and you learn about these relationships later in Chapters 9 and 16 .

Browsing Reference Dimensions

Having added the [Dim Geography] dimension as the reference dimension to the cube, assume you want to analyze the Reseller Sales based on different business types in various countries. To do so you need redeploy and process the cube with the changes. Then go to the Cube Browser and drag and drop the [English Country Region Name] hierarchy from the [Dim Geography] dimension to the rows, the [Business Type] hierarchy of the [Dim Reseller] dimension to the columns, and the measure [Sales Amount – Fact Reseller Sales] of the [Fact Reseller Sales] measure group to the details area. You can now analyze the Sales data based on the business type in each country, as shown in Figure 6 – 16 . Based on this sales knowledge, the costs associated with the products, and your business goals, you can strategically promote the business type yielding the maximum profit for your company. Reference dimensions help you to analyze fact data even though they are not directly related to the facts.

The OWC sends the following statements and queries to retrieve data for analyzing the reseller sales fact of various business types across various countries of the resellers. The OWC creates sets for the members on the columns and rows of OWC and then queries the facts added to the detail data along with the sets.

Drop visual totals for [Adventure Works DW]
CREATE SESSION
SET [Adventure Works DW].[{76D2D6C7-D50B-4C12-8DBF-DA53595646F5} Pivot24Axis0Set0] AS

‘ { { [Dim Reseller].[Business Type].[All] },
AddCalculatedMembers([Dim Reseller].[Business Type].[Business

Type].MEMBERS)
}

SET [Adventure Works DW].[{76D2D6C7-D50B-4C12-8DBF-DA53595646F5}

Pivot24Axis1Set0] AS

{ { [Dim Geography].[English Country Region Name].[All] }, AddCalculatedMembers([Dim Geography].[English Country Region Name].

[English Country Region Name].MEMBERS)
}

SELECT
NON EMPTY [{76D2D6C7-D50B-4C12-8DBF-DA53595646F5}Pivot24Axis0Set0] DIMENSION PROPERTIES MEMBER_NAME, PARENT_UNIQUE_NAME ON COLUMNS, NON EMPTY [{76D2D6C7-D50B-4C12-8DBF-DA53595646F5}Pivot24Axis1Set0] DIMENSION PROPERTIES MEMBER_NAME, PARENT_UNIQUE_NAME ON ROWS, {

[Measures].[Sales Amount - Fact Reseller Sales] }
ON PAGES
FROM [Adventure Works DW]

CELL PROPERTIES VALUE, FORMATTED_VALUE, FORE_COLOR, BACK_COLOR
DROP SET [Adventure Works DW].[{76D2D6C7-D50B-4C12-8DBFDA53595646F5}Pivot23Axis0Set0]
DROP SET [Adventure Works DW].[{76D2D6C7-D50B-4C12-8DBF
DA53595646F5}Pivot23Axis1Set0]

The OWC provides you with the option of slicing the data you are analyzing. Therefore OWC creates the MDX statements to create sets within the specified session. It then queries the multidimensional data on three different axes and displays them on the Rows, Columns, and Fields area. Because the query used by the OWC control retrieves data on three – dimensional axes, you cannot execute the same query in SQL Server Management Studio (SSMS). SSMS will only be able to display two – dimensional results. Therefore if you need to see the exact same results in SSMS, you need an MDX query that will retrieve results in a two – dimensional format. The MDX query generated by OWC can be re – written using the CrossJoin function or the cross join operator (*) so that the results can be retrieved on two axes. The simplified MDX query that will return the same results as the OWC is:

SELECT
{

[Measures].[Sales Amount - Fact Reseller Sales]
}
ON COLUMNS,
NON EMPTY {[Dim Reseller].[Business Type].members *
[Dim Geography].[English Country Region Name].members}
DIMENSION PROPERTIES MEMBER_NAME ON ROWS
FROM [Adventure Works DW]

CELL PROPERTIES VALUE, FORMATTED_VALUE, FORE_COLOR, BACK_COLOR

So far you have learned about cube dimensions, how to add them to a cube, how to define relationships, and then how to query data along with the dimensions. Cube dimensions and their attributes and hierarchies contain several properties. Some properties such as AttributeHierarchyEnabled, AttributeHierarchyVisible, and the AttributeHierarchyOptimizedState reflect the state of the cube dimension hierarchies or attributes in the shared dimension by default. You can override these properties so that appropriate settings are applied for the cube dimensions within the cube. The properties AggregationUsage for attributes and AllMemberAggregationUsage for cube dimensions control the behavior of aggregations designed on the cube. You learn more about these properties in Chapters 9 and 14 .

Measures and Measure Groups

You learned about editing cube dimensions and establishing the right relationships between dimensions and measure groups in a cube. Similarly, you can add or delete measures and measure groups in a cube. Measures are the focus point for data analysis and therefore they are the core objects of a cube. Measures are columns from the fact table that contain meaningful information for data analysis. Usually measures are of type numeric and can be aggregated or summarized along hierarchies of a dimension. You can specify the type of aggregation to be applied for each measure. The most widely used aggregate functions are Sum, Count, and Distinct Count. A collection of measures forms an object called a measure group, and a collection of measure groups forms the dimension called Measures in the cube. “ Measures ” is a keyword in Analysis Services that refers to a special dimension that only contains the fact data.

If you click the Cube Structure tab in the cube editor you will see the Measures pane on the top – left corner. Click the cube named Adventure Works DW within the Measures pane to see the associated properties in the Properties window located on the bottom – right corner of the BIDS. Figure 6 – 17 shows the Measures and Properties panes. The Measures pane shows the cube name and the measure groups within the cube. You can see the two measure groups Fact Reseller Sales and Fact Internet Sales that correspond to the two fact tables. Fact table columns that become measures of the cube are contained within the corresponding measure group. There is typically a one – to – one relationship between a fact table and measure group in the cube.

Figure 6-17

In your source data, if you had partitioned your fact data into multiple fact tables across a specific dimension, it needs to be handled differently when designing the cube. For example, if you have Fact Internet Sales data stored in separate fact tables for each quarter (fact data has been partitioned into multiple fact tables across the Time dimension), then with respect to the cube all these are considered a single fact table because they have the same schema. You typically partition your relational fact data into multiple fact tables due to design or scalability considerations, but when you want to analyze the data you will be looking to aggregate the data appropriately across various dimensions, especially the Time dimension. You can either merge the data from all the fact tables within the DSV with a named query or you can utilize the partitioning feature in Analysis Services so that Analysis Services aggregates the data correctly during browsing. You learn more about partitions in Chapters 7 and 14 .

You can see several properties of the cube in Figure 6 – 17 . The most important property is DefaultMeasure. As the name indicates, this property is used to define the measure used by default whenever queries are sent to the cube. The reason why the default measure is important is that whenever your MDX query does not explicitly contain a member from the measures dimension, the default measure is returned. In addition to that, the default measure is used whenever restrictions are applied in the query with the WHERE clause, and based on the default measure your results can be different. If you select the DefaultMeasure property you can see a drop – down list box that shows all the measures of the cube. You can choose the measure you want to define as the default measure of the cube. If the default measure is not specified, the first measure of the first measure group of the cube (as seen in the Measures pane) will be the default measure of the cube.

The next most important property is the StorageMode property. This defines whether your fact data will be stored in Analysis Services, your relational data source, or both. The StorageMode property has three options: Multidimensional OLAP (MOLAP), Relational OLAP (ROLAP), and Hybrid OLAP (HOLAP). The default value is MOLAP, which means that when the cube is processed, Analysis Services reads the relational data and stores it in a proprietary format for fast retrieval. You learn more about the defining storage modes in Chapter 9 . In Analysis Services 2008, you have the option to instruct the Analysis Services instance to automatically update cube and dimension objects if there was a change in the relational data. The ProactiveCaching property lets you specify the frequency of the update of the cube data based on changes in the relational data. You learn about the benefits of proactive caching with the help of a complete scenario in Chapter 21 . The ErrorConfiguration property helps in handling the various errors that can occur while processing the fact data and defining what actions should be taken under such error circumstances such as ignoring the error, converting to a specific value, or stopping processing when errors are encountered. One of the main features of an OLAP database is the ability to create aggregations that facilitate fast query response times. The AggregationPrefix property is used to prefix the name of the aggregations that are created for the cube. The remaining properties are self – explanatory and you can find detailed information for each property in Analysis Services 2008 product documentation.

If you click one of the measure groups, you will see the properties associated with that measure group. Most of the properties at the cube level are also applicable to the measure group. If you specify a value for a property at the cube level as well as the measure group level for a common property, the value specified at the measure group level will be honored by the Analysis Services instance. Expand the measure group Fact Internet Sales and select the measure Sales Amount. The Properties pane now shows the properties of the measure, as shown in Figure 6 – 18 . Next, you learn the important properties of a measure in detail.

The AggregateFunction property defines how the measure value is to be aggregated from one level to another level of a hierarchy in a dimension. For example, assume the Product dimension contains a hierarchy called Products that contains two levels, Model Name and Product Name. Each model contains one or more products. If you want the sales amount of a specific product to be aggregated to the model, you need to specify the aggregate function to be Sum. Whenever you browse the cube along the Products hierarchy, you will see that the sales of each product are aggregated to the corresponding model. However, sometimes you might not want the measure value to be aggregated while browsing a hierarchy. Therefore, Analysis Services 2008 provides you with several aggregate functions. Aggregation functions supported in the properties can also be done using MDX scripts. (You learn about MDX scripts in Chapter 9 .) However, we recommended that you use the built – in aggregation functions supported in the Properties window to get optimal performance from your Analysis Services instance.

Figure 6-18
Other than the Sum aggregate function, the most commonly used aggregate functions are Count and Distinct Count. The Count aggregate function, as the name indicates, is used whenever you want to count each occurrence of the measure value rather than add the measure values. For example, if you want to find the number of transactions in a day or number of customers in a day, you would use a Count aggregate function on a fact table column that indicates the customers who came to the store on a specific day. The Distinct Count aggregate function, on the other hand, can be used to identify the unique number of occurrences of a specific measure. For example, a customer can buy a specific product every month. If you want to find the unique number of customers who purchase a specific product, you use the Distinct Count aggregate function. You will see examples of Count and Distinct Count aggregate functions in this section. The None aggregate function is used when you do not want to aggregate the values of a specific measure across a dimension. An example of where the None aggregate function would be used is for the price of a specific product or discount provided on a unit product.

When you build and browse a cube you will see all the measures occurring under the dimension called [Measures] in the Measure Groups pane of the Cube Browser. If you want to organize the related measures in a logical structure that is more meaningful for users, you use the property called DisplayFolder. You can specify a measure to be part of one or more display folders by editing the DisplayFolder property. If you enter a name in the DisplayFolder property, that specific measure will become part of the newly entered display folder. You can make a specific measure part of multiple display folders by specifying the display folders separated by a semicolon. When display folders are specified, while browsing the cube you will see the display folders under the appropriate measure group name in the metadata pane of the Browser. Therefore you cannot have measures from different measure groups under a single display folder.

In some business applications you only allow access to the aggregated results of a measure. For such applications you need a way to aggregate the results of a measure but do not want to show the base measure. You can aggregate the results of a measure by specifying a measure called the calculated measure (you learn more about calculations a little later in this chapter) and hide the base measure. The measure property Visible allows you to hide the base measure from viewing for such applications.

The FormatString property allows you to show the measure value in a format of your choice. If you select the FormatString property you will see the various format options available. The MeasureExpression property is used for specifying the expression that evaluates the value for the measure. For example, if you have Sales information you might want to ensure the Sales information is presented in the local currency based on the currency conversion rates. In such a case you will define an appropriate expression for the MeasureExpression property for the measure Sales. You learn about the MeasureExpression property in Chapter 9 .

The easiest way to see the effect of some of the properties mentioned is to try them yourself in your own project. Specify two display folders named DisplayFolder1 and DisplayFolder2 for the measure Sales Amount. Because the measure Sales Amount is a currency data type, you can select the currency format. Select the $#,##0.00;($#,##0.00) format from the FormatString property drop – down list. The Properties window for the measure Sales Amount should resemble the Figure 6 – 19 .

Figure 6-19

You learned examples of where the aggregate functions Count and Distinct Count can be useful. In your Adventure Works DW cube, if you want to count the number of customers and distinct customers who have bought specific products, you need to use these aggregate functions. Customer Key identifies the customer who has bought a specific product in the fact table. Therefore, in order to see the counts of customers you need to create two new measures using the fact table column Customer Key. To create the two new measures follow these steps:

1. Right – click the measure group Fact Internet Sales and select New Measure.
2. In the New Measure dialog, select the checkbox “ Show all columns. ”
3. Select the column Customer Key and click OK. A measure called Customer Key is now created.

4. In the Measures pane, change the name for this measure from [Customer Key] to [Distinct Customers] by right – clicking the measure and selecting Rename.
5. Change the aggregate function for this measure to be Distinct Count.

At this point you will notice that a blue squiggly line shows up under the Distinct Customers measure. Analysis Services 2008 has built – in checks for many of the best practices for dimension and cube design. These best practices are implemented as warnings in the Analysis Management Objects (AMO) API. BIDS surfaces these AMO warnings through warning icons and blue squiggly lines for objects that don ’ t meet these design best practices. To discover the rules that generate these warnings, you simply have to move the mouse over the blue squiggly lines or warning icon to see a tooltip with the best practice design rule. In this case the rule suggests that distinct count measures be broken out into separate measure groups (see Figure 6 – 20 ).

The reason for this warning is that distinct count measures are semi – additive and require storing records at a finer level of detail than measures utilizing other aggregate functions. For a distinct count of customers to be accessible, the individual customer IDs must be available. Therefore, Analysis Services must use the Customer Key attribute for any and all aggregations. Consider the following example. If you are interested in the total Sales (sum) for a product in a given year, it is not necessary to retain the individual customer IDs that purchased the product within the desired year. The Analysis Services engine should be able to pre – aggregate data at the Product ID and Year attribute levels as part of the normal processing of the cube. However, if there is a requirement that you know the distinct number of customers who purchased the product within the year, you must retain the customer keys throughout any aggregated data.
If the product in question was purchased by 50,000 customers over the year, the aggregate goes from one row of data per product per year to 50,000 rows per product for the year. Separating Distinct Count measures into different measure groups allows maximum pre – aggregation of other additive measures with minimal storage and on – the – fly aggregation requirements.

If you drag and drop the Customer Key column into the Measures pane to create a new measure, you will notice that the Cube Designer automatically creates a new measure group and adds the measure based on the assumption that you are probably defining a distinct count aggregation function. For this illustration we will ignore this best practice warning and move on to the next steps.

Figure 6-20

1. Right – click the Fact Internet Sales measure group and select New Measure.
2. In the New Measure dialog select the checkbox “ Show all columns. ”

3. Select the column [Customer Key] and click OK. A measure called [Customer Key] is now created.
4. In the Measures pane, change the name for this measure from [Customer Key] to Total Customers by right – clicking the measure and selecting Rename.
5. In the Properties window change the AggregateFunction property for the [Total Customers] measure from Sum to Count.

6. The Unit Price of a product is the same value. Therefore this value should not be aggregated. In order to see the same value for a specific product you need to choose the aggregate function FirstNonEmpty.

7. Create a user hierarchy called Products in the Dim Product dimension with two levels, Model Name and English Product Name, where Model Name is the parent level of English Product Name. Rename the level English Product Name as Product Name.

8. Deploy the project to the Analysis Services instance.

9. Once the deployment is complete, switch to the Cube Browser tab. Click the Reconnect link to get the updated metadata and data from the Analysis Services instance. When you expand the [Fact Internet Sales] folder under the Measures node, you will see two folders called DisplayFolder1 and DisplayFolder2 that contain the measure [Sales Amount] as shown in Figure 6 – 21 .

Figure 6-21

10. Clear any data in your OWC browser by right – clicking within the OWC area and selecting Clear Results or by dragging and dropping each measure or hierarchy from rows/columns to outside of the OWC area.

11. Drag and drop the measures [Sales Amount], [Total Customers], and [Distinct Customers] for the [Fact Internet Sales] measure group to the data area of the OWC.
12. Then drag and drop the hierarchy Products from the Dim Product dimension to the rows and expand the member Classic Vest.

You can now see that the values for the measures are aggregated for the hierarchy Products that contains two levels, Model Name and Product Name, based on the aggregate function chosen. Choosing the aggregate functions Count and Distinct Count will not only count the values for the members of a hierarchy, but will also aggregate the counts to the next level. Notice that the values of [Sales Amount] are formatted based on the format string you specified earlier.

You should be able to add the measure [Unit Price] in the same browser and see the results of the FirstNonEmpty aggregate function. However we believe there is a bug in the product that causes the values for [Sales Amount] and [Total Customers] to be cleared in the Cube Browser. We recommend you clear the fields [Sales Amount] and [Total Customers] from the data area and drag and drop [Unit Price]. You can see that the Unit Price is aggregated from the members in the Product Name level to Model Name level based on the FirstNonEmpty aggregate function. You see the Total value for the measure Unit Price for the Classic Vest model as 63.5. The Unit Price value shown for the Mountain – 100 model name is the Unit Price Mountain – 100 Silver 42, one of the members of the Mountain – 100. In the example shown in Figure 6 – 21 , all the products under the model name Classic Vest have the same unit price. If you expand the Model Name member Mountain – 100 you will see that the Products under the model Mountain – 100 have different values.
You have now successfully enhanced the cube created by the Cube Wizard by adding cube dimensions and measures to the cube. In the process you have also learned about the properties of cube dimensions, measures, and measure groups. Most often businesses need complex logic to analyze the relational data. Analysis Services 2008 provides you with the ability to embed the complex calculations required for solving business problems in several ways. The most basic operation that every business will need is creating simple arithmetic operations on the base measures or dimension members. Objects created via such operations are called calculated members.

Calculated Members

The term calculated member refers to the creation of any MDX object through a calculation. The calculated member can be part of the Measures dimension where a simple MDX expression such as addition or subtraction of two or more base measures results in a new measure. Such calculated members on the Measures dimension are referred to as calculated measures. You can also create calculated members on other dimensions by specifying an MDX expression. These members are simply referred to as calculated members. To create a calculated member, click the Calculations tab of the cube editor. This takes you to the Calculations view, as shown in Figure 6 – 22 . The Calculations view contains three window panes: Script Organizer, Calculation Tools, and Script.

The Script Organizer window pane shows the names of the calculation objects of the cube. Various types of calculations can be created in the Calculations view such as calculated members and calculated measures. You can apply a name to a subset of dimension members. This is referred to as a named set. In addition to calculated members and named sets, you can define a script containing complex MDX expressions to perform complex business logic calculations. If you right – click within the Script Organizer you can see the selections to create a calculated member, named set, or a script command. These operations can also be performed by clicking the buttons in the toolbar as indicated in Figure 6 – 22 . You create calculated measures in this chapter. The creation of script commands and named sets are detailed in Chapters 9 and 10 .

The Calculation Tools pane contains three pages: Metadata, Functions, and Templates. The Metadata view is identical to the Measure Groups pane you have become familiar with in the Cube Designer’ s Browser page. It shows the measures and dimensions of the current cube. The Functions view shows all the MDX functions along with a template of the arguments needed for each function. In the Templates view you can see templates for some common calculations used in certain applications such as budgeting and financial.

The Script window pane shows the details of calculation scripts. The default view of the Script window is called the Form View. It can also be toggled to a different view called the Script View. In the Form View, the Script Organizer pane will be visible and you can see the calculations of each object in the Script window pane. If the Script window is switched to the Script View (using the appropriate button as shown in Figure 6 – 22 ), all the calculations are shown as a single script and the Script Organizer pane becomes invisible. You can toggle between the two views by clicking the icons shown in Figure 6 – 22 or by selecting the option through the menu item Cube Show Calculations In, which contains options for Script or Form views.

New Named Set Form View
Script View Change UserNew Calculated New Script
Member Command Calculation Properties
Script Window
Figure 6-22

All commands and selections available in Analysis Services 2008 are accessible via keyboard controls. You can switch between the three panes of the Script tab of the Cube Designer using the F6 function key or by making the appropriate selection via menu items.

Calculated Measures

Calculated measures are the most common type of calculated members created in a cube. In your project you have the measures Sales and Product Cost in the two measure groups, Fact Internet Sales and Fact Reseller Sales. An important question to ask about any business concerns profits gained. Profits gained is the difference between total sales and cost of goods sold. In the Adventure Works DW cube you have Sales through the Internet as well as through resellers. Therefore you need to add these two sales amounts to calculate the total sales of products. Similarly, you need to calculate the total product cost by adding the costs of products sold through the Internet and resellers. Two calculated measures must be formed to perform these operations. Once you have created these two calculations, you can calculate the profit. Follow these steps to create the calculated measure for profit:

1. Right – click in the Script Organizer pane and select New Calculated Member, as shown in Figure 6 – 23 . An object called Calculated Member is created. The Script window now shows several text boxes for you to specify the name of the calculation, the MDX expression for the calculated member, and other properties for the calculated member.

Figure 6-23

2. Specify the name of the calculated member as [Total Sales Amount] in the Script window. In the Expression text box you need to type the MDX expression that will calculate the Total Sales Amount. As mentioned earlier, the Total Sales Amount is the sum of sales from the sales amounts in the Fact Internet Sales and Fact Reseller Sales measure groups. Drag and drop these measures from the Metadata window and add the MDX operator “ + ” between these measures as shown in Figure 6 – 24 .

Figure 6-24

3. For cost of goods sold, create a new calculated member called [Total Product Costs] using a method similar to the one described in step 2 but with appropriate Product Cost measures from the two measure groups.

4. Create a calculated member called [Profit]. The MDX expression to evaluate Profit is the difference of the calculated measures you have created in steps 2 and 3. Enter the MDX expression [Measures].[Total Sales Amount] – [Measures].[Total Product Costs] in the Expression text box as shown in Figure 6 – 25 . Since Measures is a special dimension, we do not necessarily have to precede the measure name with [Measures].

Figure 6-25

5. You have the option of specifying certain additional properties for the calculated measures you have created based on an MDX expression. By default all the calculated measures created are visible. You can specify color, font, and format strings for the calculated measures based on certain conditions. For example, if you want to highlight the profit in red if the amount is less than one million dollars and in green if it is greater than or equal to one million, you can do so by specifying the appropriate background color for the calculated member.

6. Enter the following MDX expression for the Color Expressions Back color: in the Script Window.
iif ( [Measures].[Profit] < 1000000, 255 /*Red*/, 65280 /*Green*/)

This MDX expression uses the IIF function. This function takes three arguments. The first argument is an expression that should evaluate to true or false. The return value of the IIF function is either the second or the third argument passed to the function. If the result of the expression is true, the IIF function returns the second argument; if the expression is false, it returns the third argument. The first argument passed to the IIF function is to see if the profit is less than one million. The second and third arguments passed to the function are the values for the colors red and green. The values for the colors can be selected by clicking the color icon next to the background color text box.

To see the effect of the calculations you have created:
7. Go to the Cube Browser tab.
8. Deploy the AnalysisServices2008Tutorial project to your Analysis Services instance.

9. As soon as the deployment is complete, switch to the Cube Browser tab and click the Reconnect button to get the updated metadata and data from the Analysis Services instance. 10. Expand the Measures folder to see the newly created calculated measures as shown in Figure 6 – 26 .

11. Drag and drop the measure Profit to the OWC detail area, hierarchy English Country Region name of the Dim Geography dimension on rows, and hierarchy Style of the Dim Product dimension on columns.

You will see the background color for the cells are either red or green based on the Profit value as shown in Figure 6 – 26 .
Figure 6-26

Querying Calculated Measures

You can query the calculated measures similar to other measures in the cube by referencing them by name. For example, if you want to query the calculated member Profit based on Model Name, you execute the following query:

SELECT [Measures].[Profit] on COLUMNS,
[Dim Product].[Model Name].MEMBERS on ROWS
FROM [Adventure Works DW]

If you want to retrieve all the measures in the cube instead of specifying each measure, you use [Measures].MEMBERS. However, calculated members are not returned in your query result when you specify [Measures].MEMBERS. You need to execute the following MDX query to retrieve the base measures along with the calculated members:

SELECT [Measures].ALLMEMBERS on COLUMNS,
[Dim Product].[Model Name].MEMBERS on ROWS
FROM [Adventure Works DW]

You have learned to enhance the Adventure Works DW cube by creating calculated measures and learned to set certain properties for the calculated measures via MDX expressions. The NonEmptyBehavior property for calculated measures is discussed in Chapter 15 .

Creating Perspectives

Analysis Services 2008 provides you with the option of creating a cube that combines many fact tables. Each cube dimension can contain several attributes and hierarchies. Even though the cube might contain all the relevant data for business analysis combined into a single object, the users of the cube might only be interested in sections of the cube. For example, you can have a cube that contains sales and budget information of a company. The Sales department is only interested in viewing sales – relevant data, whereas the users involved in budgeting or forecasting next year’ s revenue are only interested in budget – relevant sections of the cube. Typically, users do not like to see too much extra information. In order to accommodate this, Analysis Services 2008 provides you with the option of creating a view of a cube that only contains a subset of its objects, called a perspective.

In the Adventure Works DW cube you have two fact tables, FactInternetSales and FactResellerSales. To understand the behavior of perspectives, create a perspective for Internet Sales and a perspective for Reseller Sales. The following steps show you how to create new perspectives:

1. Click the Perspectives tab in the Cube Designer. You will see a column on the left showing the measures, dimensions, and calculated members as shown in Figure 6 – 27 .
Figure 6-27

2. Right – click in the window pane and select New Perspective as shown in Figure 6 – 27 . You can also create a new perspective by clicking the New Perspective button in the toolbar. A new column with the name Perspective is created. You have a checkbox next to each object in the cube and these are selected by default. Rename the perspective Internet Sales. Deselect the Fact Reseller Sales measure group and the dimensions Dim Employee and Dim Reseller.

3. Create another perspective called Reseller Sales. Deselect the Fact Internet Sales measure group and the Dim Customer dimension.
Your Perspective window will now look similar to Figure 6 – 28 . Now deploy the project. BIDS sends the definitions for the new perspectives to the server. Perspectives are not new cubes on the server, but only a view of an existing cube object. Keep in mind that perspectives are represented as different cubes with the cube names represented as the perspective name when a client queries for the cube in a database.

Figure 6-28

In Chapter 5 you learned to specify translations to attributes in a dimension. Similarly, you can create translations for the cube. You see the effect of perspectives along with translations after learning how to create translations for a cube.

Creating Translations

Translations facilitate the display of data and metadata in a regional language. Unlike translations for dimensions, where a column from the relational table is specified as containing the translation for members of an attribute hierarchy, cube translations are specified for the cube ’ s metadata objects.

To create a new translation for the Adventure Works DW cube, do the following:

1. Click the Translations tab in the Cube Editor. Similar to the Perspective view, the left column shows the names of all the metadata objects in the default language. There is another column that indicates the object type, which indicates Caption because defining translations for a cube is only providing translated names for the metadata object names.

2. Right – click in the Translation window pane and select New Translation. You can also create a new translation using the New Translation button in the toolbar. In the Select Language dialog, select French (France) as the language and click OK. You now have a new column where you can provide the translations of each object (measure, display folders, dimension name, attribute names). Specify the translations in French as shown in Figure 6 – 29 . (If you don ’ t know French you can enter the translations in a language of your choice.) You can define translations for each metadata object in the cube such as measure names, measure group names, dimension names, perspective names, as well as calculated member names.

3. Deploy the project to your Analysis Services instance.
Figure 6-29

Browsing Perspectives and Translations

You have successfully created perspectives and translations for the Adventure Works DW cube. To see the effect, you need to be in the Browser tab of the Cube Designer. In the Browser, if you click the Perspective drop – down list box you will see three perspectives: Adventure Works DW (the default perspective that contains all cube objects), Internet Sales, and Reseller Sales. Select the Internet Sales perspective. If you expand the measures in the Measure Group window you will notice that all the measures relevant to the reseller are now not visible. Drag and drop the Sales Amount, English Product Name hierarchy in the Dim Product dimension, and the English Education hierarchy of the Dim Customer dimension to the OWC browser. You will see the sales amount data along with product names and education of customers as shown in Figure 6 – 30 .

To see the translated names in French you need to select the language French (France) in the Cube Browser. As soon as you select the French (France) language you will notice that all the metadata and data members for the hierarchies in the OWC automatically change to values in French for those objects where translations have been defined, as shown in Figure 6 – 31 . Thus you have created translated values in French for a French client who wants to analyze the same values, but who would be able to understand and interpret the results better in French than English. Each language has a corresponding id called the locale id. When you select a specific language in the Browser, BIDS connects to the server with the corresponding locale id for the language. Analysis Services automatically provides you with the metadata and data corresponding to the locale id whenever queries are sent to the server on the same connection.

Figure 6-30

Figure 6-31
Instead of creating new cubes for various users and clients understanding different languages and the overhead of maintaining the cubes in each language, Analysis Services 2008 provides you with the functionality through the perspectives and translations features.

Summary

You traversed the Cube Wizard for a second time in this book, but also at a different level of granularity and hopefully with more understanding of what was going on. You learned how to create calculated members and set properties concerning the display of those members; for example, different color foregrounds and backgrounds. And finally, you learned how to create and browse perspectives and translations. In the real world of business, you will have additional enhancement requirements to meet after running the Cube Wizard. These requirements may include creating calculated members on dimensions, creating cube scripts containing complex MDX expressions to meet your business needs, and adding Key Performance Indicators (KPIs), which will graphically represent the state of your business in real time. The Cube Designer contains additional tabs for KPIs and Actions. These features help enhance your cubes for business analysis. In addition to that, the Cube Designer helps in partitioning fact data, and defining aggregations, which in turn help you achieve improved performance while querying your UDM. These are covered in Chapter 9 , with additional coverage in other chapters as well. In the next chapter you learn how to manage your Analysis Services databases using the SQL Server Management Studio.

Dim Design

Dimension Design

Prior to the advent of cable, when you brought home a new television, the first order of business was to manually tune in one of the few existing local channels. To accomplish this you manipulated the dials, rabbit – ear antennae positioning, and other controls to eventually obtain an optimal picture, audio, and vertical hold configuration. The process of designing a data warehouse using Analysis Services 2008 is similar to that. Analysis Services 2008 provides you with various wizards that help you build the initial framework, just like the rotary tuner on the television got you close to the desired channel. With the basic infrastructure in place, some fine – tuning can optimize the initial framework to your needs. In fact, you saw this approach in the previous chapter when you learned about creating data sources and DSVs. Likewise, here you learn how to create dimensions using the Dimension Wizard and then use the Dimension Designer to fine – tune the dimension based on your business needs.

Cubes are made up of dimensions and measures, where the measures are aggregated along each dimension. Without an understanding of dimensions and how measures are aggregated along them, you can ’ t create and exploit the power of cubes, so let ’ s jump right into learning about building and viewing dimensions. Once the dimensions are created, they need to be added to the cube and the right relationship type between the fact data and dimension needs to be defined. Analysis Services 2008 supports six relationship types (no relationship, regular, fact, referenced, many – to – many, and data mining). You learn about relationship types in this chapter and Chapters 8 and 16 . In addition, you learn about the attributes and hierarchies that form an integral part of dimensions. You learn how to model the Time dimension and Parent – Child dimensions, which are different from regular dimensions and are found in many data warehouses. Finally, you learn how to process and browse dimensions.

Working with the Dimension Wizard

Dimensions help you define the structure of your cube so as to facilitate effective data analysis. Specifically, dimensions provide you with the capability of slicing data within a cube, and these dimensions can be built from one or more dimension tables. As you learned in Chapter 1 , your data warehouse can be designed as a star or snowflake schema. In a star schema, dimensions are created from single tables that are joined to a fact table. In a snowflake schema, two or more joined dimension tables are used to create dimensions where one of the tables is joined to the fact table. You create both of these dimension types in this chapter.
You also learned in Chapters 1 , 2 , and 3 that each dimension contains objects called hierarchies. In Analysis Services 2008 you have two types of hierarchies to contend with: the attribute hierarchy, which corresponds to a single column in a relational table, and multilevel hierarchies, which are derived from two or more attribute hierarchies where each attribute is a level in the multilevel hierarchy. A typical example of an attribute hierarchy would be Zip Code in a Dim Geography dimension, and a typical example for a multilevel hierarchy would be Country – State – City – Zip Code also in a Geography dimension. In everyday discussions of multilevel hierarchies, most people leave off the “ multilevel ” and just call them “ hierarchies. ”

For the exercises in this chapter, you use the project you designed in Chapter 2 . If you don ’ t happen to have the project handy, you can download it from http://www.wrox.com. Regardless of whether you download, you will still need to add the Geography Dimension (dbo.DimGeography) to the DSV. To add this dimension to your DSV, follow these steps:

1. Double – click the DSV named “ AdventureWorksDW.dsv ” in Solution Explorer. 2. Click the Add/Remove Objects toolbar button (the top – left button in the DSV Designer toolbar) as shown in Figure 5 – 1 .
Figure 5 – 1

3. In the Available objects list, select DimGeography and click the > (right arrow) button as shown in Figure 5 – 2 . This will move the Geography dimension into the Included objects list in the Add/Remove Tables dialog. Click OK to continue.

4. All tables in the DSV should have the logical primary key set in order to allow Analysis Services to determine the key attribute columns if the table is used in a dimension or the foreign key columns in the case of fact tables. Review the DimGeography table in the DSV designer to make sure the DimGeography column has been set as the primary key as shown in Figure 5 – 3 .

If the primary key column is not retrieved for a table, you can right – click the key column in the table and select Set Logical Primary Key as shown in Figure 5 – 3 . If the primary key for the table has already been set, the option to Set Logical Primary Key will be disabled.

Figure 5 – 3
Now you are ready to explore use of the Dimension Wizard in Analysis Services 2008. Continue to follow these steps to create a Geography dimension.

5. Launch the Dimension Wizard by right – clicking Dimensions in the Solution Explorer and selecting New Dimension as shown in Figure 5 – 4 . If the welcome screen of the Dimension Wizard opens up, click Next.

6. In the Select Creation Method screen, shown in Figure 5 – 5 , you will see four options:

❏ Use an existing table
❏ Generate a time table in the data source
❏ Generate a time table on the server
❏ Generate a non – time table in the data source

Using an existing table in the data source allows for the creation of a standard dimension, which can later be modified to become any sophisticated dimension type. This makes for a great generic starting point.

A Time dimension, on the other hand, is a unique type of dimension typically created from a table that contains time information such as year, semester, quarter, month, week, and date. A Time dimension is unique because its members are fixed (a year always has 12 months in it) and typical business analyses are performed over time. Due to the uniqueness of the Time dimensions and how they are used in business analysis, there are special MDX functions that can be used with time dimensions. Furthermore, aggregation of data on a Time dimension does not have to be a garden variety additive aggregation like sum or count.

Most business decision makers want to analyze their data across a Time dimension to understand, for example, the month with maximum sales for a quarter or some other time period. Analysis Services provides you a distinct way to aggregate measure data across a Time dimension. This is done with semi – additive measures. You learn more about semi – additive measures in Chapters 6 and 9 . In a Time dimension, some standard hierarchies are commonly used, such as fiscal year and calendar year, both of which can be built automatically. The Time dimension can be built using either a table from the data source or without any associated tables in the data source. To create a table to serve as the source of your Time dimension, you choose the second option on the Creation Method screen. To create an Analysis Server – based Time dimension you would select the third option. You learn more about server Time dimensions in Chapter 8 .

In addition to Time, Analysis Services 2008 is also aware of several other common dimension types used in Business Intelligence applications such as Account, Customer, Employee, and Currency, and can create the necessary tables in the data source to support these dimension types. In this chapter we ’ re concerned with creating dimensions from a data source.

In the Select Creation Method dialog, select “ Use an existing table ” and click Next. Figure 5 – 5

7. In the Specify Source Information page (shown in Figure 5 – 6 ), you need to select the DSV for creating the dimension, select the main table from which the dimension is to be designed, specify the key columns for the dimension, and optionally specify a name column for the dimension key value. By default, the first DSV in your project is selected. Because the current project has only one DSV (the Adventure WorksDW DSV), it is selected.

In the Main Table listbox on the screen, you need to select the main table from which the dimension is to be designed. If a dimension is to be created from a star schema, the dimension is created from the single pertinent table. A snowflake schema dimension actually contains several tables, one of which is the primary table of the dimension. This primary table is chosen as the main table in the Main Table selection of the Dimension Wizard.

Select the DimGeography table from the Main table drop – down list as shown in Figure 5 – 6 .

After selecting the Main Table for the dimension, the Key Columns list and the Name Column combo box will automatically be set to the logical primary key of the selected table. If no logical primary key is set, you will need to specify the key columns yourself. If the logical key for the main dimension table is a collection of columns, you must select a single column for the Name Column before proceeding. You have already defined a logical primary key column for the DimGeography table in the DSV.

Click the Next button to proceed to the next step in the Dimension Wizard.

8. The Dimension Wizard now analyzes the DSV to detect any outward – facing relationships from the DimGeography table. An outward – facing relationship is a relationship between the DimGeography table and another table, such that a column in the DimGeography table is a foreign key related to another table. The Select Related Tables screen (see Figure 5 – 7 ) shows that the wizard detected an outward relationship between the DimGeography table and the DimSalesTerritory table. In this example you will be modeling the DimGeography table as a star schema table instead of snowflake schema. Deselect the DimSalesTerritory table and click Next.

9. The Select Dimension Attributes screen of the Dimension Wizard (see Figure 5 – 8 ) displays the columns of the main table that have been selected for the dimension you ’ re creating. Each selected column on this screen results in an equivalent attribute being created in the new dimension. Even though you are building just a dimension here, that dimension is going to be part of a cube, which is described by the Unified Dimensional Model (UDM). The UDM combines the best of the relational and OLAP worlds. One important aspect of the relational model is the ability to query each column for reporting purposes. The columns selected from the relational table are transformed to attributes of a dimension that can then be used for querying from the UDM. You can control which of the attributes are available for browsing and querying by checking or un – checking the Enable Browsing option for each attribute. In addition, you can set the Attribute Type property to allow Analysis Services to provide special functionality based on the attribute ’ s type and/or Analysis Services client tools to utilize this property to provide appropriate navigational paths. By default the wizard assigns the column name as the attribute name. You can change the attribute name for each selected attribute in this page.

In the Select Dimension Attributes screen, select all the attributes of the DimGeography table (all the attributes in the screen), leave their Attribute Type as Regular, allow them to be browsed as shown in Figure 5 – 8 , and click Next.

Figure 5-8
10. The final screen of the Dimension Wizard shows the attributes that will be created for the dimension based on your choices in the wizard (see Figure 5 – 9 ). Click the Finish button. Figure 5-9

The wizard has created the dimension object Dim Geography and opened it up in the Dimension Designer. Congratulations!!! You have successfully created your first dimension using the Dimension Wizard. Next, you learn how to use the Dimension Designer to enhance the dimension to fit your business needs.

Working with the Dimension Designer

The Dimension Designer, shown in Figure 5 – 10 , is an important tool that helps you to refine the dimension created by the Dimension Wizard. You can define the properties such as unary operators, custom roll – ups, and so forth, which help you to define how data should be aggregated for cells referred to by members of hierarchies in the dimension. The Dimension Designer itself is composed of four pages, which can be accessed from the tabs at the top of the designer: Dimension Structure, Attribute Relationships, Translations, and Browser. The first of these pages, Dimension Structure, contains three panes: Attributes, Hierarchies, and Data Source View. In addition to that you have the toolbar, which contains several buttons that help you to enhance the dimension. The Attributes pane shows all the attributes, the Hierarchies pane shows all the hierarchies along with their levels, and the Data Source View pane shows the tables that are used in the dimension. If you hover over each toolbar button you will see a tooltip that describes the functionality of that button. Some of the buttons are the same as the ones you saw in the DSV Designer and are used for operations within the Dimension Designer’ s Data Source View pane. The functionality of some of the other buttons is discussed later in this chapter and in Chapter 8 .

Figure 5-10

Attributes

Attributes are hierarchies that have only two levels: the leaf level, which contains one member for each distinct attribute value, and the All level, which contains the aggregated value of all the leaf level members. The All level is optional. Each attribute directly corresponds to a table ’ s column in the DSV. The Attributes pane in the Dimension Designer shows all the attribute hierarchies of the dimension. The default view of all the attributes within the Attributes pane window is a Tree view as shown in Figure 5 – 11 . Two additional views are supported in the Dimension Designer: List view and Grid view. These views show the attributes and associated properties in different ways.

Figure 5-11

The List view repositions the Attributes pane below the Hierarchies pane and shows only the attributes of the dimension in a flat list (it doesn ’ t show the dimension name as a parent node). This view is useful when your dimension has a lot of multilevel hierarchies. Because you get a wider area for the Hierarchies pane, you get a visually optimized view for this kind of dimension.

The Grid view is laid out similarly to the List view but includes additional columns that allow you to easily edit some of the important dimension properties right in the Attributes pane. When you ’ re working with more than one attribute, editing these properties in the Attributes pane is less cumbersome than having to select each attribute and then switching over to the Properties window to change the attribute ’ s value. (All the properties shown in the Grid view are also present in the Properties window.)

You can toggle between the different views by right – clicking in the Attributes pane and selecting the view type you desire, as shown in Figure 5 – 11 . Just choose the view that best suits you to visualize and design your dimension easily.

Figure 5 – 12 shows the List view and Grid view of the attributes shown in Figure 5 – 11 . Figure 5-12

Attribute Relationships

Attribute relationships can be defined when attributes within the same dimension have a one – to – many relationship with each other. For example, if you have the attributes Country, State, and City, you have one – to – many relationships between country and state, as well as between state and city. Each dimension has to have at least one attribute that is defined as the key attribute. By definition, the key attribute has a one – to – many relationship with every attribute in the dimension. The Dimension Wizard automatically establishes relationships, such that all attributes of the dimension are related to key attributes.

If you are aware of one – to – many relationships between attributes, we highly recommend that you specify these relationships in the Dimension Designer with attribute relationships. Specifying the attribute relationship helps improve query performance as well as changing the aggregation design for multilevel hierarchies so as to include the attributes that are part of a hierarchy. Because the Dim Geography dimension contains one – to – many relationships, you need to specify attribute relationships to get query performance improvements. You learn more about the benefits of attribute relationships in Chapter 14 .

If you are familiar with Analysis Services 2005, you will notice that attributes in the Tree view no longer expand to show attribute relationships for the attributes in the tree. Analysis Services 2008 has added a separate page in the Dimension Designer to make definition of attribute relationships easier for the user. To view and edit the attribute relationships in Analysis Services 2008, you use the Dimension Designer’ s Attribute Relationships page shown in Figure 5 – 13 . The Attribute Relationships page contains three panes. The top pane graphically shows attribute relationships, the Attributes pane on the lower left shows the list of attributes in the dimension, and the Attribute Relationships pane in the lower right shows the list of defined relationships. The attributes shown in the top pane below the Geography Key attribute are all the attributes of the dimension that have one – to – many relationships with the key attribute. All these attributes are also referred to as member property attributes or related attributes. Because the attribute relationship is defined for each member in the Geography Key attribute, you can retrieve its properties from the related attributes using member property MDX functions.

Figure 5-13
You can create new or modify existing attribute relationships using various methods within each of these panes. Follow these steps to update the Geography dimension ’ s attribute relationships: 1. In the visualization (top) pane, modifying attribute relationships is accomplished by dragging and dropping member property attributes onto the attribute to which they are related.

For example, if a State – Province Name has a one – to – many relationship with City, you would create the relationship by dragging the City attribute onto the State – Province Name attribute as follows: In the Attribute Relationships page ’ s visualization pane, select the City attribute and drag and drop it onto the State – Province Name attribute. This creates a new attribute relationship node as shown in Figure 5 – 14 . Note the change in the Attribute Relationships pane to reflect the newly defined relationship. In the visualization pane, editing and deleting attribute relationships is accomplished by right – clicking a relationship ’ s line and selecting the desired action from the context menu.

Figure 5-14

2. To define a new relationship using the Attributes pane, you right – click the attribute that makes up the many side of the one – to – many relationship and select New Attribute Relationship. This will launch the Create Attribute Relationship dialog. The Source Attribute is the attribute corresponding to the “ many ” side of the relationship, and the Related Attribute is the attribute corresponding to the “ one ” side. You can also set the relationship type in this dialog to either Flexible (default) or Rigid. By default, Analysis Services tools define all the relationships to be flexible. A relationship is flexible if the value can change over time. A relationship is rigid if the relationship does not change over time. For example, the birth date of a customer is fixed and hence the relationship between a customer’ s key/name and the birth date attribute would be defined as rigid. However, the relationship between a customer and his city is flexible because the customer can move from one city to another. You can ’ t delete or alter existing relationships from the Attributes pane. You have a one – to – many relationship between English Country Region Name and State – Province Name. To specify that the attribute English Country Region Name has a one – to – many relationship or is a member property of State – Province Name, perform the following steps in the Attribute Relationships tab of the Dimension Designer.

3. Right – click the State – Province Name attribute (source attribute) in the Attributes pane of the Attribute Relationships page and select New Attribute Relationship from the context menu. 4. In the Create Attribute Relationship dialog select the English Country Region Name as the Related Attribute (see Figure 5 – 15 ).
5. Click OK to create the relationship.
Figure 5-15
Your Attribute Relationships display should be similar to that shown in Figure 5 – 16 .

Establishing attribute relationships is important for two reasons: It can improve processing performance (as you learn in Chapter 14 ), and it affects calculations that are aggregated across these attributes. You can view and modify the cardinality of the attribute relationships you establish using the Cardinality property in the Properties window. Click the relationship in the visualization pane or in the Attribute Relationships pane to bring up its properties. By default the Cardinality is set to many. If you know that the relationship between the attributes is one – to – one you can change the cardinality to one. For example, the cardinality between a customer’ s ID and social security number is one – to – one, however the cardinality between the English Country Region Name attribute and the State – Province Name attribute is one – to – many.

Figure 5-16
To define a new relationship using the Attribute Relationships pane you must first select an attribute from either the visualization or Attributes pane and then right – click in the Attribute Relationships pane in the area not occupied by existing attribute relationships. This can be a bit cumbersome. We recommend you use the visualization pane or the Attributes pane for creating new attribute relationships. Editing and deleting existing relationships in the Attribute Relationships pane, however, is as simple as right – clicking the relationship and choosing the desired action from the context menu as shown in Figure 5 – 17 . Editing a relationship launches the Relationship Editor dialog, whose functionality and layout is identical to the Create Attribute Relationships dialog shown in Figure 5 – 15 ; only the title is different.

Figure 5-17
Use the Attribute Relationships pane to edit the existing relationships for the French and Spanish Country Region Name attributes using the following steps:
6. Click the Geography Key to French Country Region Name relationship in the Attribute Relationships pane.
7. Right – click and select Edit Attribute Relationship.
8. In the Edit Attribute Relationship dialog select the English Country Region Name as the Source Attribute (see Figure 5 – 18 ).
9. Click OK to save the change to the relationship.
10. In the Properties window, change the Cardinality property corresponding to the relationship between English Country Region Name and French Country Region Name from Many to One. Figure 5-18
Repeat the previous five steps for the Spanish Country Region Name attribute relationship.

You have now used three different methods for working with attribute relationships. Often in business analysis when you are analyzing a specific member of a dimension, you need to see the properties of the dimension member to understand it better. In such circumstances, instead of traversing the complete hierarchy you can retrieve the member by querying the member properties. This once again is a performance improvement from the end user’ s perspective. A wide variety of client tools support the ability to retrieve member properties of a specific member when needed by the data analyst. You can add additional attributes by dragging and dropping a column from the DSV to the Attributes pane or delete an existing attribute by right – clicking that attribute and selecting Delete.

Hierarchies and Levels

Hierarchies (also called multilevel hierarchies) are created from attributes of a dimension. Each multilevel hierarchy contains one or more levels, and each level is an attribute hierarchy itself. Based on the attributes of the Geography dimension you created, the logical multilevel hierarchy to create would be Country – State – City – Postal Code. You can create this hierarchy using the following steps:

1. Switch to the Dimension Structure tab of the Geography dimension and drag and drop the attribute English Country Region Name from the Attributes pane to the Hierarchies pane. This creates a multilevel hierarchy called Hierarchy with one level: English Country Region Name. This level actually corresponds to a country. To make this name more user friendly, rename the English Country Region Name to “ Country ” by right – clicking the attribute within the multilevel hierarchy and selecting Rename.

2. Drag and drop State – Province Name from the Attributes pane to the Hierarchies pane such that the State – Province Name attribute is below Country in the multilevel hierarchy. Rename State Province Name to “ State – Province ” by right – clicking the attribute and selecting Rename.

3. Drag and drop City and Postal Code attributes to the multilevel hierarchy in that order so that you now have a four- level hierarchy Country – State – City – Postal Code.

4. The default name of the hierarchy you have created is “ Hierarchy. ” Rename it to “ Geography ” by right – clicking its name and selecting Rename (see Figure 5 – 19 ). You can also rename hierarchy and level names in the Hierarchies pane by selecting the item and changing the value of its Name property in the Properties pane.

Figure 5-19

You have now created a multilevel hierarchy called Geography that has four levels, as shown in Figure 5 – 20 . You can click the arrows to expand the attribute in each level to see all the member properties. You can create additional hierarchies in the Hierarchies pane.

Figure 5-20

Notice the warning icon next to the Geography hierarchy name and squiggly line under the name of the hierarchy. If you place your mouse over this icon or the hierarchy name, you will see a tooltip message indicating that attribute relationships do not exist between one or more levels of the hierarchy and could result in decreased performance as shown in Figure 5 – 20 .

The current hierarchy design is what is called an unnatural hierarchy. An unnatural hierarchy exists when knowing the attribute value of one level of the hierarchy is not sufficient to know who its parent is in the next level up the hierarchy. Another example of an unnatural hierarchy would be a Customer Gender- Age hierarchy, where Gender is the top level of the dimension and Age is the second level. Knowing that a customer is 37 years old does not give any indication of their gender. Conversely, in a natural hierarchy, knowing the value of an attribute at one level clearly indicates who its parent is on the next level of the hierarchy. An example of a natural hierarchy would be a Product Department hierarchy with Category and Sub – Category levels. By knowing that a product is in the Mountain Bike Sub – Category, we would know that it belongs to the Bike Category. This relationship between attribute values is defined through attribute relationships. In order for a hierarchy to be considered natural, attribute relationships must exist from the bottom level of the hierarchy all the way to the top. Analysis Services 2008 will only materialize hierarchies that are considered natural. Use the following steps to refine the current Geography hierarchy so that it is natural:

5. Switch back to the Attribute Relationships page. The page should look similar to Figure 5 – 21 .
Figure 5-21
6. There is no relationship between Postal Code and City. In the visualization pane drag and drop the Postal Code attribute to the City attribute.

An attribute relationship between the Postal Code attribute and the City attribute is created as shown in Figure 5 – 22 . Notice that the visualization of the attribute relationships extends beyond the visualization pane. (Depending on the resolution of your monitor, you might be able to view the all the attribute relationships.) You can zoom in or zoom out using the Zoom item in the context menu of the visualization pane to adjust the size of the content of the visualization pane to see all the attribute relationships. Sometimes the attribute relationships view can be quite large depending on the number of attributes and the relationships you have established. You can easily navigate to the area of the visualization pane you ’ re interested in by clicking the “ + ” symbol at the far right of the horizontal scrollbar and using the locator window (as shown in Figure 5 – 23 ).

Figure 5-22

Locator Window
Figure 5-23
7. Switch back to the Dimension Structure tab, verify the warning is gone, and save the dimension as shown in Figure 5 – 24 .

Browsing the Dimension

After successfully creating the Dim Geography dimension, you definitely would like to see the results of what you have created and find out how you can see the members of the dimension. So far, the dimension has been designed but not deployed to the server. Indeed, there has been no interaction with the instance of Analysis Services yet. To see the members of the dimension, Analysis Services needs to receive the details of the dimension (the attributes, member properties, and the multilevel hierarchies you have created). The Analysis Services 2008 tools communicate to the instance of Analysis Services via XMLA (XML for Analysis).

XMLA is an industry – standard, Simple Object Access Protocol (SOAP) – based XMLApplication Programming Interface (API) that is designed for OLAP and Data Mining. The XMLA specification defines two functions, Execute and Discover, which are used to send actions to and retrieve data from the host instance. The Execute and Discover functions take several parameters that define the actions the instance of Analysis Services will perform. One of the parameters of the Execute function is the command sent to an instance of Analysis Services. Note that in addition to supporting the functionality defined in the XMLA specification, Analysis Services supports extensions to the standard. Following is a sample Execute request sent to an instance of Analysis Services using XMLA. The Execute request is a modified version of the one in XMLA specification available at http://www.xmla.org.

< Execute xmlns=”urn:schemas-microsoft-com:xml-analysis”
SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/” > < Command >
< Statement > select [Measures].members on Columns from Adventure
Works < /Statement >
< /Command >
< Properties >
< PropertyList >
< DataSourceInfo > Provider=SQL Server 2008;Data Source=local; < /DataSourceInfo > < Catalog > AnalysisServices2008Tutorial < /Catalog >
< Format > Multidimensional < /Format >
< AxisFormat > ClusterFormat < /AxisFormat >
< /PropertyList >
< /Properties >
< /Execute >
< /SOAP-ENV:Body >
< /SOAP-ENV:Envelope >

In the preceding XMLA, a request is sent to execute an MDX query that is specified within the command Statement on the catalog AnalysisServices2008Tutorial. The XML request shown results in the query being executed on the server side and the results returned to the client via XMLA.

Several different commands are used to communicate to Analysis Server 2008. Some of the common ones are Create, Alter, Process, and Statement. These commands are used to change the structure of objects referenced in the command. Each object in Analysis Services 2008 has a well – defined set of properties. The definition of the objects is accomplished by commands referred to as Data Definition Language (DDL) commands in this book. Other commands work with data that has already been defined. Those commands are referred to as Data Manipulation Language (DML) commands. You learn some of the DML and DDL commands used in Analysis Services 2008 in various chapters of the book through examples. For in – depth understanding of DML and DDL commands, we recommend you read the Analysis Services 2008 documentation.

You might recall that you deployed the AnalysisServices2008Tutorial project in Chapter 2 . When you deploy a project, the BIDS packages all the design change information in the project into a single XMLA request and sends it to the server. In this case, you want to see the contents of the dimension you have created. Therefore you need to deploy the project to an instance of Analysis Services. When you deploy the entire project using BIDS to Analysis Services, several XMLA requests are sent by BIDS. They are:

1. Request a list of the databases from Analysis Services to determine if the current project already exists on the instance. The project name you specified while creating the object will be used as the database name. Based on the deployment settings in your project, BIDS either sends the entire definition of all the objects or only the changes you have made since the last deploy. BIDS will send either a Create or Alter command based upon whether the database already exists on the Analysis Services instance. We have not included the Create/Alter XMLA request in the following code because it is quite large. You can use the SQL Server Profiler to analyze the XMLA request (you learn to use SQL Server Profiler in Chapter 15 ).

2. BIDS then sends an XMLA request to process the objects on the instance of Analysis Services. Following is the request that would be sent to the server to process the dimension Dim Geography:

< Batch xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine” > < Parallel >

< Process xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:ddl2=”http://schemas.microsoft.com/analysisservices/2003/engine/2” xmlns:ddl2_2=”http://schemas.microsoft.com/analysisservices/2003/engine/2/2” xmlns:ddl100_100=”http://schemas.microsoft.com/analysisservices/2008/engine/100/100” >

< Object >
< DatabaseID > AnalysisServices2008Tutorial < /DatabaseID >
< DimensionID > Dim Geography < /DimensionID >

< /Object >
< Type > ProcessDefault < /Type >
< WriteBackTableCreation > UseExisting < /WriteBackTableCreation >

< /Process >
< /Parallel >
< /Batch >

BIDS performs certain validations to make sure your dimension design is correct. If there are errors, BIDS will show those errors using red squiggly lines. In addition to that, a set of error handling properties in the Analysis Services instance helps in validating errors in your dimension design when data is being processed. BIDS sends the default error handling information to the Analysis Services instance for the server to raise any referential integrity errors as part of the deployment process. The default error handling mode in BIDS has been changed in SQL Server 2008 to make sure the developer is aware of all the warnings and errors by default. Follow these steps to deploy your Analysis Services2008Tutorial project:

1. Deploy the AnalysisServices2008Tutorial project to your Analysis Services 2008 instance by either hitting the F5 key or right – clicking the project in the Solution Explorer window and selecting Deploy. BIDS deploys the project to the Analysis Services 2008 instance. You will get a dialog indicating that you have deployment errors as shown in Figure 5 – 25 .

2. Click the No button in the deployment errors dialog shown in Figure 5 – 25 .

BIDS will now report all the warnings as well as errors identified by BIDS and from the Analysis Services instance using the Errors tab as shown in Figure 5 – 26 .
Figure 5-26

BIDS in Analysis Services 2008 has added a new feature by which you can see warnings identified by BIDS in addition to the errors that were shown in previous versions of Analysis Services. The first 15 warnings shown in Figure 5 – 26 are an example of this new feature in action. Some of the warnings detected by BIDS might be the result of valid design decisions you made for your Analysis Services database. Hence BIDS supports a warning infrastructure by which you can disable warnings for specific objects or even disable specific warnings from reappearing in future deployments. When you right – click one of the first 15 warnings, you can see an option to Dismiss the warning. Note, however, that you cannot dismiss a warning reported by the Analysis Services instance or any error. If you click the sixteenth warning, you can see that the warning cannot be dismissed. This is the first warning reported by the Analysis Services instance followed by two errors that fail the deployment of your AnalysisServices2008Tutorial project. You learn more about the warning feature in Chapter 9 .

The Analysis Services instance warning (warning 16 shown in Figure 5 – 26 ) indicates that there was an issue while processing the City attribute and duplicate attribute keys were identified. This warning indicates that there are several cities with the same name. This warning is, in fact, an error raised by the Analysis Services instance. The reason why this error is raised is because you have defined and guaranteed a one – to – many attribute relationship between the City attribute and the State – Province Name attribute. The Analysis Services instance identifies that there are several different Cities with the same name and is unable to decide which State – Province name has the relationship to a specific City. If you query the City column in the DimGeography table, you will see that City names are not unique. For example, London, Paris, and Berlin all appear in excess of a dozen times in the DimGeography table of the AdventureWorksDW database. Hence the Analysis Services instance raises the error with the text “ Errors in OLAP Storage Engine. ” Due to this error, the Analysis Services instance fails the processing of the City attribute and subsequently the Dim Geography dimension and the deployment fails.

To correct this issue, you need to make sure each City is unique. You can do this by creating a surrogate key for the City that makes each city unique and use that key as the key column for the City attribute. Alternatively you can use composite keys to uniquely identify a City attribute. In the following steps, you use a collection of columns to define the keys for several attributes of the Dim Geography dimension. To uniquely identify a City, you need to know the State – Province Name to which it belongs. Therefore, the key collection for the City attribute should be City and State – Province Code. Follow these steps to make the City attribute have unique members:

1. Open the Dim Geography dimension in the Dimension Designer and click the City attribute in the Attributes pane.
2. In the Properties pane, locate the KeyColumns property and click the ellipses (as shown in Figure 5 – 27 ) to open the Key Columns selection dialog.
Figure 5-27

3. In the Key Columns selection dialog, add the StateProvince Code to the list of columns and click OK as shown in Figure 5 – 28 .

By default, the Dimension Wizard uses the column name as the key column for the attribute. The Analysis Services instance automatically infers the same column to be the name column (the column that is used to display the member names for the attribute). Whenever you define a composite key, you need to define a name column for the attribute because BIDS and the Analysis Services instance do not know which of the composite key columns should be used as the name column for the attribute.

4. In the NameColumn property for the City attribute, click the ellipses to open the Name Column selection dialog (shown in Figure 5 – 29 ) and select City as the source for the name of the City attribute.

Figure 5-29
The DimGeography table in the data source also contains duplicate PostalCodes. As you just did for the City attribute, you need to make the PostalCode attribute members unique. 5. Select the PostalCode attribute in the Dimension Designer’ s Attributes pane. 6. In the Properties pane, locate the KeyColumns property and click the ellipses to open the Key Columns selection dialog.
7. Change the KeyColumns for the PostalCode attribute to include the StateProvinceCode, City, and PostalCode columns from the data source. Click OK.
8. Change the NameColumn property by clicking the ellipses next to the NameColumn property in the Properties window.

9. In the Name Column dialog, set the NameColumn property to PostalCode. Click OK. 10. Deploy the AnalysisServices2008Tutorial database to the Analysis Services instance.

The AnalysisServices2008Tutorial database now successfully deploys. Now that you have successfully deployed the database, you can browse the data for the Dim Geography structure by switching to the Browser tab of the Dimension Designer as shown in Figure 5 – 30 . To display the data in the browser, BIDS obtains schema information through several Discover requests to retrieve information such as the hierarchies and levels available for the dimension. Finally, an MDX query is sent to the server by BIDS to retrieve dimension data. The MDX query is:

SELECT HEAD( [Dim Geography].[Geography].LEVELS(0).MEMBERS, 1000 ) on 0 FROM [$Dim Geography]
Figure 5-30

Because you have some familiarity with MDX by now you might have deciphered most of the query. This query uses the HEAD function to request the first 1,000 members from Level 0 of the hierarchy Geography in dimension [Dim Geography]. In the FROM clause you see [$ Dim Geography]. Though you have not created any cube in your data warehouse project yet, you know that the FROM clause should contain a cube name, so how does this MDX query work? When a dimension is created, the server internally stores the values of the dimension as a cube. This means that every dimension is internally represented as a cube with a single dimension that holds all the attribute values. The dimension you have created is part of the Analysis Services database AnalysisServices2008Tutorial and is called a database dimension. Because each database dimension is a one – dimensional cube, they can be queried using MDX using the special character $ before the dimension name. This is exactly what you see in the query, [$Dim Geography].

The hierarchy first shown in the hierarchy browser is the most recently created multilevel hierarchy (in this case, Geography). You can choose to browse any of the multilevel hierarchies or attribute hierarchies by selecting one from the drop – down list labeled Hierarchy. This list contains the multilevel hierarchies followed by the attribute hierarchies. Each attribute hierarchy and multilevel hierarchy within a dimension has a level called the All level. In Figure 5 – 30 you can see the All level for the hierarchy Geography. The All level is the topmost level of most hierarchies (the All level can be removed in certain hierarchies) and you can change the name of the All level by changing the property of the hierarchy. It makes sense to call the level “ All ” because it encompasses all of the sub – levels in the hierarchy. If a hierarchy does not contain the All level, the members of the topmost level would be displayed as the first level in the Dimension Designer’ s Browser page.

Assume you want to change the All level of the Geography hierarchy to “ All Countries. ” The following steps show how to do this:

1. Go to the Dimension Structure view of the Dimension Designer.
2. Click the Geography hierarchy in the Hierarchies pane.

3. The Properties window now shows all the properties of this hierarchy. The first property is AllMemberName and it displays no value. Add a value by typing All Countries in the text entry box to the right of AllMemberName as shown in Figure 5 – 31 .

Figure 5-31

4. Deploy the project once again.

5. After successful deployment, BIDS switches from the Dimension Structure page to the Browser page. If your Deployment “ Processing Option ” has been set to “ Do Not Process, ” you will see a warning in the Dimension Browser pane asking you if you need to process the dimension. If you see this message, click the Process link to launch the Process dialog. Click OK to process the Dim Geography dimension and click the Reconnect button in the Dimension Designer Browser toolbar to view your All member name changes. If your Deployment mode processing has been set to Full or Default, the Dim Geography dimension would be processed along with the deployment and you will see a message in the Dimension Browser to click Reconnect in order to see the latest changes. Click the Reconnect link.

You can now see that the All level of the Geography hierarchy has changed to All Countries, as shown in Figure 5 – 32 . You can also see in the figure that the All Countries level has been expanded to show all members in the next level.

Figure 5-32
When you expand the All Countries level, the following MDX query is sent to the Analysis Services instance to retrieve the members in the next level:

WITH MEMBER [Measures].[-DimBrowseLevelKey 0-] AS
‘[Dim Geography].[Geography].currentmember.properties(“key0”, TYPED)’

SELECT { [Measures].[-DimBrowseLevelKey 0-] } ON 0,
HEAD( [Dim Geography].[Geography].[All Countries].Children, 1000) ON 1 FROM [$Dim Geography]
CELL PROPERTIES VALUE

The goal of the MDX query is to retrieve all the members that are children of the All Countries level. Similar to the MDX query that was sent to retrieve members in level 0, this query only retrieves the first 1,000 children of All Countries level. This is accomplished by use of the HEAD function as seen in the MDX query. This query includes a calculated measure called Measures.[ - DimBrowseLevelKey 0 - ], which is selected in the MDX query. The calculated measure expression in this query retrieves the key of the current member by using the MDX function Properties. The MDX function Properties returns a string value based on the parameters passed to it. The Properties function returns the value of the member property that is specified as the first argument to the expression. In this query the value requested is the Key of the current member.

Other parameters that can be passed to the Properties function are NAME, ID, and CAPTION, or the name of a member property or related attribute. The properties NAME, ID, KEY, and CAPTION are called intrinsic member properties because all attributes and hierarchies will have these properties. The second argument passed to the Properties function is optional and the only value that can be passed is TYPED. If the Properties function is called without the second parameter, the function returns the string representation of the property. If the second argument TYPED is passed to the Properties function, the function returns the data type of the property (data type that was defined in the data source) requested. For example, if the first argument is Key and if the Key of this attribute is of type integer, the Properties function returns integer values. Typically the second parameter TYPED is useful if you want to filter the results based on a member property. For example, if the key of the Geography hierarchy is an integer and if you want to see only the children of member United States, you can use the FILTER function along with the calculated measure that has been created using the parameter TYPED.

The result of the preceding MDX query is shown in the following table. The Dimension Browser retrieves this information and shows the names of the members in the hierarchical format shown in Figure 5 – 32 .

- DIMBROWSEKEY 0 –

Australia
Canada
France
Germany
United Kingdom United States
Unknown
Australia
Canada
France
Germany
United Kingdom United States
Unknown

When you defined an attribute relationship between the State – Province Name and City attribute earlier in the chapter, you implicitly set member properties for those attributes. Now you can see these member properties in the Dimension Designer Browser. To do that you can either click the Member Properties button in the Dimension Designer Browser toolbar (highlighted in Figure 5 – 33 ) or choose Member Properties from the Dimension menu. A dialog appears that has all the attributes of the dimension that participate in attribute relationships. Select the attributes English Country Region Name, State – Province, and City and click OK. The member properties you have selected are now shown in the Dimension Browser as shown in Figure 5 – 33 .

Figure 5-33

Expand the members of United States to see the member properties of the States and Cities under United States. The member properties of a member are also retrieved with the help of an MDX query. For example, when you want to see all the cities in Alabama, the following MDX query is sent to the server:

WITH MEMBER [Measures].[-DimBrowseLevelKey 0-] AS
‘[Dim Geography].[Geography].currentmember.properties(“key0”, TYPED)’ MEMBER [Measures].[-DimBrowseLevelKey 1-] AS
‘[Dim Geography].[Geography].currentmember.properties(“key1”, TYPED)’ MEMBER [Measures].[-DimBrowseProp State Province Name-] AS
‘[Dim Geography].[Geography].currentmember.properties(“State Province Name”, TYPED)’

SELECT { [Measures].[-DimBrowseLevelKey 0-], [Measures].[-DimBrowseLevelKey 1-], [Measures].[-DimBrowseProp State Province Name-] } ON 0,
HEAD( [Dim Geography].[Geography].[State-Province]. & [Alabama].Children, 1000) ON 1 FROM [$Dim Geography]
CELL PROPERTIES VALUE

Similar to the MDX query you analyzed earlier to retrieve all the members of the All level, this query retrieves all the Alabama City members. The City attribute ’ s member property State – Province Name is retrieved (along with the values that make up the City attribute ’ s composite key, City, and State – Province Code) with the same query as calculated members using the WITH MEMBER clause as seen in the preceding query.

Sorting Members of a Level

Members of a level are the members of the attribute that defines that level. For example, the members of the level Country in the Geography hierarchy are actually the members of the attribute English Country Region Name. The member name that is shown in the Dimension Designer Browser is the text associated with the Name of the Country. It is not uncommon for dimension tables to have one column for the descriptive name and one column that is the key column of the table. You can use the descriptive name column to display the name of the attribute and the key column to sort the members in that attribute. The attributes ’ properties help you sort members of a level.

Each attribute in a dimension has two properties: KeyColumns and NameColumn. The KeyColumns property is used to specify the columns that are used for sorting the members, and the NameColumn is used for the descriptive name of the member. By default, the Dimension Wizard and the Dimension Designer set the KeyColumns attribute when an attribute is added to the dimension. They do not set the NameColumn property. If the NameColumn property is empty, Analysis Services will return the KeyColumns value for the descriptive names in response to client requests.

Figur e 5 – 34 shows these properties for the attribute English Country Region Name (Country Level in the Geography multilevel hierarchy). The data type of the attribute is also shown in the KeyColumns property. Country is of data type WChar, which means the members are strings. Therefore, when you view the members in the Dimension Browser the members are sorted by the names. The Dim Geography dimension table has the column Country Region Code. You can define the sort order of the countries based on the Country Region Code instead of their names by changing the KeyColumns and NameColumn properties appropriately. The following exercise demonstrates how you can change the order of the countries based on the order of Country Region Code (AU, CA, DE, FR, GB, and US) instead of the country names.

1. Click English Country Region Name in the Attributes pane; then in the Properties pane, click

the NameColumn property value ellipses. This opens an Object Binding dialog showing all the columns in the Dim Geography table. Select the column EnglishCountryRegionName and click OK.

2. Click the KeyColumns property value (the ellipsis button). This action launches the Key Columns dialog. Remove the column EnglishCountryRegionName from the collection. In the list of available columns, select CountryRegionCode and add it to the Key Columns list. The Key Columns selection dialog should look like Figure 5 – 35 . Click the OK button.

Figure 5-35

3. Click the Advanced Properties for the attribute EnglishCountryRegionName. Make sure the value of the property OrderBy is Key as shown in Figure 5 – 34 . This instructs the server to order this attribute using the Key attribute (CountryRegionCode), which you specified in step 2.

4. Deploy the project to the Analysis Services instance.

Deploying the project to the Analysis Services instance results in sending the new changes defined in steps 1 through 3 followed by processing the dimension. BIDS will switch to the Broswer tab. (If it doesn ’ t, switch to the Browser tab and click the Reconnect option to retrieve the latest dimension data.) In the Dimension Browser select the Geography hierarchy. The order of the countries has now changed based on the order of Country Region Code (AU, CA, DE, FR, GB, and US followed by the Unknown members) instead of the country names you viewed in Figure 5 – 32 . The new order of countries is shown in Figure 5 – 36 .

Optimizing Attributes

During the design of a dimension you might want to include certain attributes in the dimension, but not want to make the attribute hierarchies available to end users for querying. Two attribute properties allow you to manipulate visibility of attributes to end users. One property, AttributeHierarchyEnabled, allows you to disable the attribute. By setting this property to False you are disabling the attribute in the dimension; you cannot include this attribute in any level of a multilevel hierarchy. This attribute can only be defined as a member property (related attribute) to another attribute. Members of this attribute cannot be retrieved by an MDX query, but you can retrieve the value as a member property of another attribute. If you disable an attribute you might see improvements in processing performance depending on the number of members in the attribute. You need to be sure that there will be no future need to slice and dice on this attribute.

Another property called AttributeHierarchyVisible is useful for setting an attribute hierarchy to invisible for browsing; but even with this set, the attribute can be used as a level within a hierarchy and it can be used for querying. If you set this property to False, you will not see this attribute in the Dimension Browser. The properties AttributeHierarchyEnabled and AttributeHierarchyVisible are part of the Advanced group in the Properties window, as shown in Figure 5 – 37 .

Figure 5-37

If you want to create a dimension that contains only multilevel hierarchies and no attributes, you can mark the AttributeHierarchyVisible property to False for all the attributes. When you go to the Dimension Browser you will only see the multilevel hierarchies. Even though you have disabled the attribute for browsing, you will still be able to query the attribute using MDX.

Defining Translations in Dimensions

If your data warehouse is to be used globally, you want to show the hierarchies, levels, and members in different languages so that customers in those countries can read the cube in their own language. Analysis Services 2008 provides you with a feature called Translations (not a super- imaginative name but a name that is intuitive) that helps you create and view dimension members in various languages. The benefit of this feature is that you do not have to build a new cube in every language. For the translation feature to be used, you need to only have a column in the relational data source that will have the translated names for the members of a specific attribute in the dimension.

For example, the Dim Geography table has two columns, Spanish Country Region Name and French Country Region Name, which contain the translated names of the countries that are members of the attribute English Country Region Name. The following steps describe how to create a new translation:

1. Switch to the Translations page in the Dimension Designer.

2. Click the New Translation toolbar button shown in Figure 5 – 38 or choose New Translation from the Dimension menu to create a new translation and choose a language. The Select Language dialog now pops up.

Figure 5-38
3. Select the language French (France) and click OK.

4. A new column with the title French (France) is added as shown in Figure 5 – 39 . Select the cell from the column French (France) in the English Country Region Name row. Then click the button that appears on the right side of the cell. You now see the Attribute Data Translation dialog.

5. Select the French Country Region Name column in the Translation Columns tree view as shown in Figure 5 – 40 and click OK.
6. Repeat steps 2 through 5 for the language Spanish (Spain).

You have now created two translations in French and Spanish languages. In addition to specifying the columns for member names, you can also change the metadata information of each level. For example, if you want to change the level Country in the Geography hierarchy in the French and Spanish languages, you can do that by entering the names in the row that show the Country level. Type Pays and Pais as shown in Figure 5 – 39 for French and Spanish translations, respectively. You have defined translations for the Country attribute in two languages making use of the columns in the relational data source. To see how this metadata information is shown in the Dimension Browser, first deploy the project to your Analysis Services instance.

Figure 5-39

Figure 5-40

Next, to see the effect of the translations you have created, select language French (France) from within the Dimension Browser as shown in Figure 5 – 41 . Select the Geography hierarchy and expand the All level. Now you can see all the members in French. If you click any of the countries, the metadata shown for the level is “ Pays ” (French for country) as shown in Figure 5 – 39 . There is a negligible amount of overhead associated with viewing dimension hierarchies, levels, and members in different languages from your UDM.

Figure 5-41

Creating a Snowflake Dimension

A snowflake dimension is a dimension that is created using a set of dimension tables. A snowflake dimension normally suggests that the tables in the data source have been normalized. Normalization is the process by which tables of a relational database are designed to remove redundancy and are optimized for frequent updates. Most database design books, including The Data Warehouse Toolkit by Ralph Kimball (Wiley, 1996) and An Introduction to Database Systems by C. J. Date (Addison Wesley, 2003), talk about the normalization process in detail.

The columns from different tables of a snowflake dimension often result in levels of a hierarchy in the dimension. The best way to understand a snowflake dimension is to create one yourself. To create one you ’ re going to need two additional tables added to your DSV. Here is how to add the two tables:

1. Open the AdventureWorksDW DSV and click the Add/Remove Tables button (top – left button in the DSV).
2. Click DimProductCategory, then Control – Click DimProductSubcategory, then click the right arrow > to move the two tables from the source to the DSV and click OK.

The DSV Designer identifies the relationships defined in the relational backend and shows the relationships between the DimProduct, DimProductSubCategory, and DimProductCategory tables within the DSV Designer graphical design pane. Now that you have the necessary tables in the DSV and the relationships and logical primary keys defined, you can create a snowflake Product dimension. You can either delete the existing Product dimension in the AnalysisServices2008Tutorial project and create a snowflake dimension using the Dimension Wizard or refine the existing Product dimension and make it a snowflake dimension. In this illustration you will be refining the existing Product dimension and making it a snowflake dimension. Follow these steps to create a snowflake dimension called Dim Product:

1. Double – click the Dim Product dimension in the Solution Explorer to open the Dimension Designer for the Dim Product dimension.
2. Within the Data Source View pane of the Dimension Designer, right – click and select Show Tables as shown in Figure 5 – 42 .
Figure 5-42
3. In the Show Tables dialog select the DimProductSubCategory and DimProductCategory tables as shown in Figure 5 – 43 and click OK.

Figure 5-43
You will now see the DimProductCategory and DimProductSubCategory tables added to the Data Source View pane of the Dimension Designer as shown in Figure 5 – 44 . Notice that the new tables added to the pane have a lighter colored caption bar. This indicates that none of the columns in the tables are included as attributes within the dimension.

Figure 5-44
4. Drag and drop the column ProductCategoryKey from the DimProductSubCategory table in the DSV pane to the Attributes pane.
5. Launch the Name Column dialog for the ProductCategoryKey attribute by clicking the ellipsis next to the Name Column property in the Properties window.
6. Select EnglishProductCategoryName from the DimProductCategory table as the Name Column and click OK.
7. Select the attribute ProductSubCategoryKey from the Attributes pane.
8. Launch the Name Column dialog for the ProductSubCategoryKey attribute by clicking the ellipsis next to the Name Column property in the Properties window.
9. Select EnglishProductSubCategoryName from the DimProductSubCategory table as the Name Column and click OK.
10. Launch the Name Column dialog for Dim Product (the key attribute) by clicking the ellipsis next to the Name Column property in the Properties window.
11. Select English Product Name as the Name Column and click OK.

12. Create a Product Categories multilevel hierarchy with levels ProductCategoryKey, ProductSubCategoryKey, and Dim Product by dragging and dropping the attributes to the Hierarchies pane and naming the hierarchy as Product Categories.

13. Rename the level ProductCategoryKey to ProductCategory.
14. Rename the level ProductSubCategoryKey to ProductSubCategory.
15. Rename the level Dim Product to Product Name.
16. Change the EnglishProductName attribute to Product Name.
17. Figure 5 – 45 shows the Dimension Designer after all the refinements to the Product dimension.

Figure 5-45

You have now successfully created a snowflake Dim Product dimension. You can perform most of the same operations in a snowflake dimension as you can in a star schema dimension, including adding attributes, creating hierarchies, and defining member properties. We recommend you deploy the AnalysisServices2008Tutorial project and browse the snowflake dimension Dim Product.

Creating a Time Dimension

Almost every data warehouse will have a Time dimension. The Time dimension can be comprised of the levels Year, Semester, Quarter, Month, Week, Date, Hour, Minute, and Seconds. Most data warehouses contain the levels Year, Quarter, Month, and Date. The Time dimension helps in analyzing business data across similar time periods; for example, determining how the current revenues or profit of a company compare to those of the previous year or previous quarter.

Even though it appears that the Time dimension has regular time periods, irregularities often exist. The number of days in a month varies across months, and the number of days in a year changes each leap year. In addition to that, a company can have its own fiscal year, which might not be identical to the calendar year. Even though there are minor differences in the levels, the Time dimension is often viewed as having regular time intervals. Several MDX functions help in solving typical business problems related to analyzing data across time periods. ParallelPeriod is one such function, which you learned about in Chapter 3 . Time dimensions are treated specially by Analysis Services and certain measures are aggregated across the Time dimension uniquely and are called semi – additive measures. You learn more about semi – additive measures in Chapters 6 and 9 .

The AnalysisServices2008Tutorial project has a Dim Date dimension that was created by the Cube Wizard in Chapter 2 . Even though the dimension has been created from the Dim Date table, it does not have certain properties set that would allow Analysis Services to see it as the source for a Time dimension. In the following exercise you first delete the Dim Date dimension and then create a Time dimension. Follow these steps to create a Time dimension on the Dim Date table of the AdventureWorksDW2008 database:

1. In the Solution Explorer right – click the Dim Date dimension and select Delete.

2. In the Delete Objects and Files dialog, Analysis Services requests you to confirm the deletion of corresponding Cube dimensions (you learn about Cube dimensions in Chapter 9 ). Select OK to delete the Dim Date dimension.

3. Launch the Dimension Wizard by right – clicking Dimensions in the Solution Explorer and selecting New Dimension. When the welcome screen of the Dimension Wizard opens up, click Next.

4. In the Select Creation Method page of the wizard, select the “ Use an existing table ” option and click Next.
5. In the Specify Source Information page, select DimDate as the main table from which the dimension is to be designed and click Next.

6. In the Select Dimension Attributes page, in addition to the Date Key attribute, enable the checkboxes for the following attributes: Calendar Year, Calendar Semester, Calendar Quarter, English Month Name, and Day Number Of Month.

7. Set the Attribute Type for the “ Calendar Year ” attribute to Date Calendar Year as shown in Figure 5 – 46 .
Figure 5-46
8. Set the Attribute Type for the remaining enabled attributes so they match those shown in Figure 5 – 47 and click Next to continue.
Figure 5-47
9. Set the name of the dimension to “ Dim Date ” and click Finish to close the Dimension Wizard. You have now successfully created a Time dimension using the Dimension Wizard.

10. Create a multilevel hierarchy Calendar Date with the levels Calendar Year, Calendar Semester, Calendar Quarter, Month (rename English Month Name), and Day (rename Day Number Of Month).

11. Save the project and deploy it to the Analysis Services instance.
12. Switch to the Browser pane of the Dim Date dimension.

Figur e 5 – 48 shows the Calendar Date hierarchy that you created. Notice that the order of months within a quarter is not the default calendar order. For example, the order of months of CY Q1 of year 2002 is February, January, and March. To change the order, change the KeyColumns, NameColumn, and SortOrder appropriately and redeploy the project. We recommend that you define the necessary attribute relationships and attribute key values as defined by your business needs.

Figure 5-48

You have now successfully created a Time dimension. If you review the properties of the Dim Date dimension you will see the property “ Type ” set to Time which indicates to Analysis Services that the Dim Date dimension is a Time dimension. If you review the basic properties of each attribute in the Dim Date dimension, you will notice that the property Type has values such as Quarters, HalfYears, Years, DayOfMonth, and Months. You can use the Properties pane to set the right property type for the chosen attribute. Setting the right property type is important because a client application could use this property to apply the MDX functions for a Time dimension.

Creating a Parent – Child Hierarchy

In the real world you come across relationships such as that between managers and their direct reports. This relationship is similar to the relationship between a parent and child in that a parent can have several children and a parent can also be a child, because parents also have parents. In the data warehousing world such relationships are modeled as a Parent – Child dimension and in Analysis Services 2008 this type of relationship is modeled as a hierarchy called a Parent – Child hierarchy. The key difference between this relationship and any other hierarchy with several levels is how this relationship is represented in the data source. Well, that and certain other properties that are unique to the Parent – Child design. Both of these are discussed in this section.

When you created the Geography dimension, you might have noticed that there were separate columns for Country, State, and City in the relational table. Similarly, the manager and direct report can be modeled by two columns, ManagerName and EmployeeName, where the EmployeeName column is used for the direct report. If there are five direct reports for a manager, there will be five rows in the relational table. The interesting part of the Manager- DirectReport relationship is that the manager is also an employee and is a direct report to another manager. This is unlike the columns City, State, and Country in the Dim Geography table.

It is probably rare at your company, but employees can sometimes have new managers due to reorganizations. The fact that an employee ’ s manager can change at any time is very interesting when you want to look at facts such as sales generated under a specific manager, which is the sum of sales generated by the manager’ s direct reports. A dimension modeling such a behavior is called a slowly changing dimension because the manager of an employee changes over time. You can learn slowly changing dimensions and different variations in detail in the book The Microsoft Data Warehouse Toolkit: With SQL Server 2005 and the Microsoft Business Intelligence Toolset by Joy Mundy et al. (Wiley, 2006).

The DimEmployee table in AdventureWorksDW has a Parent – Child relationship because it has a join from ParentEmployeeKey to the EmployeeKey. You have already created a DimEmployee dimension in the AnalysisServices2008Tutorial project in Chapter 2 using the Cube Wizard. In the following exercise you refine the existing Dim Employee dimension and learn how to create a dimension with a Parent – Child hierarchy using the Dimension Wizard. Note that you will actually be refining, not creating, the Dim Employee dimension in the illustration.

1. Launch the Dimension Wizard by right – clicking Dimensions in the Solution Explorer and selecting New Dimension. If the welcome screen of the Dimension Wizard opens up, click Next. 2. Make sure the “ Use an existing table ” option is selected and click Next.
3. In the Specify Source Information page, select DimEmployee as the main table from which the dimension is to be designed and click Next.
4. On the Select Related Tables screen, uncheck the DimSalesTerritory table and click Next.

In the Select Dimensions Attributes dialog, the Dimension Wizard has detected three columns of the DimEmployee table to be included as attributes. The Dimension Wizard will select columns if they are either the primary key of the table or a foreign key of the table or another table in the DSV. Figure 5 – 49 shows two of the attributes. The attributes suggested by the Dimension Wizard in this example are the key attribute Employee Key, the parent – child attribute Parent Employee Key, and the Sales Territory Key, which is a foreign key column to the DimSalesTerritory table.

5. Select all the columns of the DimEmployee table as attributes and click Next.

6. Notice in the preview pane of the Completing the Wizard dialog that the Parent Employee Key attribute has a unique icon (see Figure 5 – 50 ) indicating that Analysis Services detected a parent – child relationship in the DimEmployee table. The wizard was able to identify the parent – child relationship due to the join within the same table in the DSV.

7. Click the Cancel button because you will not be creating another DimEmployee dimension. Figure 5-50
By default the Dimension Wizard defines the properties for the attribute modeling the Parent – Child hierarchy at the completion of the Dimension Wizard or the Cube Wizard. 8. Double – click the DimEmployee dimension in the Solution Explorer to open the Dimension Designer.
9. See the properties of the Parent Employee Key attribute that indicate that this attribute defines a

Parent – Child hierarchy as shown in Figure 5 – 51 .

Notice that the hierarchy doesn ’ t appear in the Hierarchies pane of the Dimension Designer. That ’ s because the Parent – Child hierarchy is actually a special type of attribute hierarchy that can contain multiple levels, unlike the other attributes. The Parent – Child hierarchy that the wizard created is on the attribute ParentEmployeeKey. The Usage property for this attribute is set to Parent, which indicates that this attribute is a Parent – Child hierarchy. If you browse the Parent – Child hierarchy of the DimEmployee dimension, you will notice that you see the IDs of parent and employee as a multilevel hierarchy as seen in Figure 5 – 52 .

Figure 5-52

Typically, you would want to see the names of the employees rather than their IDs. You learned earlier that you can use the named column to specify the name that is shown in the browser and use the key column for ordering. Because the Parent – Child hierarchy retrieves all the information from the Key attribute, which is the DimEmployee attribute in this example, you need to modify the named column of the DimEmployee attribute rather than the named column of the Parent – Child hierarchy attribute.

10. Change the NameColumn property of the Key attribute Dim Employee to LastName and deploy the project to your Analysis Services instance.
When you browse the Parent – Child hierarchy, you will see the members of the hierarchy showing the last names of the employees, as shown in Figure 5 – 53 .
Figure 5-53

Summary

Using the Dimension Wizard and other wizards in BIDS is only the starting point for designing objects in Analysis Services 2008. For optimal results, you will need to fine – tune what those wizards produce. At the beginning of each episode of the television serial The Outer Limits the viewers were exhorted to not adjust their television set. Just the opposite is true with Analysis Services 2008, because you do need to refine your objects created by the Dimension and Cube Wizards. A couple of examples are using the Properties window to assign descriptive names to an attribute that might otherwise harbor some obscure name coming from a source database and defining attribute relationships to optimize dimension performance. More profoundly, you can use the Dimension Designer to create translations for the attributes and hierarchies of a dimension into another language.

In addition to learning about dimensions, you learned the necessity of deploying your dimension to the instance of Analysis Services where the dimension is processed by retrieving the data from the data source. Processing is essential to enable the user to browse a dimension. The communication between BIDS and an instance of Analysis Services is accomplished through a SOAP – based XML API called XMLA (XML for Analysis), which is an industry standard. Even more interesting is that dimensions stored in Analysis Services are represented internally as cubes — one – dimensional cubes; and, what a coincidence, cubes are the topic of Chapter 6 .

SQL Server 2008 70-433 Certification Sample Questions

Number: 70-433
Passing Score: 700
Time Limit: 120 min
File Version: 10.0
 – 70-433
Added 2 new questions and explanations for some answers. Removed duplicate
questions.
Sections
1. Section 1
2. Section 2
3. Section 3
4. Section 4
5. Section 5
6. Section 6
7. Section 7
8. New questions
Exam A
QUESTION 1
You have a user named John. He has SELECT access to the Sales schema. You need to eliminate John’s
SELECT access rights from the Sales.SalesOrder table without affecting his other permissions.
Which Transact-SQL statement should you use?
A. DROP USER John;
B. DENY SELECT ON Sales.SalesOrder TO John;
C. GRANT DELETE ON Sales.SalesOrder TO John;
D. REVOKE SELECT ON Sales.SalesOrder FROM John;
Correct Answer: B
Section: Section 1
Explanation
Explanation/Reference:
REVOKE – permanently removes both granted an denied permissions on an object, resulting in no
permissions.Main thing you have to remember is, this does not restrict user accessing the object
completely. If user is in a role that has permission on the object for the operation, user will be able to
perform the operation.
DENY – Denies permission to the object for an operation. Once it set, it takes precedence over all other
GRANT permissions, user will not be able to perform the operation against the object.
To sum up, because John does not have GRANT permissions on the Sales.SalesOrder table (instead it has
GRANT permission on Sales schema), then REVOKE SELECT ON Sales.SalesOrder from John will not
remove any permissions.
Here is a code that shows it clearly.
– create a login and user
CREATE LOGIN [John] WITH PASSWORD = ‘1’, CHECK_POLICY = OFF
GO
USE [AdventureWorks2008]
GO
CREATE USER [John] FOR LOGIN [John]
WITH DEFAULT_SCHEMA = [dbo]
GO
– grant permission on Sales schema
GRANT SELECT ON SCHEMA :: Sales TO [John]
– Run SELECT with John’s credentials and see
– He sees records
EXECUTE AS USER = ‘John’
SELECT * FROM Sales.SalesOrderHeader
REVERT
– Revoke permisson for the table from him
REVOKE SELECT ON Sales.SalesOrderHeader FROM [John]
– He still sees data
EXECUTE AS USER = ‘John’
SELECT * FROM Sales.SalesOrderHeader
REVERT
– This explicitly denies permission on SalesOrderHeader to John
– Once this is executed, he will not be able to see data
– even we grant him again.
DENY SELECT ON Sales.SalesOrderHeader TO [John]
– He sees error message: The SELECT permission was denied on the object
‘SalesOrderHeader’, database ‘AdventureWorks2008′, schema ‘Sales’.
EXECUTE AS USER = ‘John’
SELECT * FROM Sales.SalesOrderHeader
REVERT
QUESTION 2
You need to create a column that allows you to create a unique constraint.
Which two column definitions should you choose? (Each correct answer presents a complete solution.
Choose two.)
A. nvarchar(26) NULL
B. nvarchar(max) NOT NULL
C. nvarchar(26) NOT NULL
D. nvarchar(26) SPARSE NULL
Correct Answer: AC
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 3
You manage a SQL Server 2008 database that is located at your company’s corporate headquarters.
The database contains a table named dbo.Sales. You need to create different views of the dbo.Sales table
that will be used by each region to insert, update, and delete rows. Each regional office must only be able to
insert, update, and delete rows for their respective region.
Which view should you create for Region1?
A. CREATE VIEW dbo.Region1Sales
AS
SELECT SalesID,OrderQty,SalespersonID,RegionID FROM dbo.Sales
WHERE RegionID = 1;
B. CREATE VIEW dbo.Region1Sales
AS
SELECT SalesID,OrderQty,SalespersonID,RegionID FROM dbo.Sales
WHERE RegionID = 1 WITH CHECK OPTION;
C. CREATE VIEW dbo.Region1Sales
WITH SCHEMABINDING
AS SELECT SalesID,OrderQty,SalespersonID,RegionID FROM dbo.Sales WHERE RegionID = 1;
D. CREATE VIEW dbo.Region1Sales
WITH VIEW_METADATA
AS
SELECT SalesID,OrderQty,SalespersonID,RegionID FROM dbo.Sales
WHERE RegionID = 1;
Correct Answer: B
Section: Section 1
Explanation
Explanation/Reference:
CHECK OPTION
Forces all data modification statements executed against the view to follow the criteria set within
select_statement. When a row is modified through a view, the WITH CHECK OPTION makes sure the data
remains visible through the view after the modification is committed.
QUESTION 4
You administer a SQL Server 2008 database that contains a table name dbo.Sales, which contains the
following table definition:
CREATE TABLE [dbo].[Sales](
[SalesID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
[OrderDate] [datetime] NOT NULL,
[CustomerID] [int] NOT NULL,
[SalesPersonID] [int] NULL,
[CommentDate] [date] NULL);
This table contains millions of orders. You run the following query to determine when sales persons
comment in the dbo.Sales table:
SELECT SalesID,CustomerID,SalesPersonID,CommentDate FROM dbo.Sales
WHERE CommentDate IS NOT NULL AND SalesPersonID IS NOT NULL;
You discover that this query runs slow. After examining the data, you find only 1% of rows have comment
dates and the SalesPersonID is null on 10% of the rows. You need to create an index to optimize the query.
The index must conserve disk space while optimizing your query. Which index should you create?
A. CREATE NONCLUSTERED INDEX idx1
ON dbo.Sales (CustomerID)
INCLUDE (CommentDate,SalesPersonID);
B. CREATE NONCLUSTERED INDEX idx1
ON dbo.Sales (SalesPersonID)
INCLUDE (CommentDate,CustomerID);
C. CREATE NONCLUSTERED INDEX idx1
ON dbo.Sales (CustomerID)
INCLUDE(CommentDate)
WHERE SalesPersonID IS NOT NULL;
D. CREATE NONCLUSTERED INDEX idx1
ON dbo.Sales (CommentDate, SalesPersonID)
INCLUDE(CustomerID)
WHERE CommentDate IS NOT NULL;
Correct Answer: D
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 5
Your database is 5GB and contains a table named SalesHistory. Sales information is frequently inserted
and updated.
You discover that excessive page splitting is occurring.
You need to reduce the occurrence of page splitting in the SalesHistory table.
Which code segment should you use?.
A. ALTER DATABASE Sales MODIFY FILE
(NAME = Salesdat3, SIZE = 10GB);
B. ALTER INDEX ALL ON Sales.SalesHistory REBUILD WITH (FILLFACTOR = 60);
C. EXEC sys.sp_configure ‘fill factor (%)’, ’60′;
D. UPDATE STATISTICS Sales.SalesHistory(Products)
WITH FULLSCAN, NORECOMPUTE;
Correct Answer: B
Section: Section 1
Explanation
Explanation/Reference:
Fill Factor
The fill-factor option is provided for fine-tuning index data storage and performance. When an index is
created or rebuilt, the fill-factor value determines the percentage of space on each leaf-level page to be
filled with data, reserving the remainder on each page as free space for future growth. For example,
specifying a fill-factor value of 60 means that 40 percent of each leaf-level page will be left empty, providing
space for index expansion as data is added to the underlying table.
Page Splits
A correctly chosen fill-factor value can reduce potential page splits by providing enough space for index
expansion as data is added to the underlying table.When a new row is added to a full index page, the
Database Engine moves approximately half the rows to a new page to make room for the new row. This
reorganization is known as a page split. A page split makes room for new records, but can take time to
perform and is a resource intensive operation. Also, it can cause fragmentation that causes increased I/O
operations.
Fragmentation
Fragmentation breaks down to physical and logical fragmentation (or, internal and external fragmentation).
Physical/Internal fragmentation is caused when there is wasted space in the index caused by page splits,
deletes, FILLFACTOR and PAD_INDEX. Logical/External fragmentation is when the pages that make up
the leaf levels of the index are not in good order. This is usually caused by page splits. Both cause
performance problems. Internal fragmentation causes problems because the indexes get bigger and bigger
requiring more and more pages to store the data, which means that reads from the index slow things down.
External fragmentation causes problems because when the data needs to be read from the index it has to
skip all over the place following the links between pages, again, slowing things down.
The SQL Server Database Engine automatically maintains indexes whenever insert, update, or delete
operations are made to the underlying data. Over time these modifications can cause the information in the
index to become scattered in the database (fragmented). Fragmentation exists when indexes have pages in
which the logical ordering, based on the key value, does not match the physical ordering inside the data
file.
You can remedy index fragmentation by either reorganizing an index or by rebuilding an index.
To reorganize one or more indexes, use the ALTER INDEX statement with the REORGANIZE clause.
Reorganizing an index defragments the leaf level of clustered and nonclustered indexes on tables and
views by physically reordering the leaf-level pages to match the logical order (left to right) of the leaf nodes.
Having the pages in order improves index-scanning performance. The index is reorganized within the
existing pages allocated to it; no new pages are allocated.
Rebuilding an index drops the index and creates a new one. In doing this, fragmentation is removed, disk
space is reclaimed by compacting the pages using the specified or existing fill factor setting, and the index
rows are reordered in contiguous pages (allocating new pages as needed). This can improve disk
performance by reducing the number of page reads required to obtain the requested data.
You can use the CREATE INDEX with the DROP_EXISTING clause or ALTER INDEX with the REBUILD
clause statements to set the fill-factor value for individual indexes.
EXEC sys.sp_configure ‘fill factor (%)’, ’60′; will modify the server default fill factor value.
QUESTION 6
You have a table named dbo.Customers. The table was created by using the following Transact-SQL
statement:
CREATE TABLE dbo.Customers
(
CustomerID int IDENTITY(1,1) PRIMARY KEY CLUSTERED,
AccountNumber nvarchar(25) NOT NULL,
FirstName nvarchar(50) NOT NULL,
LastName nvarchar(50) NOT NULL,
AddressLine1 nvarchar(255) NOT NULL,
AddressLine2 nvarchar(255) NOT NULL,
City nvarchar(50) NOT NULL,
StateProvince nvarchar(50) NOT NULL,
Country nvarchar(50) NOT NULL,
PostalCode nvarchar(50) NOT NULL,
CreateDate datetime NOT NULL DEFAULT(GETDATE()),
ModifiedDate datetime NOT NULL DEFAULT(GETDATE())
)
You create a stored procedure that includes the AccountNumber, Country, and StateProvince columns from
the dbo.Customers table. The stored procedure accepts a parameter to filter the output on the
AccountNumber column. You need to optimize the performance of the stored procedure. You must not
change the existing structure of the table. Which Transact-SQL statement should you use?
A. CREATE STATISTICS ST_Customer_AccountNumber ON dbo.Customer (AccountNumber) WITH
FULLSCAN;
B. CREATE CLUSTERED INDEX IX_Customer_AccountNumber ON dbo.Customer (AccountNumber);
C. CREATE NONCLUSTERED INDEX IX_Customer_AccountNumber ON dbo.Customer
(AccountNumber) WHERE AccountNumber = ”;
D. CREATE NONCLUSTERED INDEX IX_Customer_AccountNumber ON dbo.Customer
(AccountNumber) INCLUDE (Country, StateProvince);
Correct Answer: D
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 7
You have a table named Customer.
You need to ensure that customer data in the table meets the following requirements:
credit limit must be zero unless customer identification has been verified.
credit limit must be less than 10,000.
Which constraint should you use?
A. CHECK (CreditLimt BETWEEN 1 AND 10000)
B. CHECK (Verified = 1 AND CreditLimt BETWEEN 1 AND 10000)
C. CHECK ((CreditLimt = 0 AND Verified = 0) OR (CreditLimt BETWEEN 1 AND 10000 AND Verified = 1))
D. CHECK ((CreditLimt = 0 AND Verified = 0) AND (CreditLimt BETWEEN 1 AND 10000 AND Verified =
1))
Correct Answer: C
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 8
You have a table named AccountsReceivable. The table has no indexes. There are 75,000 rows in the
table. You have a partition function named FG_AccountData. The AccountsReceivable table is defined in
the following Transact-SQL statement:
CREATE TABLE AccountsReceivable (
column_a INT NOT NULL,
column_b VARCHAR(20) NULL)
ON [PRIMARY];
You need to move the AccountsReceivable table from the PRIMARY file group to FG_AccountData. Which
Transact-SQL statement should you use?
A. CREATE CLUSTERED INDEX idx_AccountsReceivable ON AccountsReceivable(column_a) ON
[FG_AccountData];
B. CREATE NONCLUSTERED INDEX idx_AccountsReceivable ON AccountsReceivable(column_a) ON
[FG_AccountData];
C. CREATE CLUSTERED INDEX idx_AccountsReceivable ON AccountsReceivable(column_a) ON
FG_AccountData(column_a);
D. CREATE NONCLUSTERED INDEX idx_AccountsReceivable ON AccountsReceivable(column_a) ON
FG_AccountData(column_a);
Correct Answer: C
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 9
You have a SQL Server 2008 database named Contoso with a table named Invoice. The primary key of the
table is InvoiceId, and it is populated by using the identity property. The Invoice table is related to the
InvoiceLineItem table. You remove all constraints from the Invoice table during a data load to increase load
speed. You notice that while the constraints were removed, a row with InvoiceId = 10 was removed from the
database. You need to re-insert the row into the Invoice table with the same InvoiceId value. Which
Transact-SQL statement should you use?
A. INSERT INTO Invoice (InvoiceId, … VALUES (10, …
B. SET IDENTITY_INSERT Invoice ON;
INSERT INTO Invoice (InvoiceId, …
VALUES (10, …
SET IDENTITY_INSERT Invoice OFF;
C. ALTER TABLE Invoice;
ALTER COLUMN InvoiceId int;
INSERT INTO Invoice (InvoiceId, …
VALUES (10, …
D. ALTER DATABASE Contoso SET SINGLE_USER;
INSERT INTO Invoice (InvoiceId, …
VALUES (10, …
ALTER DATABASE Contoso SET MULTI_USER;
Correct Answer: B
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 10
You are developing a new database. The database contains two tables named SalesOrderDetail and
Product.
You need to ensure that all products referenced in the SalesOrderDetail table have a corresponding record
in the Product table.
Which method should you use?
A. JOIN
B. DDL trigger
C. Foreign key constraint
D. Primary key constraint
Correct Answer: C
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 11
You are creating a table that stores the GPS location of customers.
You need to ensure that the table allows you to identify customers within a specified sales boundary and to
calculate the distance between a customer and the nearest store.
Which data type should you use?
A. geometry
B. geography
C. nvarchar(max)
D. varbinary(max) FILESTREAM
Correct Answer: B
Section: Section 1
Explanation
Explanation/Reference:
The GEOGRAPHY data type is used to store ellipsoidal (round-earth) data. It is used to store latitude and
longitude coordinates that represent points, lines, and polygons on the earth’s surface. For example, GPS
data that represents the lay of the land is one example of data that can be stored in the GEOGRAPHY data
type.
QUESTION 12
You plan to add a new column named SmallKey to the Sales.Product table that will be used in a
unique constraint. You are required to ensure that the following information is applied when adding the
new column:
‘a1′ and ‘A1′ are treated as different values
‘a’ and ‘A’ sort before ‘b’ and ‘B’ in an ORDER BY clause You need to select the collation that meets the
requirements for the new column. Which collation should you select?
A. Latin1_General_BIN
B. SQL_Latin1_General_CP1_CI_AI
C. SQL_Latin1_General_CP1_CI_AS
D. SQL_Latin1_General_CP1_CS_AS
Correct Answer: D
Section: Section 1
Explanation
Explanation/Reference:
SQL Server Collation Name consists of several parts, one of them is responsible for CaseSensitivity – CI
specifies case-insensitive, CS specifies case-sensitive.
BIN specifies the binary sort order to be used.
So, because we want case-sensitive location, B and C are not suitable. Latin1_General_BIN use binary sort
order, but we want linguistical sort order (according to rules of language), not based on the code point
values of characters.
QUESTION 13
You have multiple tables that represent properties of the same kind of entities. The property values are
comprised of text, geometry, varchar(max), and user-defined types specified as ‘bit NOT NULL’ data types.
You plan to consolidate the data from multiple tables into a single table. The table will use semi-structured
storage by taking advantage of the SPARSE option.
You are tasked to identify the data types that are compatible with the SPARSE option.
Which data type is compatible with the SPARSE option?
A. text
B. geometry
C. varchar(max)
D. A user-defined type defined as ‘bit NOT NULL’
Correct Answer: C
Section: Section 1
Explanation
Explanation/Reference:
Sparse columns are ordinary columns that have an optimized storage for null values. Sparse columns
reduce the space requirements for null values at the cost of more overhead to retrieve nonnull values.
The following data types cannot be specified as SPARSE:
geography
geometry
image
ntext
text
timestamp
user-defined data types
QUESTION 14
You currently store date information in two columns. One column contains the date in local time and one
column contains the difference between local time and UTC time. You need to store this data in a single
column.
Which data type should you use?
A. time
B. datetime2
C. datetime2(5)
D. datetimeoffset
Correct Answer: D
Section: Section 1
Explanation
Explanation/Reference:
datetimeoffset defines a date that is combined with a time of a day that has time zone awareness.
QUESTION 15
You have two partitioned tables named Transaction and TransactionHistory.
You need to archive one of the partitions of the Transaction table to the TransactionHistory table.
Which method should you use?
A. ALTER TABLE …
SWITCH …
B. INSERT … SELECT …; TRUNCATE TABLE
C. ALTER PARTITION FUNCTION … MERGE …
D. ALTER PARTITION FUNCTION …
SPLIT …
Correct Answer: B
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 16
You are creating a new table in a database. Your business requires you to store data in the table for only
seven days.
You need to implement a partitioned table to meet this business requirement.
Which tasks should you complete?
A. Create the partition function
Create the partition scheme
Create the table
B. Create the partition function
Create the table
Create a filtered index
C. Add a secondary file to the primary filegroups
Create the table
Create the distributed partitioned view
D. Create the partition function
Create the partition scheme
Create the distributed partitioned view
Correct Answer: A
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 17
You need to alter stored procedures to use the WITH RECOMPILE option. Which types of stored
procedures should you alter? (Each correct answer represents a complete solution. Choose two.)
A. Stored procedures implemented from CLR assemblies.
B. Stored procedures that require the FOR REPLICATION option.
C. Stored procedures that require the WITH ENCRYPTION option.
D. Stored procedures that contain queries that use the OPTION (RECOMPILE) hint.
Correct Answer: CD
Section: Section 1
Explanation
Explanation/Reference:
As a database is changed by such actions as adding indexes or changing data in indexed columns, the
original query plans used to access its tables should be optimized again by recompiling them. This
optimization happens automatically the first time a stored procedure is run after Microsoft SQL Server is
restarted. It also occurs if an underlying table used by the stored procedure changes. But if a new index is
added from which the stored procedure might benefit, optimization does not happen until the next time the
stored procedure is run after SQL Server is restarted. In this situation, it can be useful to force the stored
procedure to recompile the next time it executes.
SQL Server provides three ways to force a stored procedure to recompile:
The sp_recompile system stored procedure forces a recompile of a stored procedure the next time that
it is run. It does this by deleting the existing plan from the procedure cache forcing a new plan to be
created the next time that the procedure is run.
Creating a stored procedure that specifies the WITH RECOMPILE option in its definition indicates that
SQL Server does not cache a plan for this stored procedure; the stored procedure is recompiled every
time that it is executed. Use of this option is uncommon and causes the stored procedure to execute
more slowly, because the stored procedure must be recompiled every time that it is executed.
You can force the stored procedure to be recompiled by specifying the WITH RECOMPILE option when
you execute the stored procedure.
A. CREATE and ALTER PROCEDURE syntax for CLR Stored Procedure does not have RECOMPILE
option.
B. The RECOMPILE option is ignored for procedures created with FOR REPLICATION.
C. ENCRYPTION option and RECOMPILE option can go together.
QUESTION 18
You have a SQL Server database. The database contains two schemas named Marketing and Sales.
The Marketing schema is owned by a user named MarketingManager. The Sales schema is owned by a
user named SalesManager.
A user named John must be able to access the Sales.Orders table by using a stored procedure named
Marketing.GetSalesSummary.
John is not granted a SELECT permission on the Sales.Orders table.
A user named SalesUser does have SELECT permission on the Sales.Orders table.
You need to implement appropriate permissions for John and the stored procedure Marketing.
GetSalesSummary.
What should you do?
A. Marketing.GetSalesSummary should be created by using the EXECUTE AS ‘SalesUser’ clause.
John should be granted EXECUTE permission on Marketing.GetSalesSummary.
B. Marketing.GetSalesSummary should be created by using the EXECUTE AS OWNER clause.
John should be granted EXECUTE WITH GRANT OPTION on Marketing.GetSalesSummary.
C. Marketing.GetSalesSummary should be created by using the EXECUTE AS CALLER clause.
John should be granted IMPERSONATE permission for the user named SalesUser.
D. Marketing.GetSalesSummary should be created without an EXECUTE AS clause.
John should be granted SELECT permission on the Sales.Orders table.
Correct Answer: A
Section: Section 1
Explanation
Explanation/Reference:
1. When the module is executed, the Database Engine first verifies that the user executing the module has
EXECUTE permission on the module. So John should be granted EXECUTE permission on Marketing.
GetSalesSummary stored procedure.
2. Additional permissions checks on objects that are accessed by the module are performed against the
user account specified in the EXECUTE AS clause. The user executing the module is, in effect,
impersonating the specified user. Because John is not granted a SELECT permission on the Sales.
Orders table which is referenced by the stored procedure, EXECUTE AS CALLER is not suitable.
(CALLER specifies the statements inside the module are executed in the context of the caller of the
module. The user executing the module must have appropriate permissions not only on the module
itself, but also on any database objects that are referenced by the module.) Because the user named
SalesUser DOES have SELECT permission on the Sales.Orders table, he can be specified in
EXECUTE AS clause. It means that Marketing.GetSalesSummary stored procedure should be created
by using the EXECUTE AS ‘SalesUser’ clause.
QUESTION 19
You need to create a stored procedure that accepts a table-valued parameter named @Customers.
Which code segment should you use?
A. CREATE PROCEDURE AddCustomers (@Customers varchar(max))
B. CREATE PROCEDURE AddCustomers (@Customers Customer READONLY)
C. CREATE PROCEDURE AddCustomers (@Customers CustomerType OUTPUT)
D. CREATE PROCEDURE ADDCUSTOMERS
(@Customers varchar (max)) AS EXTERNAL NAME Customer.Add.NewCustomer
Correct Answer: B
Section: Section 1
Explanation
Explanation/Reference:
To create and use table-valued parameters, follow these steps:
1. Create a table type and define the table structure.
/* Create a table type. */
CREATE TYPE LocationTableType AS TABLE
( LocationName VARCHAR(50)
, CostRate INT );
GO
2. Declare a routine that has a parameter of the table type.
/* Create a procedure to receive data for the table-valued parameter. */
CREATE PROCEDURE usp_InsertProductionLocation
@TVP LocationTableType READONLY
AS
SET NOCOUNT ON
INSERT INTO [AdventureWorks2008R2].[Production].[Location]
([Name]
,[CostRate]
,[Availability]
,[ModifiedDate])
SELECT *, 0, GETDATE()
FROM @TVP;
GO
3. Declare a variable of the table type, and reference the table type.
/* Declare a variable that references the type. */
DECLARE @LocationTVP
AS LocationTableType;
4. Fill the table variable by using an INSERT statement.
/* Add data to the table variable. */
INSERT INTO @LocationTVP (LocationName, CostRate)
SELECT [Name], 0.00
FROM
[AdventureWorks2008R2].[Person].[StateProvince];
5. After the table variable is created and filled, you can pass the variable to a routine.
/* Pass the table variable data to a stored procedure. */
EXEC usp_InsertProductionLocation @LocationTVP;
Restrictions
Table-valued parameters must be passed as input READONLY parameters to Transact-SQL routines. You
cannot perform DML operations such as UPDATE, DELETE, or INSERT on a table-valued parameter in the
body of a routine.
QUESTION 20
You have a computed column that is implemented with a user-defined function. The user-defined function
returns a formatted account number. The column must be indexed to provide adequate search
performance.
You plan to create an index on the computed column. You need to identify the valid combination of
ObjectPropertyEX values for the user-defined function.
Which combination should you use?
A. IsDeterministic = True
IsSystemVerified = True
UserDataAccess = False
SystemDataAccess = False
B. IsDeterministic = True
IsSystemVerified = True
IsPrecise = True
IsTableFunction = True
C. IsDeterministic = False
IsSystemVerified = True
UserDataAccess = False
SystemDataAccess = False
D. IsDeterministic = False
IsSystemVerified = True
IsPrecise = True
SystemDataAccess = False
Correct Answer: A
Section: Section 1
Explanation
Explanation/Reference:
QUESTION 21
You need to identify, within a given clause, if the month of February will contain 29 days for a specified
year.
Which object should you use?
A. DML trigger
B. Stored procedure
C. Table-valued function
D. Scalar-valued function
Correct Answer: D
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 22
You are creating a function that references a table.
You need to prevent the table from being dropped.
Which option should you use when you create the function?
A. WITH ENCRYPTION
B. WITH EXECUTE AS
C. WITH SCHEMABINDING
D. WITH RETURNS NULL ON NULL INPUT
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 23
You are developing a database using Microsoft SQL Server 2008. The database contains the tables shown
in the exhibit. You are required to prevent parts from being deleted if they belong to a kit. If a part belongs to
a kit, the delete should not occur and the IsDeleted column for the row should be changed to ‘True’. Parts
can be deleted if they do not belong to a kit. You have the following Transact-SQL statement to be used in a
trigger:
UPDATE p
SET IsDeleted = 1
FROM KitPart kp
JOIN deleted d ON kp.PartID = d.PartID
JOIN Part p ON kp.PartID = p.PartID;
DELETE FROM p
FROM Part p
JOIN deleted d ON p.PartID = d.PartID
LEFT OUTER JOIN KitPart kp ON p.PartID = kp.PartID
WHERE kp.KitID IS NULL;
You need to implement the Transact-SQL statement in a trigger. Which trigger syntax should you use?
Exhibit:
A. CREATE TRIGGER tr_Part_d ON Part AFTER DELETE AS BEGIN
END
B. CREATE TRIGGER tr_Part_d ON Part INSTEAD OF DELETE AS BEGIN
END
C. CREATE TRIGGER tr_KitPart_d ON KitPart AFTER DELETE AS BEGIN
END
D. CREATE TRIGGER tr_KitPart_d ON KitPart INSTEAD OF DELETE AS BEGIN
END
Correct Answer: B
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 24
You have a third-party application that inserts data directly into a table.
You add two new columns to the table. These columns cannot accept NULL values and cannot use default
constraints.
You need to ensure that the new columns do not break the third-party application.
What should you do?
A. Create a DDL trigger.
B. Create a stored procedure.
C. Create an AFTER INSERT trigger.
D. Create an INSTEAD OF INSERT trigger.
Correct Answer: D
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 25
Your database contains two tables named Order and OrderDetails that store order information. They relate
to each other using the OrderID column in each table. Your business requires that the LastModifiedDate
column in the Order table must reflect the date and time when a change is made in the OrderDetails table
for the related order.
You need to create a trigger to implement this business requirement.
Which Transact-SQL statement should you use?
A. CREATE TRIGGER [uModDate] ON [OrderDetails]
INSTEAD OF UPDATE FOR REPLICATION
AS
UPDATE [Order]
SET [LastModifiedDate] = GETDATE()
FROM inserted
WHERE inserted.[OrderID] = [Order].[OrderID];
B. CREATE TRIGGER [uModDate] ON [Order]
INSTEAD OF UPDATE NOT FOR REPLICATION
AS
UPDATE [Order]
SET [LastModifiedDate] = GETDATE()
FROM inserted
WHERE inserted.[OrderID] = [Order].[OrderID];
C. CREATE TRIGGER [uModDate] ON [Order]
AFTER UPDATE FOR REPLICATION
AS
UPDATE [Order]
SET [LastModifiedDate] = GETDATE()
FROM inserted
WHERE inserted.[OrderID] = [Order].[OrderID];
D. CREATE TRIGGER [uModDate] ON [OrderDetails]
AFTER UPDATE NOT FOR REPLICATION
AS
UPDATE [Order]
SET [LastModifiedDate] = GETDATE()
FROM inserted
WHERE inserted.[OrderID] = [Order].[OrderID];
Correct Answer: D
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 26
You need to ensure that tables are not dropped from your database. What should you do?
A. Create a DDL trigger that contains COMMIT.
B. Create a DML trigger that contains COMMIT.
C. Create a DDL trigger that contains ROLLBACK.
D. Create a DML trigger that contains ROLLBACK.
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
DDL triggers can execute either when a DDL statement is executed or when the user logs on to the SQL
Server instance.
DDL triggers can be scoped at either the database or instance level. To scope a DDL trigger at the instance
level, you use the ON ALL SERVER option. To scope a DDL trigger at the database level, you use the ON
DATABASE option.
The following is an example of a DDL trigger:
CREATE TRIGGER tddl_tabledropalterprevent
ON DATABASE
FOR DROP_TABLE, ALTER_TABLE
AS
PRINT ‘You are attempting to drop or alter tables in production!’
ROLLBACK;
Almost all DDL commands run within the context of a transaction. Because a DDL trigger also runs within
the same transaction context, any DDL statement running in the context of a transaction can be rolled back.
QUESTION 27
You are responsible for a SQL Server database. You require the tables to be added or altered only on the
first day of the month. You need to ensure that if the tables are attempted to be modified or created on any
other day, an error is received and the attempt is not successful.
Which Transact-SQL statement should you use?
A. CREATE TRIGGER TRG_TABLES_ON_FIRST
ON DATABASE FOR CREATE_TABLE
AS
IF DATEPART(day,getdate())>1
BEGIN
RAISERROR (‘Must wait til next month.’, 16, 1)
END
B. CREATE TRIGGER TRG_TABLES_ON_FIRST ON DATABASE FOR CREATE_TABLE,
ALTER_TABLE AS
IF DATEPART(day,getdate())>1
BEGIN
RAISERROR (‘Must wait til next month.’, 16, 1)
END
C. CREATE TRIGGER TRG_TABLES_ON_FIRST ON DATABASE FOR CREATE_TABLE,
ALTER_TABLE AS
IF DATEPART(day,getdate())>1
BEGIN
ROLLBACK
RAISERROR (‘Must wait til next month.’, 16, 1)
END
D. CREATE TRIGGER TRG_TABLES_ON_FIRST ON ALL SERVER FOR ALTER_DATABASE AS
IF DATEPART(day,getdate())>1
BEGIN
ROLLBACK
RAISERROR (‘Must wait til next month.’, 16, 1)
END
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 28
You have a single CLR assembly in your database. The assembly only references blessed assemblies from
the Microsoft .NET Framework and does not access external resources.
You need to deploy this assembly by using the minimum required permissions. You must ensure that your
database remains as secure as possible.
Which options should you set?
A. PERMISSION_SET = SAFE
TRUSTWORTHY ON
B. PERMISSION_SET = SAFE
TRUSTWORTHY OFF
C. PERMISSION_SET = UNSAFE
TRUSTWORTHY ON
D. PERMISSION_SET = EXTERNAL_ACCESS
TRUSTWORTHY OFF
Correct Answer: B
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 29
You have created an assembly that utilizes unmanaged code to access external resources.
You need to deploy the assembly with the appropriate permissions.
Which permission set should you use?
A. SAFE
B. UNSAFE
C. EXTERNAL_ACCESS
D. Default permission set
Correct Answer: B
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 30
You have tables named Products and OrderDetails. The Products table has a foreign key relationship
with the OrderDetails table on the ProductID column. You have the following Transact-SQL batch:
BEGIN TRY
BEGIN TRANSACTION
DELETE FROM Products WHERE ProductID = 5;
BEGIN TRANSACTION
INSERT INTO OrderDetails
( OrderID, ProductID, Quantity )
VALUES
( 1234, 5, 12 );
COMMIT TRANSACTION
COMMIT TRANSACTION
END TRY
BEGIN CATCH ROLLBACK TRANSACTION PRINT ERROR_MESSAGE();
END CATCH
You need to analyze the result of executing this batch. What should be the expected outcome?
A. –The product will be deleted from the Products table.
–The order details will be inserted into the OrderDetails table.
B. –The product will be deleted from the Products table.
–The order details will not be inserted into the OrderDetails table.
C. –The product will not be deleted from the Products table.
–The order details will be inserted into the OrderDetails table.
D. –The product will not be deleted from the Products table.
–The order details will not be inserted into the OrderDetails table.
Correct Answer: D
Section: Section 2
Explanation
Explanation/Reference:
ROLLBACK { TRAN | TRANSACTION }
[ transaction_name | @tran_name_variable
| savepoint_name | @savepoint_variable ]
[ ; ]
transaction_name
Is the name assigned to the transaction on BEGIN TRANSACTION. When nesting transactions,
transaction_name must be the name from the outermost BEGIN TRANSACTION statement.
savepoint_name
Is savepoint_name from a SAVE TRANSACTION statement. Use savepoint_name when a conditional
rollback should affect only part of the transaction.
ROLLBACK TRANSACTION without a savepoint_name or transaction_name rolls back to the beginning of
the transaction. When nesting transactions, this same statement rolls back all inner transactions to the
outermost BEGIN TRANSACTION statement. In both cases, ROLLBACK TRANSACTION decrements the
@@TRANCOUNT system function to 0. ROLLBACK TRANSACTION savepoint_name does not decrement
@@TRANCOUNT.
A transaction cannot be rolled back after a COMMIT TRANSACTION statement is executed, except when
the COMMIT TRANSACTION is associated with a nested transaction that is contained within the
transaction being rolled back. In this instance, the nested transaction will also be rolled back, even if you
have issued a COMMIT TRANSACTION for it.
SQL Server 2008 error handling best practice
CREATE PROCEDURE SaveTranExample
@InputCandidateID INT
AS
– Detect whether the procedure was called from an active transaction and
save that for later use.
– In the procedure, @hasOuterTransaction = 0 means there was no active
transaction
– and the procedure started one.
– @hasOuterTransaction > 0 means an active transaction was started before
the
– procedure was called.
DECLARE @hasOuterTransaction BIT = CASE WHEN @@TRANCOUNT > 0 THEN 1 ELSE 0
END;
– Save points need unique names if modules can nest otherwise you can
rollback
– to the wrong save point. The solution is to use a GUID to name the save
points.
DECLARE @rollbackPoint nchar(32) = REPLACE(CONVERT(NCHAR(36), NEWID()),
N’-‘, N”);
IF @hasOuterTransaction > 0
BEGIN
– Procedure called when there is an active transaction.
– Create a savepoint to be able to roll back only the work done in the
procedure if there is an error.
SAVE TRANSACTION @rollbackPoint;
END
ELSE
– Procedure must start its own transaction.
BEGIN TRANSACTION @rollbackPoint;
– Modify database.
BEGIN TRY
– Do work;
DELETE HumanResources.JobCandidate
WHERE JobCandidateID = @InputCandidateID;
– Get here if no errors; must commit
– any transaction started in the
– procedure, but not commit a transaction
– started before the transaction was called.
IF @hasOuterTransaction = 0
BEGIN
– @hasOuterTransaction = 0 means no transaction was started before
the procedure was called.
– The procedure must commit the transaction it started.
COMMIT TRANSACTION;
END
END TRY
BEGIN CATCH
– An error occurred;
– If the transaction is still valid
IF XACT_STATE() = 1
– The XACT_STATE function can return the following values:
– 1 An open transaction exists that can be either committed or rolled
back.
– 0 There is no open transaction.
– –1 An open transaction exists, but it is in a doomed state. Due to the
type of error that was raised, the transaction can only be rolled back.
BEGIN
– Because the syntax for ROLLBACK TRANSACTION is the same for the
transaction and for a savepoint
– (ROLLBACK TRANSACTION [ transaction_name | @tran_name_variable |
savepoint_name | @savepoint_variable ])
– we can write the following:
ROLLBACK TRANSACTION @rollbackPoint;
– In case @rollbackPoint has the name of a transaction, roll back to the
beginning of the transaction.
– In case @rollbackPoint has the name of a savepoint, roll back to the
savepoint.
END;
ELSE IF XACT_STATE() = -1
BEGIN
IF @hasOuterTransaction = 0
BEGIN
– Transaction started in procedure.
– Roll back complete transaction.
ROLLBACK TRANSACTION;
END
– If the transaction is uncommitable, a rollback to the savepoint is
not allowed
– because the savepoint rollback writes to the log. Just return to the
caller, which
– should roll back the outer transaction.
END
– Execute Standard module error handler;
– After the appropriate rollback, echo error information to the caller.
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT @ErrorMessage = ERROR_MESSAGE();
SELECT @ErrorSeverity = ERROR_SEVERITY();
SELECT @ErrorState = ERROR_STATE();
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState — State.
);
END CATCH
GO
QUESTION 31
You are using TRY…CATCH error handling.
You need to raise an error that will pass control to the CATCH block.
Which severity level should you use?
A. 0
B. 9
C. 10
D. 16
Correct Answer: D
Section: Section 2
Explanation
Explanation/Reference:
A TRY…CATCH construct catches all execution errors that have a severity higher than 10 that do not close
the database connection.
Severity levels from 20 through 25 are considered fatal. If a fatal severity level is encountered, the client
connection is terminated after receiving the message, and the error is logged in the error and application
logs.
Severity levels less than 0 are interpreted as 0. Severity levels greater than 25 are interpreted as 25.
QUESTION 32
You have a table named Orders. You have been tasked to modify your company’s main database to
remove all inactive order rows. You are developing a stored procedure that will enable you to delete these
rows. You have written the following code segment to accomplish this task. (Line numbers are included for
reference only.)
01 BEGIN TRY
02 DECLARE @RowCount INT = 1000
03 WHILE @RowCount = 1000
04 BEGIN
05 DELETE TOP (1000) FROM Orders WHERE Status = ‘Inactive';
06 SET @RowCount = @@ROWCOUNT
07 …
08 END
09 END TRY
10 BEGIN CATCH
11 PRINT ERROR_MESSAGE()
12 END CATCH
You need to insert a Transact-SQL statement that will notify you immediately after each batch of rows is
deleted. Which Transact-SQL statement should you insert at line 07?
A. RAISERROR (‘Deleted %i rows’, 6, 1, @RowCount)
B. RAISERROR (‘Deleted %i rows’, 16, 1, @RowCount)
C. RAISERROR (‘Deleted %i rows’, 10, 1, @RowCount) WITH NOWAIT
D. RAISERROR (‘Deleted %i rows’, 11, 1, @RowCount) WITH NOWAIT
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
RAISERROR can be used as an alternative to PRINT to return messages to calling applications.
Because RAISERROR run with a severity of 11 to 19 in a TRY block transfers control to the associated
CATCH block, specify a severity of 10 or lower to use RAISERROR to return a message from a TRY block
without invoking the CATCH block.
NOWAIT option sends messages immediately to the client.
QUESTION 33
You have a transaction that uses the repeatable read isolation level.
This transaction causes frequent blocking problems. You need to reduce blocking. You also need to avoid
dirty reads and non-repeatable reads.
Which transaction isolation level should you use?
A. SNAPSHOT
B. SERIALIZABLE
C. READ COMMITTED
D. READ UNCOMMITTED
Correct Answer: A
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 34
You are writing a batch that contains multiple UPDATE statements to modify existing products. You have
placed these updates into one explicit transaction. You need to set an option at the beginning of the
transaction to roll back all changes if any of the updates in the transaction fail. Which option should you
enable?
A. ARITHABORT
B. XACT_ABORT
C. IMPLICIT_TRANSACTIONS
D. REMOTE_PROC_TRANSACTIONS
Correct Answer: B
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 35
You have a table named JobCandidate. You are tasked to delete a row in the JobCandidate table. You
need to write a transaction that allows the database to be restored to the exact point the record was deleted
without knowing the time of execution. Which query should you use?
A. BEGIN TRANSACTION
DELETE FROM JobCandidate
WHERE JobCandidateID = 10;
COMMIT TRANSACTION;
B. BEGIN TRANSACTION WITH MARK N’Deleting a Job Candidate';
DELETE FROM JobCandidate
WHERE JobCandidateID = 10;
COMMIT TRANSACTION;
C. BEGIN TRANSACTION Delete_Candidate WITH MARK
DELETE FROM JobCandidate
WHERE JobCandidateID = 10;
COMMIT TRANSACTION Delete_Candidate;
D. DECLARE @CandidateName varchar(50) = ‘Delete_Candidate’
BEGIN TRANSACTION @CandidateName
DELETE FROM JobCandidate
WHERE JobCandidateID = 10;
COMMIT TRANSACTION @CandidateName;
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
BEGIN { TRAN | TRANSACTION }
[ { transaction_name | @tran_name_variable }
[ WITH MARK [ 'description' ] ]
]
[ ; ]
WITH MARK [ 'description' ] – specifies that the transaction is marked in the log. description is a string that
describes the mark.
If WITH MARK is used, a transaction name must be specified. When restoring a database to an earlier
state, the marked transaction can be used in place of a date and time.
The mark is placed in the transaction log only if the database is updated by the marked transaction.
Transactions that do not modify data are not marked.
BEGIN TRAN new_name WITH MARK can be nested within an already existing transaction that is not
marked. Upon doing so, new_name becomes the mark name for the transaction, despite the name that the
transaction may already have been given.
QUESTION 36
You have the following table named Sales.
You need to return sales data ordered by customer name and date of sale. For each customer, the most
recent sale must be listed first.
Which query should you use?
A. SELECT CustomerName, SalesDate
FROM Sales
ORDER BY CustomerName, SalesDate;
B. SELECT CustomerName, SalesDate
FROM Sales
ORDER BY SalesDate DESC, CustomerName;
C. SELECT CustomerName, SalesDate
FROM Sales
ORDER BY CustomerName, SalesDate DESC;
D. SELECT CustomerName, SalesDate
FROM Sales ORDER BY CustomerName DESC;
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 37
You have a table named Sales.SalesOrderHeader and a table named Person.Person. You are tasked to
write a query that returns SalesOrderID and SalesPersonName that have an OrderDate greater than
20040101. SalesPersonName should be made up by concatenating the columns named FirstName and
LastName from the table named Person.Person. You need to write a query to return data, sorted in
alphabetical order, by the concatenation of FirstName and LastName. Which Transact-SQL statement
should you use?
A. SELECT SalesOrderID, FirstName + ‘ ‘ + LastName as SalesPersonName FROM Sales.
SalesOrderHeader H
JOIN Person.Person P on BusinessEntityID = H.SalesPersonID
WHERE OrderDate > ‘20040101’ ORDER BY FirstName ASC, LastName ASC
B. SELECT SalesOrderID, FirstName + ‘ ‘ + LastName as SalesPersonName FROM Sales.
SalesOrderHeader H
JOIN Person.Person P on BusinessEntityID = H.SalesPersonID
WHERE OrderDate > ‘20040101’ ORDER BY FirstName DESC, LastName DESC
C. SELECT SalesOrderID, FirstName +’ ‘ + LastName as SalesPersonName FROM Sales.
SalesOrderHeader H
JOIN Person.Person P on BusinessEntityID = H.SalesPersonID
WHERE OrderDate > ‘20040101’ ORDER BY SalesPersonName ASC
D. SELECT SalesOrderID, FirstName + ‘ ‘ + LastName as SalesPersonName FROM Sales.
SalesOrderHeader H
JOIN Person.Person P on BusinessEntityID = H.SalesPersonID
WHERE OrderDate > ‘20040101’ ORDER BY SalesPersonName DESC
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 38
You have a table named Sales.PotentialClients. This table contains a column named EmailAddress.
You are tasked to develop a report that returns valid “.com” email addresses from Sales.PotentialClients.
A valid email address must have at least one character before the @ sign, and one character after the @
sign and before the “.com.”
You need to write a Transact-SQL statement that returns data to meet the business requirements.
Which Transact-SQL statement should you use?
A. select * from Sales.PotentialClients
where EmailAddress like ‘_%@_%.com’
B. select * from Sales.PotentialClients
where EmailAddress like ‘%@%.com’
C. select * from Sales.PotentialClients
where EmailAddress like ‘_%@_.com’
D. select * from Sales.PotentialClients
where EmailAddress like ‘%@%[.]com’
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
If “at least” expression refer to both “one character before…” and “one character after…”, then A is correct.
If “at least” expression refer to only “one character before…” which seems the case, then C is correct.
QUESTION 39
You have a table named Orders. OrderID is defined as an IDENTITY(1,1). OrderDate has a default value of
1.
You need to write a query to insert a new order into the Orders table for CustomerID 45 with today’s date
and a cost of 89.00.
Which statement should you use?
Exhibit:
A. INSERT INTO Orders (CustomerId, OrderDate, Cost) VALUES (45, DEFAULT, 89.00);
B. INSERT INTO Orders (OrderID, CustomerId, OrderDate, Cost) VALUES (1, 45, DEFAULT, 89.00);
C. INSERT INTO Orders (CustomerId, OrderDate, Cost) VALUES (45, CURRENT_TIMESTAMP, 89.00);
D. INSERT INTO Orders (OrderID, CustomerId, OrderDate, Cost) VALUES (1, 45,
CURRENT_TIMESTAMP, 89.00);
Correct Answer: C
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 40
You have the following two tables.
The foreign key relationship between these tables has CASCADE DELETE enabled.
You need to remove all records from the Orders table.
Which Transact-SQL statement should you use?
Exhibit:
A. DROP TABLE Orders
B. DELETE FROM Orders
C. TRUNCATE TABLE Orders
D. DELETE FROM OrderDetails
Correct Answer: B
Section: Section 2
Explanation
Explanation/Reference:
QUESTION 41
You have been tasked to delete 1000 rows from a table named NewWidgets. There are 2000 rows in which
the column ToBeDeleted set to 1.
You need to write a Transact-SQL batch that will delete exactly 1000 rows.
Which Transact-SQL batch should you use?
A. DELETE TOP (1000) dbo.NewWidgets
WHERE ToBeDeleted = 1;
B. DECLARE @BatchSize INT = 10;
WHILE (@BatchSize = 10)
DELETE TOP (@BatchSize) dbo.NewWidgets
WHERE ToBeDeleted = 1;
C. DELETE TOP (SELECT COUNT(*) FROM dbo.NewWidgets WHERE ToBeDeleted = 1)
FROM dbo.NewWidgets w
WHERE w.ToBeDeleted = 1;
D. DECLARE @TotalRowCount INT = 0;
WHILE (@TotalRowCount <= 1000)
BEGIN
DELETE TOP (10) dbo.NewWidgets
WHERE ToBeDeleted = 1;
SET @TotalRowCount += @@ROWCOUNT;
END
Correct Answer: A
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 42
You have tables named Sales.SalesOrderDetails and Sales.SalesOrderHeader.
You have been tasked to update the discount amounts for the sales of a particular salesperson. You need
to set UnitPriceDiscount to 0.1 for all entries in Sales.SalesOrderDetail that only correspond to
SalesPersonID 290. Which Transact-SQL statement should you use?
A. UPDATE d
SET UnitPriceDiscount = .1
FROM Sales.SalesOrderDetail d
INNER JOIN Sales.SalesOrderHeader h ON h.SalesOrderID = d.SalesOrderID
WHERE h.SalesPersonID = 290;
B. UPDATE Sales.SalesOrderDetail
SET UnitPriceDiscount = .1
FROM Sales.SalesOrderHeader h
WHERE h.SalesPersonID = 290;
C. UPDATE Sales.SalesOrderDetail
SET UnitPriceDiscount = .1
WHERE EXISTS (
SELECT * FROM Sales.SalesOrderHeader h
WHERE h.SalesPersonID = 290);
D. UPDATE Sales.SalesOrderDetail
SET UnitPriceDiscount = .1 FROM Sales.SalesOrderDetail d
WHERE EXISTS (
SELECT * FROM Sales.SalesOrderHeader h
WHERE h.SalesPersonID = 290);
Correct Answer: A
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 43
You have a table named Product.
You need to increase product prices for only the vendor named Coho Winery by 10 percent and then return
a list of the products and updated prices.
Which code segment should you use?
A. UPDATE Product SET Price = Price * 1.10, ProductName = ProductName
WHERE Product.VendorName = ‘Coho Winery’
B. UPDATE Product
SET Price = Price * 1.10
OUTPUT inserted.ProductName, deleted.Price
WHERE Product.VendorName = ‘Coho Winery’
C. UPDATE Product
SET Price = Price * 1.10
OUTPUT inserted.ProductName, inserted.Price
WHERE Product.VendorName = ‘Coho Winery’
D. UPDATE Product
SET Price = Price * 1.10, VendorName = ‘Coho Winery’
OUTPUT inserted.ProductName, inserted.Price
Correct Answer: C
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 44
You have two tables named dbo.Products and dbo.PriceChange. Table dbo.Products contains ten
products. Five products are priced at $20 per unit and have PriceIncrease set to 1. The other five products
are priced at $10 per unit and have PriceIncrease set to 0.
You have the following query:
INSERT dbo.PriceChange (ProductID, Change, ChangeDate)
SELECT ProductID, inPrice -delPrice, SYSDATETIME()
FROM
(
UPDATE dbo.Products
SET Price *= 1.1
OUTPUT inserted.ProductID, inserted.Price, deleted.Price
WHERE PriceIncrease = 1 ) p (ProductID, inPrice, delPrice);
You need to predict the results of the query. Which results should the query produce?
A. Five rows are updated in dbo.Products.
Five rows are inserted into dbo.PriceChange.
B. Five rows are updated in dbo.Products.
No rows are inserted into dbo.PriceChange.
C. No rows are updated in dbo.Products.
Five rows are inserted into dbo.PriceChange.
D. No rows are updated in dbo.Products.
No rows are inserted into dbo.PriceChange.
Correct Answer: A
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 45
You have two tables named MainTable and ArchiveTable.
You need to move data older than 30 days from MainTable into ArchiveTable.
Which code segment should you use?
A. DELETE FROM MainTable
OUTPUT deleted.*
WHERE RecordDate < DATEADD(D,-30,GETDATE())
B. DELETE FROM MainTable
OUTPUT DELETED.* INTO ArchiveTable
WHERE RecordDate < DATEADD(D,-30,GETDATE())
C. INSERT INTO ArchiveTable
SELECT * FROM MainTable WHERE RecordDate < DATEADD(D,-30,GETDATE())
D. INSERT INTO ArchiveTable
SELECT * FROM MainTable WHERE RecordDate < DATEADD(D,-30,GETDATE())
DELETE FROM MainTable
Correct Answer: B
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 46
You have been tasked with creating a table named dbo.Widgets. You need to insert five rows into the dbo.
Widgets table and return WidgetID for each of the five rows that have been inserted. Which Transact-SQL
batch should you use?
A. CREATE TABLE dbo.Widgets ( WidgetID INT IDENTITY PRIMARY KEY, WidgetName VARCHAR
(25));
GO
INSERT dbo.Widgets (WidgetName)
OUTPUT inserted.WidgetID, inserted.WidgetName
VALUES (‘WidgetOne’),(‘WidgetTwo’),(‘WidgetThree’),(‘WidgetFour’),(‘WidgetFive’);
B. CREATE TABLE dbo.Widgets ( WidgetID INT IDENTITY PRIMARY KEY, WidgetName VARCHAR
(25) );
GO
INSERT dbo.Widgets (WidgetName)
VALUES (‘WidgetOne’),(‘WidgetTwo’),(‘WidgetThree’),(‘WidgetFour’),(‘WidgetFive’);
SELECT SCOPE_IDENTITY();
C. CREATE TABLE dbo.Widgets ( WidgetID UNIQUEIDENTIFIER PRIMARY KEY, WidgetName
VARCHAR(25) );
GO
INSERT dbo.Widgets (WidgetName)
VALUES (‘WidgetOne’),(‘WidgetTwo’),(‘WidgetThree’),(‘WidgetFour’),(‘WidgetFive’);
SELECT SCOPE_IDENTITY();
D. CREATE TABLE dbo.Widgets ( WidgetID UNIQUEIDENTIFIER PRIMARY KEY, WidgetName
VARCHAR(25));
GO
INSERT dbo.Widgets (WidgetName)
OUTPUT inserted.WidgetID, inserted.WidgetName
VALUES (‘WidgetOne’),(‘WidgetTwo’),(‘WidgetThree’),(‘WidgetFour’),(‘WidgetFive’);
Correct Answer: A
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 47
You have the following two tables.
Products
ProductID ProductName VendorID
1 Product1 0
2 Product2 1
3 Product3 1
4 Product4 0
ProductChanges
ProductID ProductName VendorID
1 Product1 1
2 Product2 1
3 NewProduct3 2
5 Product5 1
You execute the following statement.
MERGE Products USING ProductChanges ON (Products.ProductID = ProductChanges.
ProductID)
WHEN MATCHED AND Products.VendorID = 0 THEN DELETE WHEN MATCHED
THEN UPDATE SET Products.ProductName = ProductChanges.ProductName Products.
VendorID = ProductChanges.VendorID;
You need to identify the rows that will be displayed in the Products table. Which rows will be displayed?
A. ProductID ProductName VendorID
2 Product2 1
3 NewProduct3 2
B. ProductID ProductName VendorID
2 Product2 1
3 NewProduct3 2
4 Product4 0
C. ProductID ProductName VendorID
1 Product1 1
2 Product2 1
3 NewProduct3 2
5 Product5 1
D. ProductID ProductName VendorID
1 Product1 1
2 Product2 1
3 NewProduct3 2
4 Product4 0
5 Product5 1
Correct Answer: B
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 48
You have two tables.
A table named Student.CurrentStudents contains the names of all students enrolled for the current year.
Another table named Student.NewYearRoster contains the names of students who have enrolled for the
upcoming year.
You have been tasked to write a MERGE statement to:
Insert into Student.CurrentStudents the names of students who are enrolled for the upcoming year but not
for the current year.
Update information in Student.CurrentStudents for students who are enrolled both in the current year and in
the upcoming year.
Delete from Student.CurrentStudents the names of students who are not enrolled for the upcoming year.
You need to write the appropriate MERGE statement. Which Transact-SQL statement should you use?
A. MERGE Student.CurrentStudents AS T USING Student.NewYearRoster AS S ON S.LastName = T.
LastName AND S.FirstName = T.FirstName
WHEN MATCHED THEN UPDATE SET Address = S.Address, Age = S.Age
WHEN NOT MATCHED BY TARGET THEN INSERT (LastName, FirstName, Address, Age) VALUES
(S.LastName, S.FirstName, S.Address, S.Age)
WHEN NOT MATCHED BY SOURCE THEN DELETE;
B. MERGE Student.CurrentStudents AS T USING Student.NewYearRoster AS S ON S.LastName = T.
LastName AND S.FirstName = T.FirstName
WHEN MATCHED THEN DELETE
WHEN NOT MATCHED THEN INSERT (LastName, FirstName, Address, Age) VALUES (S.LastName,
S.FirstName, S.Address, S.Age)
WHEN NOT MATCHED BY SOURCE THEN UPDATE SET Address = T.Address, Age = T.Age;
C. MERGE Student.CurrentStudents AS T USING Student.NewYearRoster AS S ON S.LastName = T.
LastName AND S.FirstName = T.FirstName
WHEN MATCHED AND NOT T.Address = S.Address OR NOT T.Age = S.Age THEN UPDATE SET T.
Address = S.Address, T.Age = S.Age
WHEN NOT MATCHED THEN INSERT (LastName, FirstName, Address, Age) VALUES (S.LastName,
S.FirstName, S.Address, S.Age)
WHEN MATCHED THEN DELETE;
D. MERGE Student.CurrentStudents AS T USING Student.NewYearRoster AS S ON S.LastName = T.
LastName AND S.FirstName = T.FirstName
WHEN MATCHED AND NOT T.Address = S.Address AND NOT T.Age = S.Age THEN UPDATE SET T.
Age = S.Age, T.Address = S.Address
WHEN NOT MATCHED BY TARGET THEN INSERT (LastName, FirstName, Address, Age) VALUES
(S.LastName, S.FirstName, S.Address, S.Age)
WHEN NOT MATCHED BY SOURCE THEN DELETE;
Correct Answer: A
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 49
You create and populate two tables by using the following Transact-SQL statements:
CREATE TABLE CurrentStudents (LastName VARCHAR(50), FirstName VARCHAR(50),
Address VARCHAR(100), Age INT);
INSERT INTO CurrentStudents VALUES (‘Fritz’, ‘David’, ‘181 Kline Street’, 14)
,(‘Reese’, ‘Paul’ , ‘4429 South Union’, 14)
,(‘Brown’, ‘Jake’ , ‘5401 Washington Ave’,14)
,(‘Smith’, ‘Tom’ , ‘124 Water St’, 14)
,(‘Holtz’, ‘Mary’ , ‘984 Mass Ct’, 14)
,(‘Robbins’, ‘Jan’ , ‘4449 Union Ave’, 14)
,(‘Larsen’, ‘Frank’ , ‘5812 Meadow St’, 14)
,(‘Bishop’, ‘Cathy’ , ‘14429 Skyhigh Ave’, 14)
,(‘Francis’, ‘Thomas’ , ‘15401 120th St’, 14)
CREATE TABLE NewYearRoster(LastName VARCHAR(50), FirstName VARCHAR(50), Address
VARCHAR(100), Age INT);
INSERT INTO NewYearRoster VALUES (‘Fritz’, ‘David’, ‘181 Kline Street’, 15)
,(‘Reese’, ‘Paul’, ‘1950 Grandview Place’, 15)
,(‘Adams’, ‘Wilbur’, ‘4231 W. 93rd’, 15)
,(‘Adams’, ‘Norris’, ‘100 1st Ave’, 15)
,(‘Thomas’, ‘Paul’, ‘18176 Soundview Dr’, 15)
,(‘Linderson’, ‘Danielle’, ‘941 W. 37 Ave’, 15)
,(‘Moore’, ‘Joshua’, ‘2311 10st Ave’, 15)
,(‘Dark’, ‘Shelby’, ‘1987 Fifth Ave’, 15)
,(‘Scharp’, ‘Mary’, ‘1902 W. 303rd’, 15)
,(‘Morris’, ‘Walt’, ‘100 12st St’, 15);
You run the following MERGE statement to update, insert and delete rows in the CurrentStudents table
MERGE TOP (3) CurrentStudents AS T
USING NewYearRoster AS S ON S.LastName = T.LastName AND S.FirstName = T.
FirstName
WHEN MATCHED AND NOT (T.Age = S.Age OR T.Address = S.Address) THEN UPDATE SET
Address = S.Address, Age = S.Age
WHEN NOT MATCHED BY TARGET THEN INSERT (LastName, FirstName, Address, Age)
VALUES (S.LastName, S.FirstName, S.Address, S.Age)
WHEN NOT MATCHED BY SOURCE THEN DELETE;
You need to identify the total number of rows that are updated, inserted, and deleted in the CurrentStudent
table. Which total number of rows should you choose?
A. 0
B. 3
C. 6
D. 9
Correct Answer: B
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 50
You are writing a query that returns a list of products that have grossed more than $10,000.00 during the
year 2007.
You need to insert the following filter expression into the query.
SUM([Order Details].UnitPrice * [Order Details].Quantity) > 10000 Into which clause
should you insert this expression?
A. ON
B. WHERE
C. HAVING
D. GROUP BY
Correct Answer: C
Section: Section 3
Explanation
Explanation/Reference:
SELECT P.Name AS ProductName
FROM Sales.SalesOrderHeader AS H
INNER JOIN Sales.SalesOrderDetail AS [Order Details]
ON H.SalesOrderID = [Order Details].SalesOrderID
INNER JOIN Production.Product AS P
ON [Order Details].ProductID = P.ProductID
WHERE H.OrderDate >= ‘20070101’ AND OrderDate < ‘20080101’
GROUP BY P.Name
HAVING (SUM([Order Details].UnitPrice * [Order Details].OrderQty)) > 10000;
QUESTION 51
You have a table named Sales. You are tasked to list products that have been sold to less than ten
customers.
You need to write a query to achieve the task.
Which Transact-SQL statement should you use?
A. SELECT ProductID, COUNT(*) AS CustomerCount
FROM Sales
GROUP BY ProductID, CustomerID
HAVING COUNT(*) < 10;
B. SELECT ProductID, COUNT(DISTINCT CustomerID) AS CustomerCount
FROM Sales
GROUP BY ProductID
HAVING COUNT(DISTINCT CustomerID) < 10;
C. SELECT ProductID, CustomerID, COUNT(DISTINCT CustomerID) AS CustomerCount
FROM Sales
GROUP BY ProductID, CustomerID
HAVING COUNT(DISTINCT CustomerID) < 10;
D. SELECT *
FROM (SELECT ProductID, RANK() OVER (ORDER BY CustomerID DESC) AS Rnk FROM Sales) s
WHERE s.Rnk <= 10;
Correct Answer: B
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 52
You have two tables named Customers and Orders.
for customers that have placed at least one order, you need to produce a list of customer names and the
number of orders for each customer.
Which query should you use?
A. SELECT c.CustomerName, SUM(o.OrderID) AS [OrderCount]
FROM Customers c
JOIN Orders o ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerName
B. SELECT COUNT(o.OrderId) AS [OrderCount]
FROM CUSTOMERS c
JOIN ORDERS o ON c.CUSTOMERID = o.CUSTOMERID
C. SELECT c.CustomerName, COUNT(o.OrderID) AS [OrderCount]
FROM Customers c
JOIN Orders o ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerName
HAVING COUNT(o.OrderID) > 1
D. SELECT c.CustomerName, COUNT(o.OrderId) AS [OrderCount]
FROM Customers c
JOIN Orders o ON c.CustomerId = o.CustomerId
GROUP BY c.CustomerName
Correct Answer: D
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 53
You have a table named Products. The table contains a column named Color.
You need to write a Transact-SQL statement that calculates the percentage of products of each product
color.
Which Transact-SQL statement should you use?
A. SELECT Color, COUNT(*) OVER(PARTITION BY Color) / (COUNT(*) * 1.0) AS PercentColor
FROM Products
GROUP BY Color;
B. SELECT Color, COUNT(*) OVER() / (COUNT(*) * 1.0) AS PercentColor / (COUNT(*) * 1.0) AS
PercentColor
FROM Products
GROUP BY Color;
C. SELECT Color, (COUNT(*) * 1.0)/ COUNT(*) OVER() AS PercentColor
FROM Products
GROUP BY Color;
D. SELECT Color, COUNT(*) * 1.0) / COUNT(*) OVER(PARTITION BY Color) AS PercentColor
FROM Products
GROUP BY Color;
Correct Answer: C
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 54
You have two tables named SalesPerson and SalesTerritory.
You need to create sample data by using a Cartesian product that contains the data from the SalesPerson
and SalesTerritory tables.
Which code segment should you use?
A. SELECT p.SalesPersonId, t.Name AS [Territory]
FROM Sales.SalesPerson p FULL JOIN Sales.SalesTerritory t ON p.TerritoryId = t.TerritoryId
B. SELECT p.SalesPersonId, Name AS [Territory]
FROM Sales.SalesPerson p INNER JOIN Sales.SalesTerritory t ON p.TerritoryId = t.TerritoryId
C. SELECT p.SalesPersonId, t.Name AS [Territory] FROM Sales.SalesPerson p
CROSS JOIN Sales.SalesTerritory t WHERE p.TerritoryId = t.TerritoryId
D. SELECT p.SalesPersonId, t.Name AS [Territory] FROM Sales.SalesPerson p
CROSS JOIN Sales.SalesTerritory t;
Correct Answer: D
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 55
You have a table named Employees.
You want to identify the supervisor to which each employee reports. You write the following query.
SELECT e.EmloyeeName AS [EmployeeName], s.EmployeeName AS [SuperVisorName] FROM
Employees e
You need to ensure that the query returns a list of all employees and their respective supervisor. Which join
clause should you use to complete the query?
A. LEFT JOIN Employees s ON e.ReportsTo = s.EmployeeId
B. RIGHT JOIN Employees s ON e.ReportsTo = s.EmployeeId
C. INNER JOIN Employees s ON e.EmployeeId = s.EmployeeId
D. LEFT JOIN Employees s ON e.EmployeeId = s.EmployeeId
Correct Answer: A
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 56
You have a table named Subcategories that contains subcategories for socks, vests and helmets. You have
another table named Products that contains products only from the subcategories socks and vests. You
have the following query:
SELECT s.Name, p.Name AS ProductName
FROM Subcategories s OUTER APPLY (SELECT * FROM Products pr WHERE pr.
SubcategoryID = s.SubcategoryID) p
WHERE s.Name IS NOT NULL;
You need to predict the results of the query. What results should the query produce?
A. Name ProductName
Socks Mountain Bike
Socks, Socks Mountain Bike
Socks, Socks Racing Socks, M
Socks Racing Socks, L
Vests Classic Vest, S
Vests Classic Vest, M
Vests Classic Vest, L
B. Name ProductName
Socks Mountain Bike
Socks, Socks Mountain Bike
Socks, Socks Racing Socks, M
Socks Racing Socks, L
Vests Classic Vest, S
Vests Classic Vest, M
Vests Classic Vest, L
Helmets NULL
C. Name ProductName
Socks Mountain Bike
Socks, Socks Mountain Bike
Socks, Socks Racing Socks, M
Socks Racing Socks, L
Vests Classic Vest, S
Vests Classic Vest, M
Vests Classic Vest, L
Helmets NULL
NULL NULL
D. Name ProductName
Socks Mountain Bike
Socks, Socks Mountain Bike
Socks, Socks Racing Socks, M
Socks Racing Socks, L
Vests Classic Vest, S
Vests Classic Vest, M
Vests Classic Vest, L
NULL Mountain Bike
Socks, NULL Mountain Bike
Socks, NULL Racing Socks, M
NULL Racing Socks, L
NULL Classic Vest, S
NULL Classic Vest, M
NULL Classic Vest, L
Helmets NULL
NULL NULL
Correct Answer: B
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 57
You have two tables named dbo.CurrentProducts and dbo.ArchiveProducts. You have the following query:
SELECT ProductID, Name FROM dbo.CurrentProducts
UNION ALL
SELECT ProductID, Name FROM dbo.ArchiveProducts;
You need to predict the list of products that the query will produce. Which list of products should the query
return?
A. Products that appear in dbo.CurrentProducts or dbo.ArchiveProducts but not in both.
B. Products that have a matching ProductID and Name in dbo.CurrentProducts or dbo.ArchiveProducts.
C. Products that appear in dbo.CurrentProducts or dbo.ArchiveProducts. Products that appear in both
tables are listed only once.
D. Products that appear in dbo.CurrentProducts or dbo.ArchiveProducts. Products that appear in both
tables are listed multiple times.
Correct Answer: D
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 58
You have two tables named Products and NewProducts that have identical structures. You have the
following query (Line numbers are included for reference only):
01 SELECT Product, Description
02 FROM dbo.Products
03 ……..
04 SELECT Product, Description
05 FROM dbo.NewProducts
You need to choose the appropriate Transact-SQL operator to display rows that exist in both tables.
Which Transact-SQL operator should you insert in line 03?
A. UNION
B. EXCEPT
C. UNION ALL
D. INTERSECT
Correct Answer: D
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 59
You are tasked to create a table that has a column that must store the current time accurate to ten
microseconds.
You need to use a system function in conjunction with the DEFAULT option in the column definition.
Which system function should you use?
A. DATEADD
B. GETUTCDATE
C. SYSDATETIME
D. CURRENT_TIMESTAMP
Correct Answer: C
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 60
You need to round the value 1.75 to the nearest whole number.
Which code segment should you use?
A. Select ROUND(1.75,0)
B. Select ROUND(1.75,2)
C. Select ROUND(1.75,1.0)
D. Select ROUND(1.75,2.0)
Correct Answer: A
Section: Section 3
Explanation
Explanation/Reference:
QUESTION 61
You have a column named TelephoneNumber that stores numbers as varchar(20). You need to write a
query that returns the first three characters of a telephone number. Which expression should you use?
A. LEFT(TelephoneNumber, 3)
B. SUBSTRING(TelephoneNumber, 3, 3)
C. SUBSTRING (TelephoneNumber, 3, 1)
D. CHARINDEX(‘[0-9][0-9][0-9]‘, TelephoneNumber, 3)
Correct Answer: A
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 62
You are a database developer located in Seattle. You have a client in Melbourne, which is in a different time
zone from Seattle. You have been using the datetimeoffset data type and storing data by using the Seattle
offset.
You need to display the dates in the Melbourne offset.
Which function should you use?
A. CONVERT
B. DATEADD
C. SWITCHOFFSET
D. TODATETIMEOFFSET
Correct Answer: C
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 63
You have a database that contains two tables named ProductCategory and ProductSubCategory.
You need to write a query that returns a list of product categories that contain more than ten subcategories.
Which query should you use?
A. SELECT [Name] FROM ProductSubCategory
WHERE ProductCategoryID IN (
SELECT ProductCategoryID FROM ProductCategory)
GROUP BY [Name] HAVING COUNT(*) > 10 )
B. SELECT [Name] FROM ProductSubCategory
WHERE ProductCategoryID NOT IN (
SELECT ProductCategoryID FROM ProductCategory)
GROUP BY [Name] HAVING COUNT(*) > 10)
C. SELECT [Name] FROM Product Category c
WHERE EXISTS (
SELECT ProductCategoryID FROM ProductSubCategory
WHERE ProductCategoryID = c.ProductCategoryID
GROUP BY ProductCategoryID
HAVING COUNT(*) > 10)
D. SELECT [Name] FROM Product Category c
WHERE NOT EXISTS (
SELECT ProductCategoryID FROM ProductSubCategory
WHERE ProductCategoryID = c.ProductCategoryID
GROUP BY ProductCategoryID
HAVING COUNT(*) > 10)
Correct Answer: C
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 64
Your database contains sales information for millions of orders.
You need to identify the orders with the highest average unit price and an order total greater than 10,000.
The list should contain no more than 20 orders.
Which query should you use?
A. SELECT TOP (20) o.SalesOrderId, o.OrderDate, o.Total, SUM(od.QTY * od.UnitPrice) / SUM(od.Qty)
AS [AvgUnitPrice]
FROM Sales.SalesOrderHeader o
JOIN SALES.SalesOrderDetail od ON o.SalesOrderId = od.SalesOrderId
WHERE o.Total> 10000
GROUP BY o.SalesOrderId, o.OrderDate, o.Total
ORDER BY AvgUnitPrice;
B. SELECT TOP (20) o.SalesOrderId, o.OrderDate, o.Total,
(SELECT SUM(od.Qty * od.UnitPrice) / SUM(od.QTY) FROM Sales.SalesOrderDetail od WHERE o.
SalesOrderId = od.SalesOrderId) AS [AvgUnitPrice]
FROM Sales.SalesOrderHeader o WHERE o.Total> 10000 ORDER BY AvgUnitPrice DESC;
C. SELECT TOP (20) o.SalesOrderId, o.OrderDate, o.Total, SUM(od.Qty * od.UnitPrice) / SUM(od.Qty) AS
[AvgUnitPrice]
FROM Sales.SalesOrderHeader o
JOIN Sales.SalesOrderDetail od ON o.SalesOrderId = od.SalesOrderId
WHERE o.Total> 10000
GROUP BY o.SalesOrderId, o.OrderDate, o.Total
ORDER BY Total DESC;
D. SELECT TOP (20) o.SalesOrderId, o.OrderDate, o.Total,
(SELECT SUM(od.Qty * od.UnitPrice) / SUM(od.Qty) FROM Sales.SalesOrderDetail od WHERE o.
SalesOrderId = od.SalesOrderId) AS [AvgUnitPrice]
FROM Sales.SalesOrderHeader o
WHERE o.Total > 10000
ORDER BY o.Total DESC,
AvgUnitPrice;
Correct Answer: B
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 65
Your company stores vendor and price information in a database. All items in the database have a list
price.
You need to increase the list price for all products of only the vendor named Fabrikam by 20.00.
Which query should you use?
A. UPDATE Production.Product
SET ListPrice = ListPrice + 20.00
WHERE NOT EXISTS (
SELECT VendorId FROM Purchasing.Vendor
WHERE VendorName = ‘Fabrikam’);
B. UPDATE Production.Product SET ListPrice = ListPrice + 20.00
WHERE VendorId NOT IN (
SELECT VendorId FROM Purchasing.Vendor
WHERE VendorName = ‘Fabrikam’);
C. UPDATE Production.Product SET ListPrice = ListPrice + 20.00
WHERE EXISTS (
SELECT VendorId FROM Purchasing.Vendor
WHERE VendorName = ‘Fabrikam’);
D. UPDATE Production.Product SET ListPrice = ListPrice + 20.00 WHERE VendorId IN
(SELECT VendorId FROM Purchasing.Vendor
WHERE VendorName = ‘Fabrikam’);
Correct Answer: D
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 66
You have two tables named Customer and SalesOrder.
You need to identify all customers that have not yet made any purchases and those that have only made
orders with an OrderTotal less than 100.
Which query should you use?
A. SELECT * FROM Customer
WHERE 100 > ALL (
SELECT OrderTotal FROM SalesOrder
WHERE Customer.CustomerID = SalesOrder.CustomerID)
B. SELECT * FROM Customer
WHERE 100 > SOME (
SELECT OrderTotal FROM SalesOrder
WHERE Customer.CustomerID = SalesOrder.CustomerID)
C. SELECT * FROM Customer
WHERE 100 > (
SELECT MAX(OrderTotal) FROM SalesOrder
WHERE Customer.CustomerID = SalesOrder.CustomerID)
D. SELECT * FROM Customer
WHERE EXISTS (
SELECT SalesOrder.CustomerID FROM SalesOrder
WHERE Customer.CustomerID = SalesOrder.CustomerID AND SalesOrder.OrderTotal <= 100)
Correct Answer: A
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 67
You have two tables named Customer and SalesOrder.
In the Customer table you have 1000 customers, of which 900 customers have orders in the SalesOrder
table.
You execute the following query to list all customers that have had at least one sale.
SELECT * FROM Customer WHERE Customer.CustomerID IN (SELECT Customer.CustomerID
FROM SalesOrder)
You need to identify the results of the query. Which results will the query return?
A. No rows
B. A warning message
C. The 1000 rows in the Customer table
D. The 900 rows in the Customer table with matching rows in the SalesOrder table
Correct Answer: C
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 68
You have the following rows in the
Customer Table:
CustomerId Status
1 Active
2 Active
3 Inactive
4 NULL
5 Dormant
6 Dormant
You write the following query to return all customers that do not have NULL or ‘Dormant’ for their status:
SELECT * FROM Customer
WHERE Status NOT IN (NULL, ‘Dormant’)
You need to identify the results of the query.
Which result should you expect?
A. CustomerId Status
B. CustomerId Status
1 Active
2 Active
3 Inactive
C. CustomerId Status
1 Active
2 Active
3 Inactive
4 NULL
D. CustomerId Status
1 Active
2 Active
3 Inactive
4 NULL
5 Dormant
6 Dormant
Correct Answer: A
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 69
You have a table named Employee.
You document your company’s organizational hierarchy by inserting the EmployeeID of each employee’s
manager in the ReportsTo column.
You need to write a recursive query that produces a list of employees and their manager.
The query must also include the employee’s level in the hierarchy.
You write the following code segment. (Line numbers are included for reference only.)
01 WITH EmployeeList (EmployeeID, FullName, ManagerName, Level)
02 AS (
03 ………
04 )
05 SELECT EmployeeID, FullName, ManagerName, Level
06 FROM EmployeeList;
Which code segment should you insert at line 3?
A. SELECT EmployeeID, FullName, ” AS [ReportsTo], 1 AS [Level]
FROM Employee WHERE ReportsTo IS NULL
UNION ALL
SELECT emp.EmployeeID, emp.FullNName, mgr.FullName, 1 + 1 AS [Level]
FROM Employee emp
JOIN Employee mgr ON emp.ReportsTo = mgr.EmployeeID
B. SELECT EmployeeID, FullName, ” AS [ReportsTo], 1 AS [Level]
FROM Employee WHERE ReportsTo IS NULL
UNION ALL
SELECT emp.EmployeeID, emp.FullName, mgr.FullName, mgr.Level + 1
FROM EmployeeList mgr
JOIN Employee emp ON emp.ReportsTo = mgr.EmployeeId
C. SELECT EmployeeID, FullName, ” AS [Reports To], 1 AS [Level]
FROM Employee
UNION ALL
SELECT emp.EmployeeID, emp.FullName, mgr.FullName, 1 + 1 AS [Level]
FROM Employee emp
LEFT JOIN Employee mgr ON emp.ReportsTo = mgr.EmployeeID
D. SELECT EmployeeID, FullName, ” AS [ReportsTo], 1 AS [Level]
FROM Employee
UNION ALL
SELECT emp.EmployeeID, emp.FullName, mgr.FullName, mgr.Level + 1
FROM EmployeeList mgr
JOIN Employee emp ON emp.ReportsTo = mgr.EmployeeID
Correct Answer: B
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 70
You need to determine the result of executing this code segment.
DECLARE @RangeStart INT = 0;
DECLARE @RangeEnd INT = 10000;
DECLARE @RangeStep INT = 1;
WITH NumberRange(ItemValue)
AS (
SELECT ItemValue
FROM (SELECT @RangeStart AS ItemValue) AS t
UNION ALL
SELECT ItemValue + @RangeStep
FROM NumberRange
WHERE ItemValue < @RangeEnd)
SELECT ItemValue
FROM NumberRange
OPTION (MAXRECURSION 100)
Which result will be returned?
A. 101 rows will be returned with no error.
B. 10,001 rows will be returned with no error.
C. 101 rows will be returned with a maximum recursion error.
D. 10,001 rows will be returned with a maximum recursion error.
Correct Answer: C
Section: Section 4
Explanation
Explanation/Reference:
MAXRECURSION number specifies the maximum number of recursions allowed for this query. number is a
nonnegative integer between 0 and 32767. When 0 is specified, no limit is applied. If this option is not
specified, the default limit for the server is 100.
When the specified or default number for MAXRECURSION limit is reached during query execution, the
query is ended and an error is returned.
QUESTION 71
You need to implement a common table expression (CTE). Which code segment should you use?
A. CREATE VIEW SalesByYear AS
SELECT Year, Region, SUM(OrderTotal)
FROM Orders
GROUP BY Year, Region;
GO
SELECT Year, Region, Total
FROM SalesByYear;
B. WITH SalesByYear(Year,Region,Total)
AS (SELECT Year, Region, SUM(OrderTotal)
FROM Orders GROUP BY Year,Region)
SELECT Year, Region, Total FROM SalesByYear;
C. SELECT Year, Region, Total
FROM (
SELECT Year, Region, SUM(OrderTotal) AS Total
FROM Orders
GROUP BY Year, Region) AS [SalesByYear];
D. SELECT DISTINCT Year, Region, (
SELECT SUM(OrderTotal) FROM Orders SalesByYear
WHERE Orders.Year = SalesByYear.YEAR AND Orders.Region = SalesByYear.Region) AS [Total]
FROM Orders;
Correct Answer: B
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 72
You are tasked to analyze blocking behavior of the following query:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
WITH Customers AS (
SELECT * FROM Customer ),
SalesTotal AS ( SELECT CustomerId, SUM(OrderTotal) AS AllOrderTotal FROM
SalesOrder)
SELECT CustomerId, AllOrderTotal
FROM SalesTotal
WHERE AllOrderTotal > 10000.00;
You need to determine if other queries that are using the Customer table will be blocked by this query. You
also need to determine if this query will be blocked by other queries that are using the Customer table.
What behavior should you expect?
A. The other queries will be blocked by this query.
This query will be blocked by the other queries.
B. The other queries will be blocked by this query.
This query will not be blocked by the other queries.
C. The other queries will not be blocked by this query.
This query will be blocked by the other queries.
D. The other queries will not be blocked by this query.
This query will not be blocked by the other queries.
Correct Answer: D
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 73
You create and populate a table named SiteNavigation by using the following statements:
CREATE TABLE SiteNavigation (
SiteNavigationId INT PRIMARY KEY,
Linktext VARCHAR(10),
LinkUrl VARCHAR(40),
ParentSiteNavigationId INT NULL REFERENCES SiteNavigation
(SiteNavigationId)
)
INSERT INTO SiteNavigation VALUES (1,’First’,’http://first&#8217;,NULL)
,(2,’Second’,’http://second&#8217;,1)
,(3,’Third’,’http://third&#8217;,1)
,(4,’Fourth’,’http://fourth&#8217;,2)
,(5,’Fifth’,’http://fifth&#8217;,2)
,(6,’Sixth’,’http://sixth&#8217;,2)
,(7,’Seventh’,’http://seventh&#8217;,6)
,(8,’Eighth’,’http://eighth&#8217;,7)
You are tasked to write a query to list all site references that are more than two levels from the root node.
The query should produce the following results:
LinkText LinkUrl DistanceFromRoot
Fourth http://fourth 2
Fifth http://fifth 2
Sixth http://sixth 2
Seventh http://seventh 3
Eighth http://eighth 4
You have written the following query:
WITH DisplayHierarchy AS (SELECT LinkText, LinkUrl, SiteNavigationId,
ParentSiteNavigationId, 0 AS DistanceFromRoot
FROM SiteNavigation
WHERE ParentSiteNavigationId IS NULL
UNION ALL
SELECT SiteNavigation.LinkText, SiteNavigation.LinkUrl, SiteNavigation.
SiteNavigationId, SiteNavigation.ParentSiteNavigationId,
dh.DistanceFromRoot + 1 AS DistanceFromRoot
FROM SiteNavigation
INNER JOIN DisplayHierarchy dh
ON SiteNavigation.ParentSiteNavigationId = dh.SiteNavigationId)
SELECT LinkText, LinkUrl, DistanceFromRoot FROM DisplayHierarchy
You need to append a WHERE clause to the query. Which clause should you use?
A. WHERE DistanceFromRoot =2
B. WHERE DistanceFromRoot < 2
C. WHERE DistanceFromRoot >= 2
D. WHERE DistanceFromRoot IN (2,3)
Correct Answer: C
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 74
You have two views named Sales.SalesSummaryOverall and Sales.CustomerAndSalesSummary.
They are defined as follows:
CREATE VIEW Sales.SalesSummaryOverall
AS
SELECT CustomerId, SUM(SalesTotal) AS OverallTotal
FROM Sales.SalesOrder
GROUP BY CustomerId
GO
CREATE VIEW Sales.CustomerAndSalesSummary
AS
SELECT Customer.Name, SalesSummaryOverall.OverallTotal, (SELECT AVG
(OverallTotal)
FROM Sales.SalesSummaryOverall
WHERE SalesSummaryOverall.CustomerId = Customer.CustomerId) AS
avgOverallTotal,
(SELECT MAX(OverallTotal) FROM Sales.SalesSummaryOverall
WHERE SalesSummaryOverall.CustomerId =Customer.CustomerId) AS maxOverallTotal,
FROM Sales.Customer
LEFT OUTER JOIN Sales. Sales.SalesSummaryOverall
ON SalesSummaryByYear.CustomerId = Customer.CustomerId
GO
You have been tasked to modify the Sales.CustomerAndSalesSummary view to remove references to other
views.
You need to identify a feature to use in the modified version of the Sales.CustomerAndSalesSummary
object to achieve the task.
Which feature should you use?
A. Table variables
B. Temporary tables
C. User-defined table types
D. Common table expressions
Correct Answer: D
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 75
You need to write a query that allows you to rank total sales for each salesperson into four groups, where
the top 25 percent of results are in group 1, the next 25 percent are in group 2, the next 25 percent are in
group 3, and the lowest 25 percent are in group 4.
Which Transact-SQL statement should you use?
A. NTILE(1)
B. NTILE(4)
C. NTILE(25)
D. NTILE(100)
Correct Answer: B
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 76
You need to write a query that uses a ranking function that returns the sequential number of a row within a
partition of a result set, starting at 1 for the first row in each partition.
Which Transact-SQL statement should you use?
A. RANK
B. NTILE(10)
C. DENSE_RANK
D. ROW_NUMBER
Correct Answer: D
Section: Section 4
Explanation
Explanation/Reference:
ROW_NUMBER returns the sequential number of a row within a partition of a result set, starting at 1 for the
first row in each partition.
QUESTION 77
You have a table named ProductCounts that contains 1000 products as well as the number of units that
have been sold for each product. You need to write a query that displays the top 5% of products that have
been sold most frequently.
Which Transact-SQL code segments should you use?
A. WITH Percentages AS (
SELECT *, NTILE(5) OVER (ORDER BY UnitsSold) AS groupingColumn FROM ProductCounts)
SELECT * FROM percentages
WHERE groupingColumn =1;
B. WITH Percentages AS (
SELECT *, NTILE(5) OVER (ORDER BY UnitsSold) AS groupingColumn FROM ProductCounts)
SELECT * FROM Percentages
WHERE groupingColumn = 5;
C. WITH Percentages AS (
SELECT *, NTILE(20) OVER (ORDER BY UnitsSold) AS groupingColumn FROM ProductCounts)
SELECT * FROM Percentages
WHERE groupingColumn = 1;
D. WITH Percentages AS (
SELECT *, NTILE(20) OVER (ORDER BY UnitsSold) AS groupingColumn FROM ProductCounts)
SELECT * FROM Percentages
WHERE groupingColumn = 20;
Correct Answer: D
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 78
You work for an international charity organization. You are writing a query to list the highest 100 different
amounts that were donated. You have written the following code segment (Line numbers are included for
reference only):
01 SELECT *
02 FROM (SELECT Customer.CustomerID, SUM(TotalDue) AS TotalGiven,
03 ………………..
04 FROM Customer
05 JOIN SalesOrder
06 ON Customer.CustomerID = SalesOrder.CustomerID
07 GROUP BY Customer.CustomerID) AS DonationsToFilter
08 WHERE FilterCriteria <= 100
You need to insert a Transact-SQL clause in line 03 to complete the query. Which Transact-SQL clause
should you insert?
A. RANK() OVER (ORDER BY SUM(TotalDue) DESC) AS FilterCriteria
B. NTILE(100) OVER (ORDER BY SUM(TotalDue) DESC) AS FilterCriteria
C. ROW_NUMBER() OVER (ORDER BY SUM(TotalDue) DESC) AS FilterCriteria
D. DENSE_RANK() OVER (ORDER BY SUM(TotalDue) DESC) AS FilterCriteria
Correct Answer: D
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 79
You have a database server that has four quad-core processors. This database server executes complex
queries that are used to generate reports.
You need to force a query to use only one processor core without affecting other queries.
Which option should you use?
A. OPTION (FAST 1)
B. OPTION (MAXDOP 1)
C. OPTION (RECOMPILE)
D. OPTION (MAXRECURSION 1)
Correct Answer: B
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 80
You notice that for a particular set of parameter values the following query sometimes executes
quickly and other times executes slowly. You also notice that 90 percent of the rows in the Address table
contain the same value for the city.
SELECT AddressId, AddressLine1, City, PostalCode
FROM Person.Address
WHERE City = @city_name
AND PostalCode = @postal_code
You need to use a query hint that, for the particular set of parameter values, will result in a more consistent
query execution time. Which query hint should you use?
A. FAST
B. MAXDOP
C. OPTIMIZE FOR
D. PARAMETERIZATION FORCED
Correct Answer: C
Section: Section 4
Explanation
Explanation/Reference:
QUESTION 81
You have been tasked to write a query to select one million rows.
You need to optimize the query to return the first 50 rows as quickly as possible.
What query hint should you use?
A. FAST 50
B. MAXDOP 50
C. OPTIMIZE FOR @ROWS=50
D. TABLE HINT(table, INDEX(50))
Correct Answer: A
Section: Section 5
Explanation
Explanation/Reference:
FAST number_rows
Specifies that the query is optimized for fast retrieval of the first number_rows. This is a nonnegative
integer. After the first number_rows are returned, the query continues execution and produces its full result
set.
QUESTION 82
You have the following query:
SELECT EmployeeID, ManagerID, LoginID FROM dbo.Employees WHERE ManagerID = 1500
ORDER BY ManagerID;
You have been tasked to force the query to use the execution plan in the exhibit.
You need to use an appropriate hint to perform the task.
Which hint should you use?
Exhibit:
A. INDEX(0)
B. INDEX(1)
C. INDEX(PK_Employees)
D. INDEX(IX_Employees)
Correct Answer: D
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 83
You are working with a SQL Server 2008 instance that is configured to use the Latin1_General_CS_AS
collation. You create a database by using the following statements.
CREATE DATABASE TestDB COLLATE Estonian_CS_AS;
GO
USE TestDB;
GO
CREATE TABLE TestPermTab (PrimaryKey int PRIMARY KEY, Col1 nchar );
You implement a temporary table named #TestTempTab that uses the following code.
use TestDB;
GO
CREATE TABLE #TestTempTab (PrimaryKey int PRIMARY KEY, Col1 nchar );
INSERT INTO #TestTempTab
SELECT * FROM TestPermTab;
You need to identify which collation will be assigned to #TestTempTab. Which collation will be assigned?
A. No-collation
B. Estonian_CS_AS
C. Latin1_General_CS_AS
D. The collation selected by the Windows system locale of the server
Correct Answer: C
Section: Section 5
Explanation
Explanation/Reference:
When using temporary tables without specifying a collation (for the column used) SQL Server will inherit the
collation for the newly created temporary table from the SQL Server instance default.
You can use the database_default option in the COLLATE clause to specify that a column in a temporary
table use the collation default of the current user database for the connection instead of tempdb.
QUESTION 84
You have a table named Person that contains a nvarchar column named Surname. The Person table
currently has a clustered index on PersonID. The Surname column contains Russian and Japanese
characters.
The following code segment will be used to search by Surname.
IF @lang =’Russian’
SELECT PersonID, Surname
FROM Person WHERE Surname = @SearchName COLLATE Cyrillic_General_CI_AS
if @lang = ‘Japanese’
SELECT PersonID, Surname FROM Person WHERE Surname = @SearchName COLLATE
Japanese_CI_AS_KS
You need to enable SQL Server to perform an index seek for these queries. What should you do?
A. Create an index on the Surname column.
B. Create a computed column for each collation that needs to be searched. Create an index on the
Surname column.
C. Create a computed column for each collation that needs to be searched. Create an index on each
computed column.
D. Create a new column for each collation that needs to be searched and copy the data from the Surname
column. Create an index on each new column.
Correct Answer: C
Section: Section 5
Explanation
Explanation/Reference:
– Add computed columns with different collations.
ALTER TABLE Person
ADD Surname_RU AS Surname COLLATE Cyrillic_General_CI_AS,
Surname_JP AS Surname COLLATE Japanese_CI_AS_KS;
– Create an index on the computed columns.
CREATE NONCLUSTERED INDEX IX_Person_Surname_RU ON Person (Surname_RU);
CREATE NONCLUSTERED INDEX IX_Person_Surname_JP ON Person (Surname_JP);
GO
QUESTION 85
You have an application that is used by international clients. All clients connect by using Windows
Authentication.
You need to ensure that system and user-defined error messages are displayed in the localized language
for the clients. What should you do? (Each correct answer represents part of the solution. Choose two.)
A. Use @@LANGUAGE function
B. Use default language for each login
C. Use @lang parameter of sp_addmessage
D. Use the “set language” option of sp_configure
Correct Answer: BC
Section: Section 5
Explanation
Explanation/Reference:
sp_configure is used to specify the default language for all newly created logins.
CREATE LOGIN expression has DEFAULT_LANGUAGE = language option. It specifies the default
language to be assigned to the login. If this option is not included, the default language is set to the current
default language of the server.
sp_addmessage stores a new user-defined error message in an instance of the SQL Server Database
Engine. One of the options is ‘language. It is the language for this message, that is the language in which
message is written. When language is omitted, the language is the default language for the session.
QUESTION 86
Your server collation is SQL_Latin1_General_CP1_CI_AS. You have a database named Contoso that has a
collation setting of SQL_Scandinavian_Cp850_CI_AS. You create and populate a temporary table #Person
from table dbo.Person in Contoso using the following statements:
use Contoso;
CREATE TABLE #Person (LastName nchar(128));
INSERT INTO #Person SELECT LastName FROM dbo.Person;
You then run the following command:
SELECT * FROM dbo.Person a JOIN #Person b
ON a.LastName = b.LastName;
This command returns the following error:
Cannot resolve the collation conflict between “SQL_Latin1_General_CP1_CI_AS” and
“SQL_Scandinavian_Cp850_CI_AS” in the equal to operation.
You need to resolve the collation conflict. Which Transact-SQL statement should you use?
A. CREATE TABLE #Person (LastName nvarchar(128) SPARSE);
B. CREATE TABLE #Person (LastName nvarchar(128) COLLATE database_default);
C. CREATE TABLE #Person (LastName nvarchar(128) COLLATE SQL_Latin1_General_CP1_CI_AS);
D. CREATE TABLE tmpPerson (LastName nvarchar(128) COLLATE SQL_Latin1_General_CP1_CI_AS);
Correct Answer: B
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 87
You have a SQL Server 2008 database. You have not installed a MAPI client. You need to send e-mail from
a stored procedure. Which system stored procedure should you use?
A. xp_sendmail
B. xp_startmail
C. sp_send_dbmail
D. sysmail_start_sp
Correct Answer: C
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 88
You are using Database Mail to deliver email notification and are notified that an employee has not been
receiving emails.
You need to determine if any email notifications sent by Database Mail have been unsuccessful.
Which object from the msdb database should you use?
A. msdb.dbo.sysmail_event_log
B. msdb.dbo.sysmail_sentitems
C. msdb.dbo.sysmail_unsentitems
D. msdb.dbo.sysmail_faileditems
Correct Answer: D
Section: Section 5
Explanation
Explanation/Reference:
sysmail_faileditems
Contains one row for each Database Mail message with the failed status. Use this view to determine which
messages were not successfully sent.
QUESTION 89
You have been tasked to delete a number of Database Mail messages that have been sent.
You need to delete all the emails that were sent more than one month ago.
Which Transact-SQL statements should you run?
A. DECLARE @OneMonthAgo datetime = DATEADD(mm,-1,GETDATE())
EXEC msdb.dbo.sysmail_delete_log_sp @OneMonthAgo
B. DECLARE @OneMonthAgo datetime = DATEADD(mm,-1,GETDATE())
EXEC msdb.dbo.sysmail_delete_mailitems_sp @OneMonthAgo
C. DECLARE @OneMonthAgo datetime = DATEADD(mm,-1,GETDATE())
EXEC msdb.dbo.sysmail_delete_log_sp @OneMonthAgo,’Success’
D. DECLARE @OneMonthAgo datetime = DATEADD(mm,-1,GETDATE())
EXEC msdb.dbo.sysmail_delete_mailitems_sp @OneMonthAgo,’Sent’
Correct Answer: D
Section: Section 5
Explanation
Explanation/Reference:
sysmail_delete_mailitems_sp [ [ @sent_before = ] ‘sent_before’ ]
[ , [ @sent_status = ] ‘sent_status’ ]
Permanently deletes e-mail messages from the Database Mail internal tables.
[ @sent_before= ] ‘sent_before’
Deletes e-mails up to the date and time provided as the sent_before argument. sent_before is datetime with
NULL as default. NULL indicates all dates.
[ @sent_status= ] ‘sent_status’
Deletes e-mails of the type specified by sent_status. sent_status is varchar(8) with no default. Valid entries
are sent, unsent, retrying, and failed. NULL indicates all statuses.
Database Mail messages and their attachments are stored in the msdb database. Messages should be
periodically deleted to prevent msdb from growing larger than expected and to comply with your
organizations document retention program. Use the sysmail_delete_mailitems_sp stored procedure to
permanently delete e-mail messages from the Database Mail tables. An optional argument allows you to
delete only older e-mails by providing a date and time. E-mails older than that argument will be deleted.
Another optional argument allows you to delete only e-mails of a certain type, specified as the sent_status
argument. You must provide an argument either for @sent_before or @sent_status. To delete all
messages, use @sent_before = getdate().
QUESTION 90
You have a table named Books that has columns named BookTitle and Description. There is a full-text
index on these columns. You need to return rows from the table in which the word ‘computer’ exists in either
column. Which code segment should you use?
A. SELECT * FROM Books
WHERE FREETEXT(*,’computer’)
B. SELECT * FROM Books
WHERE BookTitle LIKE ‘%computer%’
C. SELECT * FROM Books
WHERE BookTitle = ‘%computer%’
OR Description = ‘%computer%’
D. SELECT * FROM Books
WHERE FREETEXT(BookTitle,’computer’)
Correct Answer: A
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 91
You need to configure Full-Text Search to ignore specific words. Which Full-Text Search component should
you use?
A. iFilter
B. Stoplist
C. Thesaurus file
D. Word breakers
Correct Answer: B
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 92
Your company manufactures and distributes bicycle parts. You have a full-text catalog on the Inventory
table which contains the PartName and Description columns. You also use a full-text thesaurus to expand
common bicycle terms. You need to write a full-text query that will not only match the exact word in the
search, but also the meaning.
Which Transact-SQL statement should you use?
A. SELECT * FROM Inventory
WHERE FREETEXT (*, ‘cycle’))
B. SELECT * FROM Inventory
WHERE CONTAINS (*, ‘cycle’)
C. SELECT * FROM Inventory
WHERE Description LIKE ‘%cycle%’
D. SELECT * FROM Inventory
WHERE CONTAINS (*, ‘FormsOf(Inflectional, cycle)’)
Correct Answer: A
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 93
Your company manufactures and distributes bowling balls. You have a full-text catalog named ftCatalog
which contains the ftInventory index on the Products table. Your marketing department has just inserted a
new bowling ball into the Inventory table. You notice only the new bowling ball is not being included in the
results of the full-text searches. You have confirmed that the row exists in the Products table. You need to
update the full-text catalog in the least amount of time. Which Transact-SQL statement should you use?
A. ALTER FULLTEXT INDEX ON ftInventory START FULL POPULATION
B. ALTER FULLTEXT INDEX ON ftInventory RESUME POPULATION
C. ALTER FULLTEXT INDEX ON ftInventory START UPDATE POPULATION
D. ALTER FULLTEXT CATALOG ftCatalog REBUILD
Correct Answer: C
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 94
You have a server named Contoso with multiple databases.
You have been tasked to write a PowerShell script to determine which databases on the server are larger
than 100GB.
You open PowerShell from SQL Server Management Studio. You create two variables as follows:
PS SQLSERVER:\SQL\Contoso> $MultipleOfGB = 1024 * 1024
PS SQLSERVER:\SQL\Contoso> $Server = Get-Item
You need to determine which script will produce the desired list of databases.
What script should you use?
A. $Server.Databases | Where-Object{($_.Size * $MultipleOfGB) -gt 100GB\} | Select-Object Name, Size
B. $Server | Where-Object{($_.DatabaseSize * $MultipleOfGB) -match 100GB\} | Select-Object Name,
DatabaseSize
C. $Server | Where-Object{($_.DatabaseSize * $MultipleOfGB) -gt 100GB\} | Select-Object Name,
DatabaseSize
D. $Server.Databases | Where-Object{($_.Size * $MultipleOfGB) -match 100GB\} | Select-Object Name,
Size
Correct Answer: A
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 95
You have a table named Inventory. You open a Microsoft Windows PowerShell session at the following
location by using the SQL Server Windows PowerShell provider. PS
SQLSERVER:\SQL\CONTOSO\DEFAULT\Databases\ReportServer\Tables\dbo.Inventory
\Columns>
Using the SQL Server Windows PowerShell provider, you need to query all the columns in the table. Which
cmdlet should you use?
A. Get-Item
B. Get-Location
C. Get-ChildItem
D. Get-ItemProperty
Correct Answer: C
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 96
You are configuring Service Broker to process messages within a single database. You have performed the
following steps.
CREATE MESSAGE TYPE
CREATE CONTRACT
CREATE QUEUE
You need to complete the Service Broker configuration. What should be the next step?
A. CREATE ROUTE
B. CREATE SERVICE
C. CREATE ENDPOINT
D. CREATE BROKER PRIORITY
Correct Answer: B
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 97
You have a database named Contoso. The Contoso database has a Service Broker queue named
VacationRequestQueue.
The Contoso database has been restored to a new server. Since restoring the database, Service Broker is
no longer able to send new messages.
You need to configure Service Broker in order to resolve the issue.
Which Transact-SQL statement should you use?
A. ALTER DATABASE Contoso SET NEW_BROKER;
B. ALTER DATABASE Contoso SET ENABLE_BROKER;
C. ALTER QUEUE VacationRequestQueue WITH STATUS = ON;
D. ALTER QUEUE VacationRequestQueue WITH ACTIVATION (STATUS = ON);
Correct Answer: A
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 98
You created a Service Broker queue by using the following Transact-SQL statement:
CREATE QUEUE VacationRequestQueue WITH RETENTION = OFF, ACTIVATION (
PROCEDURE_NAME = dbo.VacationRequestProcess,
MAX_QUEUE_READERS = 5, EXECUTE AS SELF
);
You need to modify the Service Broker queue to prevent it from processing received messages.
The queue should continue to receive messages.
Which Transact-SQL statement should you use?
A. ALTER QUEUE VacationRequestQueue WITH RETENTION = ON;
B. ALTER QUEUE VacationRequestQueue WITH STATUS = OFF;
C. ALTER QUEUE VacationRequestQueue WITH ACTIVATION (STATUS = OFF);
D. ALTER QUEUE VacationRequestQueue WITH ACTIVATION (EXECUTE AS OWNER);
Correct Answer: C
Section: Section 5
Explanation
Explanation/Reference:
ALTER QUEUE VacationRequestQueue WITH RETENTION = ON; sets the VacationRequestQueue queue
to retain messages. The queue retains all messages sent to or from services that use this queue until the
conversation that contains the message ends.
ALTER QUEUE VacationRequestQueue WITH STATUS = OFF; makes the VacationRequestQueue queue
unavailable to receive messages.
ALTER QUEUE VacationRequestQueue WITH ACTIVATION (STATUS = OFF); the queue does not
activate the stored procedure.
ALTER QUEUE VacationRequestQueue WITH ACTIVATION (EXECUTE AS OWNER); specifies that the
stored procedure executes as the owner of the queue.
QUESTION 99
You use the same Service Broker configuration to support a Web site and an internal application. The Web
site generates a greater workload than the internal application.
You need to configure Service Broker to ensure that messages sent by the internal application are
processed before those sent by the Web site.
Which Transact-SQL statement should you use?
A. ALTER SERVICE
B. CREATE CONTRACT
C. CREATE BROKER PRIORITY
D. ALTER QUEUE WITH ACTIVATION
Correct Answer: C
Section: Section 5
Explanation
Explanation/Reference:
QUESTION 100
You are using Microsoft SQL Server 2008 Enterprise Edition. You need to maintain a history of all data
modifications made to a table, including the type of modification and the values modified. Which tracking
method should you use?
A. Database Audit
B. Change Tracking
C. C2 Audit Tracing
D. Change Data Capture
Correct Answer: D
Section: Section 5
Explanation
Explanation/Reference:
Database Audit
Auditing an instance of the SQL Server Database Engine or an individual database involves tracking and
logging events that occur on the Database Engine. SQL Server audit lets you create server audits, which
can contain server audit specifications for server level events, and database audit specifications for
database level events. Audited events can be written to the event logs or to audit files.
Change Data Capture
Change data capture provides historical change information for a user table by capturing both the fact that
DML changes were made and the actual data that was changed. Changes are captured by using an
asynchronous process that reads the transaction log and has a low impact on the system.
Change Tracking
Change tracking captures the fact that rows in a table were changed, but does not capture the data that
was changed. This enables applications to determine the rows that have changed with the latest row data
being obtained directly from the user tables. Therefore, change tracking is more limited in the historical
questions it can answer compared to change data capture. However, for those applications that do not
require the historical information, there is far less storage overhead because of the changed data not being
captured.
QUESTION 101
A database contains tables named Sales and SalesArchive. SalesArchive contains historical sales data.
You configure Change Tracking on the Sales table. The minimum valid version of the Sales table is
You need to write a query to export only sales data that changed since version 10, including the primary key
of deleted rows. Which method should you use?
A. FROM Sales RIGHT JOIN CHANGETABLE (CHANGES Sales, 10) AS C …
B. FROM Sales INNER JOIN CHANGETABLE (CHANGES Sales, 10) AS C …
C. FROM Sales INNER JOIN CHANGETABLE (CHANGES SalesArchive, 10) AS C …
D. FROM Sales RIGHT JOIN CHANGETABLE (CHANGES SalesArchive, 10) AS C …
Correct Answer: A
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 102
You are required to modify a table named Sales.SalesOrder. The table has change tracking enabled on it.
You need to disable change tracking prior to modifying the Sales.SalesOrder table.
Which Transact-SQL statement should you use?
A. EXEC sys.sp_cdc_disable_db
B. ALTER DATABASE Contoso
SET CHANGE_TRACKING = OFF
C. ALTER TABLE Sales.SalesOrder
DISABLE CHANGE_TRACKING
D. EXEC sys.sp_cdc_disable_table
@source_schema = N’Sales’,
@source_name = N’SalesOrder’,
@capture_instance = N’Sales_SalesOrder’
Correct Answer: C
Section: Section 6
Explanation
Explanation/Reference:
Enabling Change Tracking for a Database
Before you can use change tracking, you must enable change tracking at the database level.
ALTER DATABASE AdventureWorks2008R2
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);
Enabling Change Tracking for a Table
Change tracking must be enabled for each table that you want tracked. When change tracking is enabled,
change tracking information is maintained for all rows in the table that are affected by a DML operation.
ALTER TABLE Person.Person
ENABLE CHANGE_TRACKING
WITH (TRACK_COLUMNS_UPDATED = ON);
Disabling Change Tracking
Change tracking must first be disabled for all change-tracked tables before change tracking can be set to
OFF for the database. To determine the tables that have change tracking enabled for a database, use the
sys.change_tracking_tables catalog view.
ALTER TABLE Person.Person
DISABLE CHANGE_TRACKING;
When no tables in a database track changes, you can disable change tracking for the database.
ALTER DATABASE AdventureWorks2008R2
SET CHANGE_TRACKING = OFF;
QUESTION 103
You have implemented change tracking on a table named Sales.SalesOrder.
You need to determine all columns that have changed since the minimum valid version.
Which function should you use?
A. CHANGE_TRACKING_CURRENT_VERSION
B. CHANGE_TRACKING_IS_COLUMN_IN_MASK
C. CHANGETABLE with the CHANGES argument
D. CHANGETABLE with the VERSION argument
Correct Answer: C
Section: Section 6
Explanation
Explanation/Reference:
CHANGETABLE (
{ CHANGES table , last_sync_version
| VERSION table , <primary_key_values> } )
[AS] table_alias [ ( column_alias [ ,...n ] )
CHANGES table , last_sync_version
Returns tracking information for all changes to a table that have occurred since the version that is specified
by last_sync_version.
VERSION table, { <primary_key_values> }
Returns the latest change tracking information for a specified row. Primary key values must identify the row.
<primary_key_values> identifies the primary key columns and specifies the values.
QUESTION 104
You have two tables named Customers and Orders. They are related by a foreign key constraint on the
CustomerID on each table. You need to generate the following XML structure that includes all customers
and their related orders.
<Root>
<Customer>
<CustomerName>Customer1</CustomerName>
<Orders>
<Order>
<OrderDate>1/1/2008</OrderDate>
<OrderValue>422</OrderValue>
</Order>
<Order>
<OrderDate>4/8/2008</OrderDate>
<OrderValue>300</OrderValue>
</Order>

</Orders>

</Customer>
<Root>
Which query should you use?
A. SELECT CustomerName, OrderDate, OrderValue
FROM Customers c JOIN Orders o ON o.CustomerID = c.CustomerID
FOR XML AUTO, TYPE
B. SELECT * FROM (
SELECT CustomerName, NULL AS OrderDate, NULL AS OrderValue
FROM Customers
UNION ALL
SELECT NULL, OrderDate, OrderValue FROM Orders) CustomerOrders
FOR XML AUTO, ROOT(‘Root’)
C. SELECT CustomerName, (
SELECT OrderDate, OrderValue
FROM Orders
FOR XML PATH(‘Order’))
FROM Customers FOR XML PATH(‘Customer’), ROOT(‘Root’), TYPE
D. SELECT CustomerName, (
SELECT OrderDate, OrderValue
FROM Orders
WHERE Orders.CustomerId = Customers.CustomerId FOR XML PATH(‘Order’), TYPE) Orders
FROM Customers FOR XML PATH(‘Customer’), ROOT(‘Root’)
Correct Answer: D
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 105
You need to generate the following XML document.
<ProductExport>
<Product Price=”99″>Product1</Product>
<Product Price=”199″>Product2</Product>
<Product Price=”299″>Product3</Product>
<Product Price=”399″>Product4</Product>
</ProductExport>
Which query should you use?
A. SELECT Price, ProductName
FROM Products AS ProductExport
FOR XML PATH(‘Product’)
B. SELECT Price, ProductName
FROM Products
FOR XML AUTO, ROOT(‘ProductExport’)
C. SELECT Price [@Price],
ProductName AS [*] FROM Products AS ProductExport FOR XML AUTO, ELEMENTS
D. SELECT Price [@Price],
ProductName AS [*] FROM Products FOR XML PATH(‘Product’),ROOT(‘ProductExport’)
Correct Answer: D
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 106
Your company’s database contains Customers and Orders tables.
You have been tasked to write a SELECT statement that outputs customer and order data as a valid and
well-formed XML document. You are required to mix attribute and element based XML within the document.
You have determined that using the FOR XML AUTO clause will not be suitable.
You need to identify the correct FOR XML clause to meet the requirement.
Which FOR XML statement should you use? (Each correct answer represents a complete solution. Choose
two.)
A. FOR BROWSE
B. FOR XML RAW
C. FOR XML PATH
D. FOR XML EXPLICIT
Correct Answer: CD
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 107
Your company’s database contains Customers and Orders tables.
You have been tasked to write a SELECT statement that exposes the data as a valid and well-formed
XML document. The XML data must be attribute-based, and the order data XML must be nested in the
customer data XML.
You need to write a SELECT statement to meet the requirements.
Which Transact-SQL statement should you use?
A. SELECT c.ContactName, o.OrderDate, o.RequiredDate
FROM Customers c INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
FOR XML RAW(‘Contact’), ROOT(‘ContactOrderDate’)
B. SELECT c.ContactName, o.OrderDate, o.RequiredDate
FROM Customers c INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
FOR XML PATH(‘ContactOrderDate’)
C. SELECT c.ContactName, o.OrderDate, o.RequiredDate
FROM Customers c INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
FOR XML AUTO
D. SELECT c.ContactName, o.OrderDate, o.RequiredDate
FROM Customers c INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
FOR XML AUTO, ROOT(‘ContactOrderDate’)
Correct Answer: D
Section: Section 6
Explanation
Explanation/Reference:
SELECT c.ContactName, o.OrderDate, o.RequiredDate
FROM Customers c INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
FOR XML RAW(‘Contact’), ROOT(‘ContactOrderDate’)
Produce the following result:
<ContactOrderDate>
<Contact ContactName=”Paul Henriot” OrderDate=”1996-07-04T00:00:00″
RequiredDate=”1996-08-01T00:00:00″ />
<Contact ContactName=”Karin Josephs” OrderDate=”1996-07-05T00:00:00″
RequiredDate=”1996-08-16T00:00:00″ />

<Contact ContactName=”Paula Wilson” OrderDate=”1998-05-06T00:00:00″
RequiredDate=”1998-06-03T00:00:00″ />
</ContactOrderDate>
SELECT c.ContactName, o.OrderDate, o.RequiredDate
FROM Customers c INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
FOR XML PATH(‘ContactOrderDate’)
Produce the following result:
<ContactOrderDate>
<ContactName>Paul Henriot</ContactName>
<OrderDate>1996-07-04T00:00:00</OrderDate>
<RequiredDate>1996-08-01T00:00:00</RequiredDate>
</ContactOrderDate>
<ContactOrderDate>
<ContactName>Karin Josephs</ContactName>
<OrderDate>1996-07-05T00:00:00</OrderDate>
<RequiredDate>1996-08-16T00:00:00</RequiredDate>
</ContactOrderDate>

<ContactOrderDate>
<ContactName>Paula Wilson</ContactName>
<OrderDate>1998-05-06T00:00:00</OrderDate>
<RequiredDate>1998-06-03T00:00:00</RequiredDate>
</ContactOrderDate>
SELECT c.ContactName, o.OrderDate, o.RequiredDate
FROM Customers c INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
FOR XML AUTO
Produce the following result:
<c ContactName=”Paul Henriot”>
<o OrderDate=”1996-07-04T00:00:00″ RequiredDate=”1996-08-01T00:00:00″ />
</c>
<c ContactName=”Karin Josephs”>
<o OrderDate=”1996-07-05T00:00:00″ RequiredDate=”1996-08-16T00:00:00″ />
</c>

<c ContactName=”Paula Wilson”>
<o OrderDate=”1998-05-06T00:00:00″ RequiredDate=”1998-06-03T00:00:00″ />
</c>
SELECT c.ContactName, o.OrderDate, o.RequiredDate
FROM Customers c INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
FOR XML AUTO, ROOT(‘ContactOrderDate’)
Produce the following result:
<ContactOrderDate>
<c ContactName=”Paul Henriot”>
<o OrderDate=”1996-07-04T00:00:00″ RequiredDate=”1996-08-01T00:00:00″ />
</c>
<c ContactName=”Karin Josephs”>
<o OrderDate=”1996-07-05T00:00:00″ RequiredDate=”1996-08-16T00:00:00″ />
</c>

<c ContactName=”Paula Wilson”>
<o OrderDate=”1998-05-06T00:00:00″ RequiredDate=”1998-06-03T00:00:00″ />
</c>
</ContactOrderDate>
QUESTION 108
You have a table named Customer that has an XML column named Locations. This column stores an
XML fragment that contains details of one or more locations, as show in the following examples.
<Location City=”Sydney” Address=”…” PhoneNumber=”…” />
<Location City=”Chicago” Address=”…” PhoneNumber=”…” />
<Location City=”London” Address=”…” PhoneNumber=”…” />
You need to write a query that returns a row for each of the customer’s locations. Each resulting row must
include the customer name, city, and an XML fragment that contains the location details.
Which query should you use?
A. SELECT CustomerName, Locations.query(‘for $i in /Location return data($i/@City)’), Locations.query
(‘for $i in /Location return $i’)
FROM Customer
B. SELECT CustomerName, Locations.query(‘for $i in /Location return element Location {$i/@City, $i}’)
FROM Customer
C. SELECT CustomerName, Locations.query(‘data(/Location/@City)’), Locations.query(‘/Location’) FROM
Customer
D. SELECT CustomerName, Loc.value(‘@City’,’varchar(100)’), Loc.query(‘.’)
FROM Customer CROSS APPLY Customer.Locations.nodes (‘/Location’) Locs(Loc)
Correct Answer: D
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 109
Click the Exhibit button.
You have the following XML:
<Site URL=”http://www.contoso.com/index.htm”&gt;
<Site URL=”http://www.contoso.com/finance/index.htm”&gt;
<Site URL=”http://www.contoso.com/finance/reports/index.htm&#8221; />
<Site URL=”http://www.contoso.com/finance/main/index.htm&#8221; />
</Site>
<Site URL=”http://www.contoso.com/marketing/index.htm”&gt;
<Site URL=”http://www.contoso.com/marketing/reports/index.htm&#8221; />
<Site URL=”http://www.contoso.com/marketing/main/index.htm&#8221; />
</Site>
<Site URL=”http://www.contoso.com/sales/index.htm&#8221; />
</Site>
You are tasked to query the sites listed in the XML by using OPENXML.
The results will have two columns, ParentSiteURL and SiteURL.
The ParentSiteURL column should contain the URL attribute of the parent site.
The SiteURL column should contain the URL attribute of the site itself.
The output should look like that in the exhibit.
You need to write the OPENXML query.
Which Transact-SQL statement should you use?
Exhibit:
A. SELECT ParentSiteURL, SiteURL
FROM OPENXML (@XMLDocHandle, ‘//@Site’, 1)
WITH ( ParentSiteURL nVarChar(512) ‘../URL’,
SiteURL nVarChar(512) ‘URL’)
B. SELECT ParentSiteURL, SiteURL
FROM OPENXML (@XMLDocHandle, ‘//URL’, 1)
WITH ( ParentSiteURL nVarChar(512) ‘../@URL’,
SiteURL nVarChar(512) ‘@URL’)
C. SELECT ParentSiteURL, SiteURL
FROM OPENXML (@XMLDocHandle, ‘//Site’, 1)
WITH ( ParentSiteURL nVarChar(512) ‘../@URL’,
SiteURL nVarChar(512) ‘@URL’)
D. SELECT ParentSiteURL, SiteURL
FROM OPENXML (@XMLDocHandle, ‘//@URL’, 1)
WITH ( ParentSiteURL nVarChar(512) ‘../URL’, SiteURL nVarChar(512) ‘URL’)
Correct Answer: C
Section: Section 6
Explanation
Explanation/Reference:
DECLARE @XMLDocHandle int,
@XMLDoc varchar(1000) =’
<Site URL=”http://www.contoso.com/index.htm”&gt;
<Site URL=”http://www.contoso.com/finance/index.htm”&gt;
<Site URL=”http://www.contoso.com/finance/reports/index.htm&#8221; />
<Site URL=”http://www.contoso.com/finance/main/index.htm&#8221; />
</Site>
<Site URL=”http://www.contoso.com/marketing/index.htm”&gt;
<Site URL=”http://www.contoso.com/marketing/reports/index.htm&#8221; />
<Site URL=”http://www.contoso.com/marketing/main/index.htm&#8221; />
</Site>
<Site URL=”http://www.contoso.com/sales/index.htm&#8221; />
</Site>';
–Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @XMLDocHandle OUTPUT, @XMLDoc
SELECT ParentSiteURL, SiteURL
FROM OPENXML (@XMLDocHandle, ‘//Site’, 1)
WITH ( ParentSiteURL nVarChar(512) ‘../@URL’,
SiteURL nVarChar(512) ‘@URL’)
QUESTION 110
Your company uses an application that passes XML to the database server by using stored procedures.
The database server has a large number of XML handles that are currently active. You determine that the
XML is not being flushed from SQL Server memory.
You need to identify the system stored procedure to flush the XML from memory.
Which Transact-SQL statement should you use?
A. sp_xml_removedocument
B. sp_xml_preparedocument
C. sp_reserve_http_namespace
D. sp_delete_http_namespace_reservation
Correct Answer: A
Section: Section 6
Explanation
Explanation/Reference:
sp_xml_removedocument removes the internal representation of the XML document specified by the
document handle and invalidates the document handle.
sp_xml_preparedocument reads the XML text provided as input, parses the text by using the MSXML
parser (Msxmlsql.dll), and provides the parsed document in a state ready for consumption. This parsed
document is a tree representation of the various nodes in the XML document: elements, attributes, text,
comments, and so on. A parsed document is stored in the internal cache of SQL Server. The MSXML
parser uses one-eighth the total memory available for SQL Server. To avoid running out of memory, run
sp_xml_removedocument to free up the memory.
QUESTION 111
You work for a company that provides marketing data to other companies.
You have the following Transact-SQL statement:
DECLARE @CustomerDemographics XML SET @CustomerDemographics=N’
<CustomerDemographics>
<Customer CustomerID=”1″ Age=”21″ Education=”High School”>
<IsCoffeeDrinker>0</IsCoffeeDrinker>
</Customer>
<Customer CustomerID=”2″ Age=”27″ Education=”College”>
<IsCoffeeDrinker>1</IsCoffeeDrinker>
<IsFriendly>1</IsFriendly>
</Customer>
<Customer CustomerID=”3″ Age=”35″ Education=”Unknown”>
<IsCoffeeDrinker>1</IsCoffeeDrinker>
<IsFriendly>1</IsFriendly>
</Customer>
</CustomerDemographics>’
DECLARE @OutputAgeOfCoffeeDrinkers XML
SET @OutputAgeOfCoffeeDrinkers = @CustomerDemographics.query(‘
for $output in /child::CustomerDemographics/child::Customer[( child::
IsCoffeeDrinker[1] cast as xs:boolean )]
return <CoffeeDrinkingCustomer> { $output/attribute::Age \} </
CoffeeDrinkingCustomer>’)
SELECT @OutputAgeOfCoffeeDrinkers
You need to determine the result of the query. What result should you expect?
A. <CoffeeDrinkingCustomer Age=”27″ />
<CoffeeDrinkingCustomer Age=”35″ />
B. <CoffeeDrinkingCustomer Age=”21″ />
C. <CustomerDemographics>
<Customer>
<CoffeeDrinkingCustomer Age=”21″ />
</Customer>
</CustomerDemographics>
D. <CustomerDemographics>
<Customer>
<CoffeeDrinkingCustomer Age=”27″ />
</Customer>
<Customer>
<CoffeeDrinkingCustomer Age=”35″ />
</Customer>
</CustomerDemographics>
Correct Answer: A
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 112
You have a table named Stores that has an XML column named OpenHours.
This column contains the opening and closing times.
<hours dayofWeek= “Monday” open =”8:00 AM” closed=”8:00 PM”
<hours dayofWeek= “Tuesday” open =”8:00 AM” closed=”8:00 PM”

<hours dayofWeek= “Saturday” open =”8:00 AM” closed=”8:00 PM”
You need to write a query that returns a list of stores and their opening time for a specified day.
Which code segment should you use?
A. DECLARE @Day VARCHAR(10) = ‘Tuesday’
SELECT StoreName, OpenHours.value(‘/hours[1]/@open’,’time’)
FROM Stores WHERE OpenHours.value(‘/hours[1]/@dayofWeek’,’varchar(20)’) = @Day
B. DECLARE @Day VARCHAR(10) = ‘Tuesday’
SELECT StoreName, OpenHours.value(‘/hours[1]/@open’,’time’)
FROM Stores WHERE OpenHours.exist(‘/hours[@dayofWeek=sql:variable("@Day")]‘) = 1
C. DECLARE @Day VARCHAR(10) = ‘Tuesday’
SELECT Storename, OpenHours.query(‘data(/hours[@dayofWeek=sql:variable("@Day")]/@open)’)
FROM Stores
D. DECLARE @Day VARCHAR(10) = ‘Tuesday’
SELECT StoreName, OpenHours.value(‘/hours[1][@dayofWeek=sql:variable("@Day")]/@open’,’time’)
FROM Stores
Correct Answer: C
Section: Section 6
Explanation
Explanation/Reference:
CREATE TABLE Stores(
StoreName VARCHAR(10)NOT NULL,
OpenHours [xml] NULL,
CONSTRAINT [PK_Stores] PRIMARY KEY CLUSTERED (StoreName))
GO
INSERT INTO Stores (StoreName, OpenHours)
VALUES
(
‘Store1′,
‘<hours dayofWeek= “Wednesday” open =”8:00 AM” closed=”8:00 PM”/>
<hours dayofWeek= “Tuesday” open =”9:00 AM” closed=”8:00 PM”/>
<hours dayofWeek= “Friday” open =”8:00 AM” closed=”8:00 PM”/>’),
(‘Store2′,
‘<hours dayofWeek= “Monday” open =”8:00 AM” closed=”8:00 PM”/>
<hours dayofWeek= “Tuesday” open =”8:00 AM” closed=”8:00 PM”/>
<hours dayofWeek= “Saturday” open =”8:00 AM” closed=”8:00 PM”/>’)
DECLARE @Day VARCHAR(10) = ‘Tuesday’
SELECT Storename, OpenHours.query(‘data(/hours[@dayofWeek=sql:variable
("@Day")]/@open)’)
FROM Stores
GO
QUESTION 113
You have the following XML document that contains Product information.
DECLARE @prodList xml =’
<ProductList xmlns=”urn:Wide_World_Importers/schemas/Products”>
<Product Name=”Product1″ Category=”Food” Price=”12.3″ />
<Product Name=”Product2″ Category=”Drink” Price=”1.2″ />
<Product Name=”Product3″ Category=”Food” Price=”5.1″ />

</ProductList>';
You need to return a list of products that contains the Product Name, Category, and Price of each product.
Which query should you use?
A. SELECT prod.value(‘.[1]/@Name’,’varchar(100)’), prod.value(‘.[1]/@Category’,’varchar(20)’), prod.value
(‘.[1]/@Price’,’money’)
FROM @prodList.nodes(‘/ProductList/Product’) ProdList(prod);
B. SELECT prod.value(‘@Name’,’varchar(100)’), prod.value(‘@Category’,’varchar(20)’), prod.value
(‘@Price’,’money’)
FROM @prodList.nodes(‘/ProductList/Product’) ProdList(prod);
C. WITH XMLNAMESPACES(DEFAULT ‘urn;Wide_World_Importers/schemas/Products’ as o)
SELECT prod.value(‘Name[1]‘,’varchar(100)’), prod.value(‘Category[1]‘,’varchar(20)’), prod.value(‘Price
[1]‘,’money’)
FROM @prodList.nodes(‘/o:ProductList/o:Product’) ProdList(prod);
D. WITH XMLNAMESPACES(DEFAULT ‘urn:Wide_World_Importers/schemas/Products’)
SELECT prod.value(‘./@Name’,’varchar(100)’), prod.value(‘./@Category’,’varchar(20)’), prod.value(‘./
@Price’,’money’)
FROM @prodList.nodes(‘/ProductList/Product’) ProdList(prod);
Correct Answer: D
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 114
You have a table named Products.Product. The table has columns ProductID, Name, Size, and Category.
You have a variable named @XML with following XML value:
<Root>
<Category Name=”Socks” />
<Category Name=”Pants” />
<Category Name=”Shirts” />
</Root>
You are tasked to write a query that lists the products in Products.Product that match the categories listed
in the XML document. You need to write a query to accomplish the task. Which query should you write?
A. SELECT p.ProductID, p.Name, p.Size, p.Category
FROM Production.Product p CROSS APPLY @XML.nodes(‘//Category’) as x(s)
B. SELECT p.ProductID, p.Name, p.Size, p.Category
FROM Production.Product p OUTER APPLY @XML.nodes(‘//Category’) as x(s)
C. WITH XMLTable AS (
SELECT s.value(‘@Name’,’varchar(20)’) as Category FROM @XML.nodes(‘//Category’) as x(s) )
SELECT p.ProductID, p.Name, p.Size, p.Category FROM Production.Product p
INNER JOIN XMLTable x ON p.Category = x.Category
D. WITH XMLTable AS (
SELECT s.value(‘@Category’,’varchar(20)’) as Category FROM @XML.nodes(‘//Category’) as x(s) )
SELECT p.ProductID, p.Name, p.Size, p.Category FROM Production.Product p INNER JOIN XMLTable
x ON p.Category = x.Category
Correct Answer: C
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 115
Your company exchanges information with other companies by using XML and Web services. Your
manager asks you to remove a schema collection that is no longer used. Before dropping the schema, you
should confirm that it is no longer in use.
You need to use a catalog view to determine if the schema collection is being used. Which catalog view
should you use?
A. sys.xml_schema_components
B. sys.xml_schema_namespaces
C. sys.xml_schema_collections
D. sys.column_xml_schema_collection_usages
Correct Answer: D
Section: Section 6
Explanation
Explanation/Reference:
sys.column_xml_schema_collection_usages returns a row for each column that is validated by an XML
schema.
QUESTION 116
You have an XML schema that you must use to validate XML data in your database. You need to store this
XML schema. Which code segment should you use?
A. CREATE SCHEMA CustomerSchema
B. CREATE DEFAULT CustomerSchema AS ‘XML’
C. CREATE PRIMARY XML INDEX CustomerSchema
D. CREATE XML SCHEMA COLLECTION CustomerSchema
Correct Answer: D
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 117
You have a table named Customers that has an XML column named CustomerData. There are currently no
indexes on the table.
You use the following WHERE clause in a query:
WHERE CustomerData.exist (‘/CustomerDemographic/@Age[.>="21"]‘) = 1
You need to create indexes for the query.
Which Transact-SQL statements should you use?
A. CREATE CLUSTERED INDEX CL_IDX_Customer ON Customers(CustomerID);
CREATE PRIMARY XML INDEX PXML_IDX_Customer ON Customers(CustomerData);
CREATE XML INDEX SXML_IDX_Customer ON Customer(CustomerData)
USING XML INDEX PXML_IDX_Customer FOR PATH;
B. CREATE PRIMARY XML INDEX PXML_IDX_Customer ON Customers(CustomerData);
CREATE XML INDEX SXML_IDX_Customer ON Customer(CustomerData)
USING XML INDEX PXML_IDX_Customer FOR VALUE;
C. CREATE PRIMARY XML INDEX PXML_IDX_Customer ON Customers(CustomerData);
CREATE XML INDEX SXML_IDX_Customer ON Customer(CustomerData)
USING XML INDEX PXML_IDX_Customer FOR PATH;
D. CREATE CLUSTERED INDEX CL_IDX_Customer ON Customers(CustomerID);
CREATE PRIMARY XML INDEX PXML_IDX_Customer ON Customers(CustomerData);
CREATE XML INDEX SXML_IDX_Customer_Property ON Customer(CustomerData)
USING XML INDEX PXML_IDX_Customer FOR VALUE;
Correct Answer: A
Section: Section 6
Explanation
Explanation/Reference:
The primary XML index indexes all tags, values, and paths within the XML instances in an XML column. To
create a primary XML index, the table in which the XML column occurs must have a clustered index on the
primary key of the table. SQL Server uses this primary key to correlate rows in the primary XML index with
rows in the table that contains the XML column.
The first index on the xml type column must be the primary XML index. Using the primary XML index, the
following types of secondary indexes are supported: PATH, VALUE, and PROPERTY.
Following are some guidelines for creating one or more secondary indexes:
If your workload uses path expressions significantly on XML columns, the PATH secondary XML index is
likely to speed up your workload. The most common case is the use of the exist() method on XML columns
in the WHERE clause of Transact-SQL.
If your workload retrieves multiple values from individual XML instances by using path expressions,
clustering paths within each XML instance in the PROPERTY index may be helpful. This scenario typically
occurs in a property bag scenario when properties of an object are fetched and its primary key value is
known.
If your workload involves querying for values within XML instances without knowing the element or attribute
names that contain those values, you may want to create the VALUE index. This typically occurs with
descendant axes lookups, such as //author[last-name="Howard"], where <author> elements can occur at
any level of the hierarchy. It also occurs in wildcard queries, such as /book [@* = "novel"], where the query
looks for <book> elements that have some attribute having the value “novel”.
QUESTION 118
You need to capture the execution plan for a query. Which statement should you use?
A. SET FORCEPLAN ON;
B. SET SHOWPLAN_XML ON;
C. SET STATISTICS IO ON;
D. SET STATISTICS TIME ON;
Correct Answer: B
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 119
You are troubleshooting query performance on SQL Server 2008. You are tasked to create an estimated
execution plan by using Transact-SQL. You should be able to view the plan graphically in SQL Server
Management Studio. You need to ensure that the execution plan can be saved as a .sqlplan file.
Which Transact-SQL setting should you use?
A. SET SHOWPLAN_ALL ON;
B. SET SHOWPLAN_XML ON;
C. SET STATISTICS XML ON;
D. SET STATISTICS PROFILE ON;
Correct Answer: B
Section: Section 6
Explanation
Explanation/Reference:
SET SHOWPLAN_XML ON
This statement causes SQL Server not to execute Transact-SQL statements. Instead, Microsoft SQL
Server returns execution plan information about how the statements are going to be executed in a wellformed
XML document.
SET SHOWPLAN_TEXT ON
After this SET statement is executed, SQL Server returns the execution plan information for each query in
text. The Transact-SQL statements or batches are not executed.
SET SHOWPLAN_ALL ON
This statement is similar to SET SHOWPLAN_TEXT, except that the output is in a format more verbose
than that of SHOWPLAN_TEXT.
SET STATISTICS XML ON
Returns execution information for each statement after the statement executes in addition to the regular
result set the statement returns. The output is a set of well-formed XML documents. SET STATISTICS XML
ON produces an XML output document for each statement that executes. The difference between SET
SHOWPLAN_XML ON and SET STATISTICS XML ON is that the second SET option executes the
Transact-SQL statement or batch. SET STATISTICS XML ON output also includes information about the
actual number of rows processed by various operators and the actual number of executes of the operators.
SET STATISTICS PROFILE ON
Returns the execution information for each statement after the statement executes in addition to the regular
result set the statement returns. Both SET statement options provide output in text. The difference between
SET SHOWPLAN_ALL ON and SET STATISTICS PROFILE ON is that the second SET option executes
the Transact-SQL statement or batch. SET STATISTICS PROFILE ON output also includes information
about the actual number of rows processed by various operators and the actual number of executes of the
operators.
QUESTION 120
You are troubleshooting query performance on SQL Server 2008. You are tasked to capture a graphical
execution plan. You need to save the plan to a file that can be used by SQL Server Management Studio to
display the graphical execution plan.
Which file extension should you use?
A. .gif
B. .xml
C. .psql
D. .sqlplan
Correct Answer: D
Section: Section 6
Explanation
Explanation/Reference:
QUESTION 121
You have run a server side trace that created 45 trace files. You want to load the trace files on your
workstation in a database table called PerfData for further analysis. You need to load three files starting at
c:\my_trace_38.trc.
Which Transact-SQL statement should you use?
A. SELECT * INTO PerfData
FROM ::fn_trace_gettable(‘c:\my_trace.trc’, 3)
B. SELECT * INTO PerfData
FROM ::fn_trace_gettable(‘c:\my_trace_38.trc’, 3)
C. SELECT * INTO PerfData
FROM ::fn_trace_gettable(‘c:\my_trace38.trc’, default)
D. SELECT * INTO PerfData
FROM ( SELECT * FROM ::fn_trace_gettable (‘c:\my_trace_38.trc’, default)
UNION ALL
SELECT * FROM ::fn_trace_gettable (‘c:\my_trace_39.trc’, default)
UNION ALL
SELECT * FROM ::fn_trace_gettable (‘c:\my_trace_40.trc’, default) ) Trc
Correct Answer: B
Section: Section 7
Explanation
Explanation/Reference:
sys.fn_trace_gettable returns the content of one or more trace files in tabular form.
fn_trace_gettable ( ‘filename’ , number_files )
‘filename’
Specifies the initial trace file to be read. filename is nvarchar(256), with no default.
number_files
Specifies the number of rollover files to be read. This number includes the initial file specified in filename.
number_files is an int.
If number_files is specified as default, fn_trace_gettable reads all rollover files until it reaches the end of the
trace.
QUESTION 122
You are using SQL Server Profiler to gather deadlock information. You need to capture an XML description
of a deadlock. Which event should you use?
A. Lock:Deadlock
B. Showplan XML
C. Deadlock Graph
D. Lock:Deadlock Chain
Correct Answer: C
Section: Section 7
Explanation
Explanation/Reference:
The Lock:Deadlock event class is produced when an attempt to acquire a lock is canceled because the
attempt was part of a deadlock and was chosen as the deadlock victim.
Use the Lock:Deadlock event class to monitor when deadlocks occur and which objects are involved. You
can use this information to determine if deadlocks are significantly affecting the performance of your
application. You can then examine the application code to determine if you can make changes to minimize
deadlocks.
The Deadlock Graph event class provides an XML description of a deadlock. This class occurs
simultaneously with the Lock:Deadlock event class.
The Lock:Deadlock Chain event class is produced for each participant in a deadlock.
QUESTION 123
You are troubleshooting query performance on SQL Server 2008. You have profiler trace data in a table
named PerfData. You need to determine which events are taking longer than one second of CPU time or
run for more than two seconds.
Which Transact-SQL statement should you use?
A. SELECT TextData, Duration, CPU FROM PerfData
WHERE EventClass = 12 AND ( CPU > 1000 OR Duration > 2000 )
B. SELECT TextData, Duration, CPU FROM PerfData
WHERE EventClass = 12 AND ( CPU > 1000 OR Duration > 2000000 )
C. SELECT TextData, Duration, CPU FROM PerfData
WHERE EventClass = 12 AND ( CPU > 1000000 OR Duration > 2000 )
D. SELECT TextData, Duration, CPU FROM PerfData
WHERE EventClass = 12 AND ( CPU > 1000000 OR Duration > 2000000 )
Correct Answer: B
Section: Section 7
Explanation
Explanation/Reference:
Beginning with SQL Server 2005, the server reports the duration of an event in microseconds (one millionth,
or 10-6, of a second) and the amount of CPU time used by the event in milliseconds (one thousandth, or
10-3, of a second). In SQL Server 2005 and later, the SQL Server Profiler graphical user interface displays
the Duration column in milliseconds by default, but when a trace is saved to either a file or a database table,
the Duration column value is written in microseconds.
QUESTION 124
You are using the Database Engine Tuning Advisor (DTA) to analyze a workload. You need to save the
recommendations generated by the DTA. Which command should you use?
A. Preview Workload Table
B. Export Session Results
C. Import Session Definition
D. Export Session Definition
Correct Answer: B
Section: Section 7
Explanation
Explanation/Reference:
QUESTION 125
You need to capture and record a workload for analysis by the Database Engine Tuning Advisor (DTA).
Which tool should you use?
A. DTA utility
B. Activity Monitor
C. SQL Server Profiler
D. Performance Monitor
Correct Answer: C
Section: Section 7
Explanation
Explanation/Reference:
QUESTION 126
You have a database that uses stored procedures to perform INSERT, UPDATE, DELETE, and SELECT
statements.
You are tasked with providing a recommendation of indexes to be created and dropped from the database.
You need to select the appropriate method to accomplish the task.
Which method should you use?
A. Index Usage DMVs
B. Missing Index DMVs
C. SQL Server Profiler
D. Database Engine Tuning Advisor
Correct Answer: D
Section: Section 7
Explanation
Explanation/Reference:
QUESTION 127
You are tasked with creating a workload that will be used by the Database Engine Tuning Advisor (DTA).
You need to create a workload in an appropriate format.
Which format should you choose? (Each correct answer represents a complete solution. Choose three.)
A. XML File
B. Transact-SQL Script
C. SQL Server Event Log
D. SQL Server Transaction Log
E. SQL Server Profiler Trace File
F. Performance Counter Log File
Correct Answer: ABE
Section: Section 7
Explanation
Explanation/Reference:
Database Engine Tuning Advisor uses trace files, trace tables, Transact-SQL scripts, or XML files as
workload input when tuning databases.
QUESTION 128
You need to build CREATE INDEX statements for all the missing indexes that SQL Server has identified.
Which dynamic management view should you use?
A. sys.dm_db_index_usage_stats
B. sys.dm_db_missing_index_details
C. sys.dm_db_missing_index_columns
D. sys.dm_db_missing_index_group_stats
Correct Answer: B
Section: Section 7
Explanation
Explanation/Reference:
sys.dm_db_missing_index_details returns detailed information about missing indexes, excluding spatial
indexes.
QUESTION 129
You notice that a database server is responding slowly to queries. You run the following dynamic
management views (DMV) query on the server.
SELECT TOP (10) wait_type, wait_time_ms FROM sys.dm_os_wait_stats
ORDER BY wait_time_ms DESC;
The query returns a top wait type of SOS_SCHEDULER_YIELD.
You need to identify what is causing the server response issues. Which resource should you investigate
first?
A. Disk
B. CPU
C. Memory
D. Network
Correct Answer: B
Section: Section 7
Explanation
Explanation/Reference:
QUESTION 130
You attempt to query sys.dm_db_index_usage_stats to check the status on the indexes in the Contoso
database. The query fails and you receive the following error:
“The user does not have permission to perform this action.”
You need to have the least amount of permissions granted to access the dynamic management views.
Which permissions should be granted?
A. CONTROL
B. VIEW SERVER STATE
C. VIEW DATABASE STATE
D. CREATE EXTERNAL ACCESS ASSEMBLY
Correct Answer: B
Section: Section 7
Explanation
Explanation/Reference:
QUESTION 131
You are given a database design to evaluate. All of the tables in this database should have a clustered
index.
You need to determine the tables that are missing a clustered index by using the system catalog views.
Which Transact-SQL statement should you use?
A. SELECT name AS table_name FROM sys.tables
WHERE OBJECTPROPERTY(object_id,’TableHasClustIndex’) = 0
ORDER BY name;
B. SELECT name AS table_name
FROM sys.tables WHERE OBJECTPROPERTY(object_id,’TableHasUniqueCnst’) = 0 ORDER BY
name;
C. SELECT name AS table_name FROM sys.tables
WHERE OBJECTPROPERTY(object_id,’TableHasClustIndex’) = 0 AND
OBJECTPROPERTY(object_id,’TableHasUniqueCnst’) = 1 ORDER BY name;
D. SELECT name AS table_name FROM sys.tables
WHERE OBJECTPROPERTY(object_id,’TableHasClustIndex’) = 1 AND OBJECTPROPERTY
(object_id,’TableHasUniqueCnst’) = 1
ORDER BY name;
Correct Answer: A
Section: Section 7
Explanation
Explanation/Reference:
QUESTION 132
You need to identify which tables are referenced by name in a stored procedure that does not use dynamic
SQL.
Which catalog view should you use?
A. sys.procedures
B. INFORMATION_SCHEMA.TABLES
C. INFORMATION_SCHEMA.ROUTINES
D. sys.sql_expression_dependencies
Correct Answer: D
Section: Section 7
Explanation
Explanation/Reference:
QUESTION 133
4.
You need to manually raise an error.
The error message that will be returned will display a message that contains
parameters 1, 2, 3
sp_addmessage @msgnum = 6000,
@severity = 16,
@msgtext = N’Your message (%d), (%d), (%d)';
GO
You have to raise message to get correct message.. ‘Your message (1), (2), (3).’
Which statement will you use?
A. RAISE_ERROR(60000, 16, 1, 1, 2, 3)
Correct Answer: A
Section: New questions
Explanation
Explanation/Reference:
CORRECT ANSWER:
RAISERROR (6000, — Message id.
16, — Severity,
1, — State,
, 1, 2, 3)
QUESTION 134
You are reviewing a trigger in the database which was deployed with the folowing script:
EXECUTE AS USER = ‘BuildUser’
GO
CREATE TRIGGER Inventory.TR_Stock ON Inventory.Stock
FOR INSERT, UPDATE, DELETE
EXECUTE AS SELF
AS …
A user ‘WebUser’ insert rows into Inventory.Stock table. You need to identify under which security context
the trigger will execute.
A. DBO
B. Inventory
C. WebUser
D. BuildUser
Correct Answer: D
Section: New questions
Explanation
Explanation/Reference:
QUESTION 135
Your database contains Products and Orders tables. You need to write a query which return ProductID of
the products which have not been placed in any order. Which operator can you use.
A. Union
B. Union ALL
C. Intersect
D. Exclude
Correct Answer: D
Section: New questions
Explanation
Explanation/Reference: