QV Developer II Course QV10 PRINT
Comments
Description
Developer IIJanuary 2011 Release QlikView Version 10.00 English Copyright © 2011 QlikTech International AB, Sweden. Under international copyright laws, neither the documentation nor the software may be copied, photocopied, reproduced, translated or reduced to any electronic medium or machinereadable form, in whole or in part, without the prior written permission of QlikTech International AB, except in the manner described in the software agreement. Qlik®Tech and Qlik®View are registered trademarks of QlikTech International AB. Microsoft, MS-DOS, Windows, Windows NT, Windows 2000, Windows Server 2003, Windows Server 2008, Windows XP, Windows Vista, SQL Server, Excel, Access, Visual Basic, Internet Explorer, Internet Information Server, Visual C++, Visual Studio and MS Query are trademarks of Microsoft Corporation. IBM, AS/400 and PowerPC are trademarks of International Business Machines Corporation. Firefox is a trademark of the Mozilla Foundation. Apple, iPhone, iPod Touch, Safari and MacOS is a trademark of Apple Corporation. BlackBerry is a trademark of Research In Motion. This release: January 2011 CONTENT 1 2 3 INTRODUCTION 7 Installing the Course Materials Program versions Text formats 7 7 7 DEVELOPER TOOLS 9 Troubleshooting The Debugger 9 9 MAPPING TABLES Mapping Quarters to the Orders table MonthYear Cleaning up the table structure 4 LOADING BUDGET DATA Reading Cross Tables 5 ADVANCED SCRIPTING Condition on a field in a table Aggregating Data Joining tables Concatenation Preceding Load on Preceding Load 6 ADVANCED CALCULATIONS IN SHEET OBJECTS Set Analysis Dollar-Sign Expansion AGGR Function 19 19 23 26 31 31 39 39 39 39 40 41 51 51 54 56 QlikView Developer II | CONTENT 7 SCRIPTING AND DATA MODELING CHALLENGES Link Tables and Concatenated Tables Calculating net change within a field Functions InDate, Data & DateIslands Aggr() Class() Dynamic Aggregation IntervalMatch 8 9 DATA MODEL OPTIMIZATION 63 63 64 64 65 65 65 81 Performance Tuning Best Practices for QlikView File Optimization Creating Incremental Loads 81 83 85 DAILY AND TRANSACTION BALANCES 95 Overview Example: Balances at Specific Dates Example: Balances for Transactions (in/out) 95 95 98 10QLIKVIEW SECURITY Access control Access levels Access control database Inherited access restrictions Hidden script Adding Section Access Access control for certain commands Further access control Unattended Command Line Reload Considerations Access restrictions on selected field values Field value limitation in Section Access 11ADVANCED DATABASE CONNECTIVITY Custom Data SAP Connector 4 63 101 101 101 102 103 104 104 109 110 111 111 112 115 115 116 QlikView Developer II | CONTENT 12BUSINESS CASE WORKSHOP Scenario Data Structure 119 119 121 5 QlikView Developer II | CONTENT 6 QlikView Developer II | 1 INTRODUCTION 1 INTRODUCTION Many students will come to this course having already taken QlikView classroom training. This chapter covers formatting and coventions used in the course manual. 1.1 Installing the Course Materials The course materials will self-extract from the file into the default directory C:\QlikViewTraining\DeveloperII\ Make a Windows shortcut to this folder and place it on your desktop. Also make a Windows shortcut to the documentation folder and place it on your desktop. C:\Program Files\QlikView\Documentation or C:\Prrogram Files (x86)\QlikView\Documentation 1.2 Program versions This course was created using the English version of QlikView 10.00 running on Windows7. If other operating systems or languages are used, minor differences may be noted in the visual appearance of windows and dialog boxes. 1.3 Text formats Exercises and actions to be completed by you, the student, will be set-off with a logo, as you see, below: Exercise/Do: This is a sample of instructions you would see to complete an exercise containing a sequence of steps. 1 2 3 Click on the Start button Locate the QlikView icon Click on the QlikView icon to launch the program All commands, as well as all names of menus, dialogs and buttons are in the following font style: File - Open All names of list boxes, graphs and specific data in list boxes, etc. are in the following font style: Country All file names are in the following font style: QlikViewCourse.qvw 7 QlikView Developer II | 1 INTRODUCTION Tips and Notes are outlined in a highlighted box, as you see below: This sample sentence is used to illustrate important points in the text, tips and notes to consider as you complete the course materials 8 QlikView Developer II | 2 DEVELOPER TOOLS 2 DEVELOPER TOOLS Objectives • • • Understand the importance of troubleshooting Use the debugger Introduce additional tools and methods 2.1 Troubleshooting Debugging is an art. There are best practices and guidelines that can help in the debugging process. The key point to take away from debugging is to change one item at a time and then examine the impact of that change. If more than one item is changed without an examination, debugging becomes difficult. This portion of the class will not teach you how to debug an document but will point you in the direction of where to look if your document does not operate or look like you expected it to. These basic tools and processes are the best place to start when debugging a QlikView document. Also, during script execution in debug mode, the debugger allows for monitoring of variables. This is useful for validation of variable state at different stages of script execution. Remember, always make sure the Generate Logfile checkbox is checked under Settings|Document Properties|General. Also remember, missing or misplaced commas and semicolons are the source of many error messages. Check for these common problems first. 2.2 The Debugger Where is that Breakpoint, Check the Variables Breakpoints stop script processing to give you a chance to troubleshoot. They can be placed in your script with the Debug option in the QlikView Script Editor. Breakpoints only stop script processing if placed on the line of the first statement in a code block that is terminated by a semi-colon. Setting a breakpoint on any other statement in the code block has no effect on breaking the script as it runs. 9 QlikView Developer II | 2 DEVELOPER TOOLS Figure 1. Breakpoints You will notice in the Figure above that three breakpoints are set at lines 38, 39 and 44. Note that the debugger will not stop at line 39 since it is not the first statement in the code block. This could be a LOAD statement, a SQL LOAD with a preceding LOAD, or a grouped LOAD statement. If you trace each statement back from the semicolon you will see that while the key word MAPPING on line 39 is part of a code block ending in a semi-colon, MAPPING is not the first line of the code block – Shippers: is. 2.2.1 Variables If you have created variables in the load script, you can view the value of the variable as the script is loading. You might be surprised that it does not hold the expected value(s). Create additional variables to investigate more states during script loading. 10 QlikView Developer II | EXERCISE Exercise: Debugging Do: 1 2 3 4 5 6 7 8 9 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder. Load the file Debugging.qvw into Qlikview and try loading data into QlikView after setting multiple breakpoints, step through the code and see where the debugger stops. Also, check the values of the variables Open the file \Debugging\Variable.qvw. Enter the debugger from the script editor and check the breakpoints that have been set in the script Use the Run button to execute the script up until the following breakpoint. Note that the variable mySetVar is not listed in the bottom right variable monitor pane. Hit Run again and note that the value of the mySetVar variable has been set. Hit Run once more and exit the script. Repeat steps 3 to 6 and note on step 4 that the variable mySetVar still retains the value from the previous execution. Go to Settings | Variable Overview and note that the script variable mySetVar (once created) is stored and accessible from within QlikViewDesktop. Remember, intermittent values of script variables can be monitored through the debugger. The scope of script variables is not limited to a single script execution, which is to say the variables persist between executions. 11 QlikView Developer II | 2 DEVELOPER TOOLS 2.2.2 Using the Table Box Sheet Object The Table Box is the developer’s best friend. It is great for identifying how data relates and where data might be missing. The table object is great for viewing row-level data relationships between different fields. For ease of use, a table box may have dropdown select enabled from the Presentation tab enabling the developer to quickly navigate each field / column and make text query selections. Creating a Table Box is easy and one can add columns from multiple tables as well as add dropdown selects to the columns (fields) in the table. Note the Dropdown Select checkbox in the Figure below; the dropdown select allows you to select and search for data in the Table Box. This will help you understand how the data relates across your tables. Figure 2. Adding Dropdown Select You can also see where NULL values happen across tables and within fields. NULL values can adversely affect a document and the selection of data. 12 QlikView Developer II | EXERCISE Exercise Do: 1 2 3 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder. Open the document KeyFields.qvw and go to the Main tab where you will see a table. Select a cell that holds data and note that any row with an identical field value will be displayed with the corresponding columns of data with which it is associated. Next, clear the selections (the Clear button) and select a cell that has a null (the default representation is a “–“ character). Note that nothing happens. Note: You are seeing disjointed information, which can be problematic. You can explore the causes of this condition by examining key fields. Remember, Table boxes are great for understanding and validating data relationships. Only included / possible values are displayed in a table box. 13 QlikView Developer II | 2 DEVELOPER TOOLS 2.2.3 Making Copies of Key Fields How might this disjointed condition have been created? • A LEFT JOIN • A MAPPING table operation • Bad data • Key field mismatches Key Fields connect tables in QlikView, but examining them will not always display the information you might expect. Showing a Key Field in a Sheet Object such as a Table Box, displays all possible values from the Key Field in any and all connected tables – any table(s) could contain distinct values that do not match any values in any other table(s). To get an understanding of what is happening in every table on every side of a Key Field, load a copy of the Key Field in every table and uniquely rename each Key Field copy with an AS clause. Reload your document, create List Boxes for all fields, then do a SELECT ALL on one of the fields that is an alias of the Key Field. Finally, SELECT EXCLUDED on the Key Field by right clicking the Key Field List Box. You can see, through the selection and exclusion, which items are joined through the Key Field and which are not. This problem usually happens when there is missing data. You can also return erroneous results if you are looking at different discreet levels of information in the model. This condition is covered later in the course. 14 QlikView Developer II | EXERCISE Exercise Do: 1 2 3 4 5 6 7 8 9 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder. Open the document KeyFields.qvw Comment the script on the Standard Join tab and uncomment the script on the Copy of Keys tab. Save and reload. Note that the key field in each table has been renamed uniquely, i.e., Key AS Key1_Table1. Create List Boxes for all fields. SELECT ALL on one of the aliased key fields. SELECT EXCLUDED on the Key field (right click in the Key field List Box and choose SELECT EXCLUDED). Observe the matches and mismatches between the keys in each table. Note: By the use of the 'Select all', 'Select possible' and 'Select excluded' selection modes on key copy fields, it is possible to investigate joined and disjointed data within your data structure. Debugging: Examples and Steps When building and debugging complex equations, take two approaches: 1 2 Take a sample of the data and do not create a data model that is more that two tables, if possible. There should not be more than three columns in each table or more that fifteen rows. Use the inline wizard or Excel to create the tables. When building complex expressions, use a Straight Table chart and build expressions a single column at a time. Do: 1 2 3 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder. Open the ComplexEquations.QVW. Create a Straight Table chart with CompanyName as the dimension plus the following expressions: Expression Label Sum(LineSalesAmount) Sales Count(LineNo) Lines Avg(LineSalesAmount) AvgSales Sum(Quantity) Qty 4 Finish with 2 more expressions: 15 QlikView Developer II | EXERCISE Expression Qty/Lines Sales/Qty Label AvgQty UnitPrice Here you see that you can type an expression directly or you can use an expression label as an alias to the expression to get the same results. Note: You can also reference an expression by its Table Column number (zero-based index) but DON’T DO IT! 5 Build your complex expression one column at a time and then move the expression to the placeholder of the Label that is referenced in the expression. This is the best approach for slowly building complex expressions. Note: You cannot nest aggregations (aggregate an aggregation) except by using the aggr() function, covered later in this course. Dates In many cases, date fields are key fields. To join tables from different systems, there are cases where dates need to be converted to a common format before dates from disparate datasources will match properly. It is always a good idea to check the key field using a Table Box to verify that the date format is consistent throughout the entire key field. Do: 1 2 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder. Open a working copy of the Dates.qvw file and load the data from the Dates.XLS file in the Datasources folder. Create two tables in the script. Your script should look like this: 16 QlikView Developer II | EXERCISE 3 Next, create a Table Box including all columns, sort by Date ascending, and scan the data. You should see something like the Table Box below. Note that the dates look the same but similar dates do not link. 4 To determine what is causing the problem, create a Text Object that displays the expression =num(Date, ‘###.######’) and alternately select each of the two similar dates. Note the fractional part of each displayed date in the Text Object. The date from one table is actually a timestamp while the other date has no time associated with it. 17 QlikView Developer II | EXERCISE 5 Next fix Date2 with the floor() function (floor(Date2)) changing Date2 from a timestamp to a date. (Note the floor() function truncates a decimal number and returns the next lower integer value, i.e., 2.7 becomes 2). Now reload the data. The result should look like this where you have rows that now link. 6 As an alternative, try using the daystart() function on the dates in both tables. Verify the results are the same. Hide the fact that both dates are now timestamps starting at midnight. Note: Be wary when comparing dates. Ensure that the granularity is the same and stored in the same manner in each date field. (e.g. Day level dates stored without a time component, month level dates stored as the first day of each month, etc. 18 QlikView Developer II | 3 MAPPING TABLES 3 MAPPING TABLES Objectives • • • Understand mapping tables Use mapping tables to add Quarters to the Orders table Clean up the table structure Sometimes you need to add an extra field to a table to use a combination of fields from different tables, or you want to add a field to clean up the data structure. QlikView has an effective way to add single fields to a table called mapping tables. In this chapter, we will take a look at how mapping tables work. 3.1 Mapping Quarters to the Orders table The Quarters table is useful, in that it links our Month data in the Orders table with the correct Quarter. However, the Month field is now a key field, and this will probably cause problems later. The following illustrations give us a visual of this dilemma: Figure 1. Quarters Table key link on Month. 19 QlikView Developer II | 3 MAPPING TABLES Figure 2. Month field with key indicator in the Available Fields listing. By changing our Quarters table into a MAPPING table, we will be able to integrate the Quarters field into the same table as Month (the Orders table). The MAPPING prefix is used on a LOAD or SELECT statement to create a mapping table. Tables read via MAPPING LOAD or MAPPING SELECT are treated differently from other tables. They will be stored in a separate area of memory and used only as mapping tables during script execution. After script execution they will be automatically dropped. A mapping table must have two fields, the first one containing comparison values and the second the desired mapping values. The two fields must be named, but the names have no relevance in themselves. The field names have no connection to field names in regular input tables. When mapping tables are used to map a certain field value or expression, that value will be compared to the values in the first field of the mapping table. If found, the original value will be replaced by the corresponding value in the second field of the mapping table. If not found, no replacement is made. The syntax is: mapping ( load statement | select statement ) 20 QlikView Developer II | EXERCISE Exercise Do: 1 2 3 4 5 6 7 Launch QlikView and save a working copy of the MappingTables.qvw QlikView file in the working directory for this chapter (C:\QlikViewTraining\DeveloperII\Chapter03). Open the Edit Script dialog. Now, let us change the Quarters table load into a mapping load. On the Main tab uncomment the Quarters table load statement you want to use. Make sure that the other table is still commented so that you do not read from two Quarters tables. Add _Map to the table name. On the next line, type MAPPING in front of the LOAD statement. When complete, verify that this section of your script resembles the following: Quarters_Map: MAPPING LOAD rowno() as Month, 'Q' & Ceil(rowno()/3) as Quarter Autogenerate(12); Do not save and close just yet. If you reload the data now, you will lose the Quarters table and field, since mapping tables are temporary. However, we can use the Quarters_Map table in our script (as long as we use it after it is defined in the script). To do this, we will use the applymap function. The syntax is: applymap( 'mapname', expr, [ , defaultexpr ] ) 8 The applymap function maps any expression on a previously loaded mapping table. Mapname is the name of a mapping table previously loaded by a MAPPING LOAD or MAPPING SELECT statement. The name must be quoted with single quotes. Expr is the expression whose result will be mapped.Defaultexpr is an optional expression, which will be used as the default mapping value if the mapping table does not contain any matching value for expr. If no default is provided, the value of expr is returned is unchanged. Add an applymap function to the Orders table, based on the numeric value of Month. This function should refer to the Quarters_Map table. Refer to the syntax example that follows: applymap('Quarters_Map',num(month(OrderDate)), null()) AS Quarter, 21 QlikView Developer II | EXERCISE 9 Save and Reload the document. 10 Open the Table Viewer to verify the Quarters table is gone and that there is now a field called Quarter in the Orders table. Figure 3. Using ApplyMap to embed fields into another table 22 QlikView Developer II | 3 MAPPING TABLES 3.2 MonthYear We will complete our time dimension fields by creating a new field that makes every month unique. There are, of course, several ways to accomplish this. In this course, we will create the field MonthYear by using QlikView date functions based on the OrderDate field, along with a date formatting function to provide the correct display format for our new month field. 23 QlikView Developer II | EXERCISE Exercise Do: 1 2 3 4 Return to the MappingTables.qvw file you have been working on in this chapter. Open the Edit Script dialog from the menu or toolbar. Locate the Orders table LOAD statement. Immediately following the applymap… as Quarter field line, create a new field named MonthYear in the LOAD statement for the table Orders, as follows: date(monthstart(OrderDate),'MMM-YYYY') AS MonthYear, The monthstart function returns the first day of the month of the OrderDate value. The date function then formats this value into a 3-character month name, followed by a 4-digit year. Since QlikView stores this field as both a text string (the format we just specified) and as a numeric, it can be sorted numerically, as you would expect. The complete Orders table LOAD statement should now look as follows. Be sure your script syntax matches this. Note, your Quarter and MonthYear fields line will likely fit on a single line instead of wrapping as seen below. //*************** Orders table *************** Orders: LOAD CustomerID, EmployeeID, EmployeeID AS EmployeeSalesID, Freight, OrderDate, year(OrderDate) AS Year, month(OrderDate) AS Month, day(OrderDate) AS Day, applymap('Quarters_Map', num(month(OrderDate)), null()) AS Quarter, date(monthstart(OrderDate), 'MMMYYYY') AS MonthYear, OrderID, OrderID AS OrderIDCounter, ShipperID; SQL SELECT * FROM Orders; 24 QlikView Developer II | EXERCISE 5 6 Save and Reload the script. Add a List Box for the new MonthYear field to your sheet. 25 QlikView Developer II | 3 MAPPING TABLES 3.3 Cleaning up the table structure You will most likely want to minimize the number of tables in QlikView. (Omit needless tables.) It takes computational resources to make calculations between tables. If you have tables with only two fields, map those tables to another table and so minimize the number of tables. Let us look at the Table Viewer and see if there are any tables than can easily be mapped to another table. 26 QlikView Developer II | EXERCISE Exercise Do: 1 2 Return to the file you have been working on in this chapter. Open up the Table Viewer. As we can see in the Table Viewer, some tables have only two fields. These tables could be mapped to the connecting tables. Let us start by mapping the Shippers table to the Orders table. Figure 4. The Table Viewer 3 4 Open up the Script Editor and scroll down. Change the table referring to the script for the Shippers table as follows. 5 Shippers_Map: MAPPING LOAD ShipperID, CompanyName AS Shipper; SQL SELECT * FROM Shippers; Add the following line to the bottom of the Orders table. applymap('Shippers_Map', ShipperID, 'MISSING') AS Shipper The above line of script tells QlikView to use the word MISSING in the Shipper field where no matching ShipperID values can be found. 27 QlikView Developer II | EXERCISE 6 7 8 Verify that your Orders table script should resemble the following; //*************** Orders table *************** Orders: LOAD CustomerID, EmployeeID, EmployeeID AS EmployeeSalesID, Freight, OrderDate, year(OrderDate) AS Year, month(OrderDate) AS Month, day(OrderDate) AS Day, applymap('Quarters_Map', num(month(OrderDate)), null()) AS Quarter, date(monthstart(OrderDate), 'MMMYYYY') AS MonthYear, OrderID, OrderID AS OrderIDCounter, ShipperID, applymap('Shippers_Map', ShipperID, 'MISSING') AS Shipper; SQL SELECT * FROM Orders; Save the document and Reload the script. Take a look in the Table Viewer to see that in fact the Shipper field is now a part of the Orders table. Figure 5. The Shipper field is now part of the Orders table. 28 QlikView Developer II | EXERCISE Extra Credit Exercises Do: 1 2 3 4 5 6 Launch QlikView and save a working copy of the AdditionalMappingExercises.qvwQlikView file in the working directory for this chapter (C:\QlikViewTraining\DeveloperII\Chapter03). Open the Edit Script dialog. Create a tab after the Main tab and name it Mapping Loads. Move the Shippers_Map and Quarters_Map script to the Mapping Loads tab. Map the Divisions table to the Customers table. Make sure to remove (or comment out) the Divisions table from the Dimensions tab and create a mapping table on the Mapping Loads tab. Although script examples are at the bottom of this page, they are for reference only should you need help. We encourage you to try to add the Mapping Load and ApplyMap script on your own. Are there any other tables that can be mapped to another table? Check the Table Viewer. Make sure to look for tables with only two fields. Discuss with the course Instructor. //*************** Divisions *************** Divisions_Map: MAPPING LOAD DivisionID, DivisionName; SQL SELECT * FROM Divisions; //*************** Customers *************** Customers: LOAD Address, City, CompanyName, ContactName, Country, CustomerID, DivisionID, applymap ('Divisions_Map', DivisionID) as Division, Fax, Phone, PostalCode, 29 QlikView Developer II | EXERCISE StateProvince; SQL SELECT * FROM Customers; 30 QlikView Developer II | 4 LOADING BUDGET DATA 4 LOADING BUDGET DATA Objectives • • Understand cross tables Use the File Wizard to transform the data and create load script In our example data, there is a Budget table for Employees and Offices. We are going to load this into our QlikView document. The Budget table is built as a cross table and we need to convert this when we read it into QlikView. We will also add a field to the Budget table that allows us to change the values of the budget to help in planning. 4.1 Reading Cross Tables First, we will open the Budget table that is contained in the Excel file. This table does need some rework to read it into QlikView. Fortunately, QlikView has excellent functionality to interpret and change tables so that we do not need to alter the original look of the Excel file. We will use the crosstable wizard to load the data initially, and then make adjustments to our script. We will also use an input field to load the data initially, and then make adjustments to our script. 31 QlikView Developer II | EXERCISE Loading Budget Data Exercise Do: 1 2 3 4 5 6 7 8 9 Launch QlikView and save a working copy of the LoadingBudgetData.qvw QlikView file in the working directory for this chapter (C:\QlikViewTraining\DeveloperII\Chapter04). Open the Edit Script dialog. Create a new tab following the Sales Person tab and call it Budget. Click on the Table Files button and open the Budget.xls file from the data folder for this chapter. In the File Wizard, start by setting the Header Size to one line. Next, we need to make sure that there are no empty rows in the Office field. Click on the Next button and then click on Enable Transformation Step to transform the table and then click the Fill tab. Click the Fill… button and then Cell Condition. We want the cell to fill if it is empty. Click OK, OK and Next to return to the File Wizard. Click on Crosstable… to change the table from a cross table to a normal table. Click on the Qualifier Fields and type 2 to expand them to include both the Office and EmployeeID fields in purple. A qualifying field in a cross table, is a field that should not be altered during the Cross table load. 2006 is not a qualifying field. This is the first of the fields we want to transform so that the years are placed in one field and the budget values are placed in another field. 10 Name the Attribute BudgetYear. 11 Name the data BudgetAmount. 12 Click OK. 33 QlikView Developer II | EXERCISE 13 Click Finish. You should have the following table in the script. CROSSTABLE(BudgetYear, BudgetAmount, 2) LOAD Office, EmployeeID, [2006], [2007], [2008], [2009], [2010] FROM Datasources\Budget.xls (biff, header is line, embedded labels, table is [Sheet1$], filters(Replace(1, top, StrCnd(null)))) ; 14 Name this table BudgetTemp. 15 Save and Reload the document. Open the Table Viewer. As you can see, there is a synthetic key between the BudgetTemp and the Employees table. We want to remove this synthetic key. We will adjust our script to get the data we need from the BudgetTemp table, and then we will drop it. 16 Go to the Script Editor. 34 QlikView Developer II | EXERCISE 17 For simplicity’s sake, change the BudgetTemp table to the following script by replacing the individual field names with the asterisk. This will allow your script to run properly even when the labels in the data change. BudgetTemp: CrossTable(BudgetYear, BudgetAmount, 2) LOAD * FROM [Datasources\Budget.xls] (biff, embedded labels, header is 1 lines, table is Sheet1$, filters(Replace(1, top, StrCnd(null)))) ; 18 To fix the first part of the synthetic key issue, go to the File Data tab and add the following line to the top of the Employees table. Office&'-'&EmpID AS BudgetKey, 19 Save and Reload the script. Do: 1 2 3 Now we will address the synthetic key field in the Budget statement and add the input field to set the budget prognosis. If it is not already open, launch the QlikView document you have been working on in this chapter. Go to the Script Editor and place the cursor right after the SET statements on the Main tab. Enter the following statement. INPUTFIELD BudgetPrognosis; The INPUTFIELD statement tells QlikView that the field will be an INPUT field. You have to state this in the script before you actually read the field in a table. 35 QlikView Developer II | EXERCISE 4 Go to the Budget tab and create a Budget table, as follows: Budget: LOAD Office &'-'& EmployeeID AS BudgetKey, BudgetYear, BudgetAmount AS BudgetPrognosis, BudgetAmount RESIDENT BudgetTemp ; DROP TABLE BudgetTemp; 5 Save and Reload the script. 6 Now, we can use the INPUT field BudgetPrognosis to set different budget values if we need to alter the budget to correspond to the actual values. Create a new Table Box titled Sales Budget consisting of the following fields: SalesPerson, BudgetYear, BudgetAmount, and BudgetPrognosis. Move your mouse cursor over the BudgetPrognosis column in the table box. An entry arrow icon will appear. 7 8 9 36 Click on the Input icon on any row and enter any number. Right-click on the BudgetPrognosis column. Notice the related options of Restore Single Value, Restore Possible Values, and Restore All Values. QlikView Developer II | Now, we can use the INPUT field BudgetPrognosis to set different budget values if we need to alter the budget to correspond to the actual values. 37 QlikView Developer II | 5 ADVANCED SCRIPTING 5 ADVANCED SCRIPTING There are several key measures to create in this chapter. We need to calculate these in the script. They are OrderLineAmount, CostOfGoodsSold and Margin. To make these calculation fields, we need to do some advanced scripting. There is also a key field, CategoryType, which we need to create. Objectives Learn and use • Conditions in tables • Aggregation • Joining tables • Preceding Load on Preceding Load 5.1 Condition on a field in a table The CategoryType field can be created by using the CategoryID field. If the CategoryID is 5 or 6, the CategoryType should be Footwear, otherwise the type should be clothing. Let us create this field in the script. 5.2 Aggregating Data One of the key measures for this chapter is the OrderSalesAmount. We need to calculate this in the script. At the moment we already have the LineSalesAmount, but we want to have a total amount for each Order. To accomplish this, we need to aggregate the LineSalesAmount. To group or aggregate data, we will use the GROUP BY clause in the LOAD statement. In this case, we need to aggregate the data in the OrderDetails table by OrderID. 5.3 Joining tables We want to add the OrderSalesAmount field to the Orders table. To do so we can add the values of this table to the Orders table. To use two tables together like this, we must begin by combining them into a single table. Here, the JOIN between tables can be performed against the source database or we can use a QlikView JOIN command. Since we already have the source data we need loaded into memory, we will use the QlikView JOIN LOAD statement against the table just created. Tip: Bad joins can result in significant memory penalties. If you receive an “Out of Memory” error, be sure to double-check your script and data model! 39 QlikView Developer II | 5 ADVANCED SCRIPTING 5.4 Concatenation Another way to join data together from multiple tables is to use concatenation. There are two ways to concatenate data. We will explore each of these methods. 5.4.1 Automatic Concatenation If the field names and the number of fields of two or more loaded tables are exactly the same, QlikView will automatically concatenate the results of the different LOAD or SELECT statements into one table. Example: LOAD a, b, c FROM Table1.csv; LOAD a, c, b FROM Table2.csv; The resulting logical table has the fields a, b and c. The number of records is the sum of the numbers of records in table 1 and table 2. Rules: - The number and names of the fields must be exactly the same. - The order of the fields listed in each statement is arbitrary. - The order of the two statements is arbitrary. 5.4.2 Forced Concatenation If two or more tables do not have exactly the same set of fields, it is still possible to force QlikView to concatenate the two tables. This is done with the Concatenate prefix in the script, which concatenates a table with another named table or with the last previously created logical table. Example: LOAD a, b, c FROM Table1.csv; Concatenate LOAD a, c FROM Table2.csv; The resulting logical table has the fields a, b and c. The number of records in the resulting table is the sum of the numbers of records in table 1 and table 2. The value of field b in the records coming from table 2 is NULL. Rules: - The names of the fields must be exactly the same. - The order of the fields listed in each statement is arbitrary. - Unless a table name of a previously loaded table is specified in the concatenate statement the concatenate prefix uses the last previously created logical table. The order of the two statements is thus not arbitrary. 40 QlikView Developer II | 5 ADVANCED SCRIPTING 5.4.3 Prevent Concatenation If two tables have the same set of fields and thus would normally be automatically concatenated, you can prevent the concatenation with the NoConcatenate prefix. This statement prevents concatenation with any existing logical table with the same set of fields. The syntax is: NoConcatenate ( LoadStatement | SelectStatement ) Example: LOAD a, b FROM Table1.csv; Noconcatenate LOAD a, b FROM Table2.csv; In our data, we have been provided with an additional set of new employees that are not yet contained in the EmpOff.xls file. In order to add this data, we need to modify our load script. 5.5 Preceding Load on Preceding Load The next key measure we are going to add is the CostOfGoodsSold. To calculate this value, we need to add the UnitCost field from the Products table to the OrderDetails table. We are going to do this by using a mapping table and apply this to the OrderDetails table. 41 QlikView Developer II | EXERCISE Exercises Do: Condition on a Field in a Table 1 2 3 4 Launch QlikView and save a working copy of the AdvancedScripting.qvw QlikView file in the working directory for this chapter (C:\QlikViewTraining\DeveloperII\Chapter05). Open the Edit Script dialog and go to the Dimensions tab. Find the Categories table and place the cursor after the last field of this table. Type a comma and press ENTER to get to a new row. Type the following to create the CategoryType. IF(CategoryID = 5 OR CategoryID = 6, 'Footwear', 'Clothing') AS CategoryType; The IF statement in QlikView uses the following syntax: if( condition , then , else ) 5 6 The condition should be evaluated to be either true or false. If the condition is true, the then part will be processed. However, if the condition is false, the else portion of the statement will be processed. Save the script and Reload. Look at the fields. You can now see that we have a new field named CategoryType. Do: Aggregation 1 2 3 Open the QlikView file you have been working on in this chapter. Open the Script Editor and place the cursor after the OrderDetails table on the Orders tab. Add the following statement to your script: LOAD OrderID, sum(LineSalesAmount) AS OrderSalesAmount RESIDENT OrderDetails GROUP BY OrderID; 4 Notice the aggregation function sum(LineSalesAmount) included in this statement. This function will be evaluated over all the potential combinations of the other fields in the LOAD (OrderID) statement. The GROUP BY clause is needed to aggregate, or group fields other than those included in the aggregation. In this case, it will total the Sales Amount for each OrderID. 43 QlikView Developer II | EXERCISE Do: Joining Tables 1 2 Go to the Script again and place the cursor just in front of LOAD in the table just created. Type LEFT JOIN (Orders) in front of the LOAD statement. The result should be as below. LEFT JOIN (Orders) LOAD … 3 Here we use a LEFT JOIN load because we want to make sure that we do not get any values of Orders that do not exist in the Orders table. In QlikView, the default join behavior is a full outer join. Therefore, if there are no matching fields between the two joined tables, you will get a Cartesian product of the records. Since we are specifying OrderID in both tables, and we are specifying Left, only the records matching OrderID included in the Orders table will be included. We include the OrderSalesAmount field because that is what we want to add to the Orders table. Save and Reload the script. Do: Concatenation 1 2 3 Open the Edit Script dialog in the QlikView file you have been working on in this chapter. Position your cursor on the File Data tab directly after the Employees table has been loaded. We need to duplicate the fields we currently have for Employees, so we will not use the File Wizard in this case. Instead, copy the Employee LOAD statement, and paste the copied text after the original text. Since the new file data format matches our first file, we only need to change the source of the data. Revise the From clause in the new load statement to read as follows: FROM Datasources\Employees_New.xls (biff, embedded labels, table is [Employee$]); 4 5 6 44 Click OK and Save the QlikView document. Run the script. If you notice a number of new Synthetic Keys, or a new $Table value of Employee-1, you know something did not work correctly with automatic concatenation. You can avoid a number of potential problems with automatic concatenation by using the concatenate prefix on load statements that you know should be concatenated. Add the concatenate prefix to the new Employee LOAD statement, and specify the Employees table. QlikView Developer II | EXERCISE This will always concatenate these two tables together, even if inadvertent script changes are made later to one of the loads, but not the other. The new Employee LOAD statement should now begin as follows: Concatenate (Employees) Load 7 You may have noticed that there are very few differences between our two Employee LOAD statements. In fact, we can use another QlikView feature to load the same data in just a single load statement. By using a wildcard specification on the FROM file name, QlikView will automatically load from all files matching that specification, and concatenate the data into a single logical table for you. Since both our file names start with “Emp”, and have the “.xls” file extension, we can use the wildcard “Emp*.xls” in the FROM clause. If we make this change, and comment the second Employee LOAD statement, the script should now read as follows: Employees: Load Office & ‘-’ & EmpID as BudgetKey, EmpID AS EmployeeID, //[Last Name], //[First Name], [First Name] & ' ' & [Last Name] AS Name, Title, [Hire Date], Year([Hire Date]) AS [HireYear], Office, Extension, [Reports To], [Year Salary] FROM Datasources\Emp*.xls (biff, embedded labels, table is [Employee$]); //Employees: //Concatenate (Employee) Load //Office & ‘-’ & EmpID as BudgetKey, //EmpID AS EmployeeID, //[Last Name], //[First Name], //[First Name] & ' ' & [Last Name] AS Name, //Title, //[Hire Date], //Year([Hire Date]) AS [HireYear], //Office, 45 QlikView Developer II | EXERCISE //Extension, //[Reports To], //[Year Salary] //FROM Datasources\Employees_New.xls (biff, embedded labels, table is [Employee$]); 8 9 Save the revised script and the QlikView document. Then Reload, and verify the Employee data has not changed. As an optional exercise, you may want to try to determine why the employees listed in the Employees_New.xls file are not assigned e-mail addresses (field e-mail is null for these employees). What do you need to do to correct this problem? Do: Preceding Load on Preceding Load 1 2 In the QlikView file you have been working on in this chapter, go to the Script Editor and place the cursor at the bottom of the Mapping Loads tab. Create the following table either by typing it from scratch or by using the Select button. UnitCost_Map: MAPPING LOAD ProductID, UnitCost; SQL SELECT * FROM Products; 3 Go to the Orders tab and add the following script line to the bottom of the OrderDetails table just above the SQL SELECT * line. Remember to remove the semi-colon from the line above and replace it with a comma. applymap('UnitCost_Map', ProductID, 0) * Quantity AS CostOfGoodsSold; We combine the applymap function with a calculation and create the CostOfGoodsSold field directly in the preceding LOAD of the OrderDetails table. The last of the remaining key measures that we need to create in the script is the Margin. The Margin is calculated as the LineSalesAmount – CostOfGoodsSold. The easiest way to do this is to place a preceding load on top of the preceding load in the OrderDetails table. You can add several preceding loads on top of each other and they will be evaluated from the bottom and up. This means that you can use a field created in a preceding load in a new preceding load on top of the first one. 46 QlikView Developer II | EXERCISE 4 5 6 7 8 We will use this functionality to create the Margin field. Put the cursor after the OrderDetails label. Create a preceding load by adding the following script. LOAD LineSalesAmount - CostOfGoodsSold AS Margin, * ; The full OrderDetails script should look like this: //*************** Order Details table OrderDetails: LOAD LineSalesAmount - CostOfGoodsSold AS Margin, * ; LOAD Discount, LineNo, OrderID, ProductID, Quantity, UnitPrice, UnitPrice * Quantity * (1 - Discount) AS LineSalesAmount, applymap('UnitCost_Map', ProductID, 0) * Quantity AS CostOfGoodsSold; SQL SELECT * FROM `Order Details`; LEFT JOIN (Orders) LOAD OrderID, sum(LineSalesAmount) AS OrderSalesAmount RESIDENT OrderDetails GROUP BY OrderID; Save and Reload the script. The new key measure fields should be ready for use. 47 QlikView Developer II | EXERCISE Extra Credit Do: 1 2 Launch QlikView and save a working copy of the AdditionalExercises.qvw QlikView file in the extra cradit folder for this chapter (C:\QlikViewTraining\DeveloperII\Chapter05\ExtraCredit_Chapter05). To clean up the script a little more, Join the Categories table with the Products table. Make sure not to get any Categories that do not exist in the Products table. //************** Categories table ************** Categories: LEFT JOIN (Products) LOAD CategoryID, CategoryName, Description AS CategoryDescription, IF(CategoryID = 5 OR CategoryID = 6, 'Footwear', 'Clothing') AS CategoryType; SQL SELECT * FROM Categories; 3 4 5 Create a pivot table with CategoryType and CategoryName as dimensions. Create the following four expressions: Sales Sum(LineSalesAmount) COGS Sum (CostOfGoodsSold) Margin Sum (Margin) Margin % Sum (Margin)/ Sum (LineSalesAmount) Format the table the way you want to. Figure 1. The resulting pivot table. 49 QlikView Developer II | 6 ADVANCED CALCULATIONS IN SHEET OBJECTS 6 ADVANCED CALCULATIONS IN SHEET OBJECTS Objectives • • Introduce advanced calculations in charts and tables, including: • Set Analysis • Dollar-Sign Expansion • AGGR Function Complete exercises using examples of each of these functions 6.1 Set Analysis QlikView has always been good at calculating aggregates for the current selection of data. However, when you wanted to compare results for different selections in the same chart, you needed to either prepare data in the script or resort to rather complicated expressions with if clauses. Set analysis changes all that, by making it possible to modify any aggregation function with an arbitrary selection set. The set may be defined as a bookmark, as an on-the-fly selection in one or more fields, as a function of current selections, the inverse of current selections, previous selections or all data. The possibilities are endless and yet the syntax is fairly simple and straightforward. Indirect Set Analysis Selections in a field can be stated based on selections in another field, such as Select all possible values in Customers based on Sales last year. 6.1.1 Overview Sets can be used in aggregation functions. Aggregation functions normally aggregate over the set of possible records defined by the current selection. But an alternative set of records can be defined by a set expression. Hence, a set is conceptually similar to a selection. Note: A set expression is always enclosed in curly brackets when used, e.g.{BM01}. 6.1.2 Set Identifiers There is one constant that can be used to denote a record set; 1. It represents the full set of all the records in the document. 51 QlikView Developer II | 6 ADVANCED CALCULATIONS IN SHEET OBJECTS The $ sign represents the records of the current selection. The set expression {$} is, therefore, the equivalent of not stating a set expression at all. {1-$} is all the more interesting as it defines the inverse of the current selection, that is, everything that the current selection excludes. Selections from the Back/Forward stack can be used as set identifiers, by use of the dollar symbol: $1 represents the previous selection and is equivalent to pressing the Back button. Similarly, $_1 represents one step forward and is equivalent to pressing the Forward button. Any unsigned integer can be used in the Back and Forward notations. $0 represents the current selection. Finally, bookmarks can be used as set identifiers. Either the bookmark ID or the bookmark name can be used, BM01 or MyBookmark. 6.1.3 Set Operators Several operators are used in set expressions. All set operators use sets as operands, as described above, and return a set as result. The operators are as follows: + Union. This binary operation returns a set consisting of the records that belong to any of the two set operands. – Exclusion. This binary operation returns a set of the records that belong to the first but not the other of the two set operands. Also, when used as a unary operator, it returns the complement set. * Intersection. This binary operation returns a set consisting of the records that belong to both of the two set operands. / Symmetric difference (XOR). This binary operation returns a set consisting of the records that belong to either, but not both of the two set operands. The order of precedence is 1 2 3 Unary minus (complement) Intersection and Symmetric difference Union and Exclusion. Within a group, the expression is evaluated left to right. Alternative orders can be defined by standard brackets, which may be necessary since the set operators do not commute, i.e. A + (B – C) is different from (A + B) – C which in turn is different from (A – C) + B. Set Operator Examples: sum( {1-$} Sales ) returns the sales for everything excluded by the current selection. 52 QlikView Developer II | 6 ADVANCED CALCULATIONS IN SHEET OBJECTS sum( {$*BM01} Sales ) returns the sales for the intersection between the current selection and bookmark BM01. sum( {-($+BM01)} Sales ) returns the sales excluded by current selection and bookmark BM01. Note: The use of set operators in combination with basic aggregation expressions involving fields from multiple QlikView tables may cause unpredictable results and should be avoided. E.g. if “Quantity” and “Price” are fields from different tables, then the expression sum($*BM01} Quantity * Price) should be avoided. 6.1.4 Set Modifiers A set can be modified by making an additional or a changed selection. Such a modification can be written in the set expression. The modifier consists of one or several field names, each followed by a selection that should be made on the field, all enclosed by < and > as in <Year={2007, 2008}, Region={US}> Field names and field values can be quoted as usual, e.g. <[Sales Region]={’West coast’, ’South America’}>. There are several ways to define the selection: A simple case is a selection based on the selected values of another field, e.g. <OrderDate = DeliveryDate>. This modifier will take the selected values from “DeliveryDate” and apply those as a selection on “OrderDate”. Note: If there are many distinct values – more than a couple of hundred – avoid this operation because it is CPU intensive. The most common case, however, is a selection based on a field value list enclosed in curly brackets, the values separated by commas, e.g. <Year = {2007, 2008}>. The curly brackets here define an element set, where the elements can be either field values or searches of field values. A search is always defined by the use of double quotes, e.g. <Ingredient = {"*Garlic*"}> will select all ingredients including the string ‘garlic’. 53 QlikView Developer II | 6 ADVANCED CALCULATIONS IN SHEET OBJECTS Note: Searches are case-insensitive and are made over excluded values too. Tip: Empty element sets, either explicitly e.g. <Product = {}> or implicitly e.g. <Product = {"Perpetuum Mobile"}> (a search with no hits) mean no product, i.e. it will result in a set of records that are not associated with any product. Further, the selection within a field can be defined using set operators and several element sets, such as with modifier <Year = {"20*", 1997} - {2000}> which will select all years beginning with “20” in addition to “1997”, except for “2000”. The above notation defines new selections, disregarding the current selection in the field. However, if you want to base your selection on the current selection in the field and add field values, e.g. you may want a modifier <Year = Year + {2007, 2008}>. A short and equivalent way to write this is <Year += {2007, 2008}>, i.e. the assignment operator implicitly defines a union. Also implicit intersections, exclusions and symmetric differences can be defined using “*=”, “–=” and “/=”. Finally, for fields in and-mode, there is also the possibility of forced exclusion. If you want to force exclusion of specific field values, you will need to use “~” in front of the field name. Note: A set modifier can be used on a set identifier or on its own. It cannot be used on a set expression. When used on a set identifier, the modifier must be written immediately after the set identifier, e.g. {$<Year = {2007, 2008}>}. When used on its own, it is interpreted as a modification of the current selection. 6.2 Dollar-Sign Expansion Dollar-sign expansions are definitions of text replacements used in the script or in expressions. This process is known as expansion - even if the new text is shorter. The replacement is made just before the script statement or the expression is evaluated. Technically, it is a macro expansion. 54 QlikView Developer II | 6 ADVANCED CALCULATIONS IN SHEET OBJECTS A macro expansion always begins with $( and ends with ) and the content between brackets defines how the text replacement will be done. To avoid confusion with script macros we will henceforth refer to macro expansions as dollar-sign expansions. Note: Macro expansion is unrelated to script macros (VB or Java script defined in the script module). 6.2.1 Dollar-sign Expansion using a variable When using a variable for text replacement in the script or in an expression, the syntax $ (variablename) is used. $(variablename) expands to the value in variablename. If variablename does not exist the expansion will be the empty string. For numeric variable expansions, the syntax $ (#variablename) is used. $(#variablename) always yields a legal decimal-point reflection of the numeric value of variablename, possibly with exponential notation (for very large/small numbers). If variablename does not exist or does not contain a numeric value, it will be expanded to 0 instead. 6.2.2 Dollar-Sign Expansion with Parameters Parameters can be used in variable expansions. The variable must then contain formal parameters, such as $1, $2, $3 etc. When expanding the variable, the parameters should be stated in a comma separated list. If the number of formal parameters exceeds the number of actual parameters, only the formal parameters corresponding to actual parameters will be expanded. If the number of actual parameters exceeds the number of formal parameters, the superfluous actual parameters will be ignored. The parameter $0 returns the number of parameters actually passed by a call. 6.2.3 Dollar-Sign Expansion with an Expression Expressions can be used in dollar-sign expansions. The content between the brackets must then start with an equal sign: $(=expression) The expression will be evaluated and the value will be used in the expansion. Example: 55 QlikView Developer II | 6 ADVANCED CALCULATIONS IN SHEET OBJECTS $(=Year(Today())) returns the calendar year based on the system date, so if your system date is 28 May 2009, 2009 would be returned $(=Only(Year)-1)returns the year before the selected one 6.3 AGGR Function AGGR is a powerful QlikView function that returns a set of values of expression calculated over dimensions. The result can be compared to the expression column of a local chart, evaluated in the context where the aggr function resides. Each dimension must be a single field and cannot be an expression (e.g. a calculated dimension). If the expression argument is preceded by the nodistinct qualifier, each combination of dimension values may generate more than one return value, depending on underlying data structure. If the expression argument is preceded by the distinct qualifier, or if no qualifier is used at all, each combination of dimension values will generate only one return value. By default, the aggr function will aggregate over the set of possible records defined by the selection. An alternative set of records can be defined by a set expression. By using this function in calculated dimensions it is possible to achieve nested chart aggregation in multiple levels. When aggr is used in chart expressions it is possible to achieve sum-of-rows totals in a pivot table. Examples: aggr( sum(Sales), Country ) aggr( nodistinct sum(Sales), Country ) aggr( sum(Sales), Country, Region ) count( aggr( sum(Sales), Country )) 56 QlikView Developer II | EXERCISE Advanced Calculations Exercises Do: Set Analysis Exercise Create a Straight Table chart that displays a comparison of annual sales by CompanyName based on the year selected by the user. 1 2 3 4 5 6 7 Navigate to the c:\QlikViewTraining\DeveloperII\Chapter06 directory and open the Set_Analysis.qvw file. Save a copy of the file to preserve the original in case you want to start again from the beginning later. Do this by using the File | Save As command. There is also a QlikView file ending in “_Solution.qvw” containing the completed exercise for your reference. Double check to be sure there is a list box on the sheet for the Year. If not, add one. Right-click in a blank area of the sheet and New Sheet Object | Chart from the context menu. Click on the Straight Table icon (the lower right corner of the Chart Types) and type Annual Comparison in the Window Title. Click on the Next button. Add Customer to the Used Dimensions and click Next Create the following three Expressions using the Labels provided: 1 Label =Only(Year) 2 =Only(Year)-1 3 =Only(Year) & ' vs ' & (Only(Year)-1) Expression Sum({$<Year={$(=Only(Year))} >} LineSalesAmount) Sum({$<Year={$(=Only(Year)1)}>} LineSalesAmount) Sum({$<Year={$(=Only(Year))} >} LineSalesAmount) Sum({$<Year={$(=Only(Year)1)}>} LineSalesAmount) 8 9 Click Finish Save your QlikView file and then continue to edit the Annual Comparison straight table. 10 Set the Sort order to match the depiction, below, remembering that Customer should be set to Text 57 QlikView Developer II | EXERCISE 11 On the Visual Cues tab, make the negative values for the year-to-year comparison red and the positive values green. 58 QlikView Developer II | EXERCISE 12 Return to the General tab and add a Calculation Condition to ensure that the user selects a Year to begin the comparison by entering the following into the Calculation Condition box Count(distinct [Year])=1 13 Click on the Error Messages button on the General tab and then on Calculation Condition Unfulfilled in the Standard Messages list. 14 Type: Select a Year to compare with a previous year in the Custom Message box and click OK. 15 Click OK again to close the chart properties dialog. 59 QlikView Developer II | EXERCISE 16 With 2009 selected in the Year list box you added at the beginning of the Exercise, your straight table should look something like the one below: 17 Save your work. Do: Advanced Set Analysis 1 2 3 4 5 60 Continue working in the file you have been using in this exercise chapter so far. Create a chart that compares sales of products in the category Babywear with products in the category Children´s Wear over time for the Nice sales office. To do this you will need to create an expression using Set analysis and $ Expansion instead of traditional if() statements. Set the category name to find Babywear and the office to be 4. Pay attention to the <> and {}. QlikView Developer II | EXERCISE Solution: sum({$<CategoryName={'Babywear'}, Office={4}>} LineSalesAmount) sum({$<CategoryName={'Children´s wear'}, Office={4}>} LineSalesAmount) Do: AGGR Function Exercise 1 2 3 Continue working in the file you have been using in this exercise chapter so far. Create a table that shows if there is any link between the number of orders placed by customers and the average order value. The table should provide information on how many customers have placed one order, two orders etc, and also the average order value. There are three steps to this process. First, create a calculated dimension for the number of orders (as in “how many customers had one order, two orders, three orders, etc.). This requires aggr. First, to count the number of orders, use count(distinct OrderID) and then to aggregate those against the Customer Dimension use aggr(......, CustomerID) Putting it together, aggr(count(Distinct OrderID), CustomerID) will create the necessary order "buckets" based on customer 61 QlikView Developer II | EXERCISE 4 5 Next you need a count of customers to populate the # of order “buckets” we created in the first step. Count(distinct CustomerID) And, finally, we need to find the average order amount. Sales is from the Sales Detail Table and is a line item for every product sold. Thus one order could have several products and thus several lines with Sales data, so we need to aggregate by OrderID to get the total sales amount for an order aggr(sum(LineSalesAmount),OrderID) gets you that number and adding the avg() gives you the requested average order amount avg(aggr(sum(LineSalesAmount),OrderID)) 62 QlikView Developer II | 7 SCRIPTING AND DATA MODELING CHALLENGES 7 SCRIPTING AND DATA MODELING CHALLENGES Objectives • • • • Understand the use link tables Calculate net change within a field Use advanced functions for handling time Know why dynamic aggregation and interval matching are important 7.1 Link Tables and Concatenated Tables Link tables combine information that has different levels of detail or frequency. Generally, they are best used when the metrics being measured do not have the same base of time, perhaps one is an aggregation over a time period, i.e., by Month. Link tables are also used when data does not meet the business requirements of a calculation. So you can think of them in terms of their name. They are useful to link information that would not otherwise be automatically linked with QlikView’s associative logic. In other words, when loading data, certain scenarios can occur whereby you need to store fact type information in different tables, such as transactions separated from budgets. Each type of fact may need to join with multiple common dimensions (such as Time and Product) which would then cause loops in the datastructure. To circumvent such scenarios, we create linking tables that store the individual ways that each fact table joins to the common dimensions. 7.1.1 Concatenation Concatenation can be used to reduce the number of fact tables in a structure if there is sufficient commonality between the fact tables to validate such a combination. This can make a data model more efficient. When fact tables contain the same granularity of information and a common key is found between both facts, an outer join operation is preferable to a concatenate operation, as the output records would be linked on a record-by-record basis and hence single record operation will be possible. (e.g. For a given SalesAndBudget fact record, to be able to calculate the difference between the sales amount and the budget amount.) 7.2 Calculating net change within a field While loading data, you can look at what is being loaded using the peek() function and use it in calculations that express the relationships between records. This can be useful for understanding an account balance, over time, for example. 63 QlikView Developer II | 7 SCRIPTING AND DATA MODELING CHALLENGES We can also see what has been loaded in the load process with the previous() function. The previous() function can only be used to look one record back in the load process. If you need to look further back than one record in the load process, you have to nest the previous() function as in: previous(previous(myRecord)) This can be problematic and cumbersome when you want to see the total net change or percent change. Let us assume we need to count the number of units that are at a given site within a week and need to find the percent of utilization for a unit at a given site. If the units are at multiple sites but return to the same site within the same week, peek() and previous() can work but require complex coding with FOR loops or RESIDENT loads. However, we can get around that by grouping the information from a tracking table and Left Joining the result back into the tracking table. The steps in the exercise demonstrate the difference. 7.3 Functions InDate, Data & DateIslands This section includes concepts used to create documents: InDate and Data/ DateIslands. Data/DateIslands are tables that are not directly linked with other tables (tables that are independent of any explicit links). You can think of this as an array of values that can change with a selection by the user and will force new results to be displayed in the Qlikview Data Model via a non-key field connection. However, when using this approach you will not change the selection state in the underlying QlikView Data Model. This is usually used for KPIs so that, when moving to a tab with more detail, the user has a full view and selection of data for filtering. If there is a selection made in the QlikView Data Model outside of a Data/ DateIsland, that select will remove data used in the calculation of a KPI and could result in blank or misleading KPI displays. The InDate() functions are used in conjunction with the Data/DateIsland. 7.4 Aggr() Note: If you have already completed Chpater 6, skip this explanation. Aggr() is an advanced function that allows you to calculate an aggregation of multiple dimensions. As a rule, you can not aggregate an aggregated 64 QlikView Developer II | 7 SCRIPTING AND DATA MODELING CHALLENGES expression (nested aggregations). The exception to this restriction is to use aggr(); the format is: aggr([distinct | nodistinct] expression {,dimension}) The best way to think of aggr() is that, by using this function, you can create a mini QlikView data model on the fly, without needing to edit your data load script or reload from the source data for your QlikView file. It allows for nested aggregation. You can add more dimensions than are represented in charts such as a Pivot Table. Aggr() is used in the user interface, rather than in the load script. Typically, it is used in a chart object expression, as we saw in the previous chapter. 7.5 Class() Class() is an aggregation function that can be used to create buckets of information similar to what you would create in an Accounts Receivable document showing aged accounts. Another way of thinking of Class() is that you can group your dimension values. 7.6 Dynamic Aggregation In QlikView, you can assign a field value to a variable. Subsequently, you can use the value that the variable holds in an expression. This is similar to a pointer in C-programming or other similar programming languages. QlikView calculates information on the fly. With this approach and using a table to hold expressions, you can create a reference to the formulas located in the table which, in turn, effectively creates a library of expressions that can then be used to dynamically change your display of information. The user will be able to cycle through the KPIs by selecting choices in a List Box. 7.7 IntervalMatch The IntervalMatch script statement facilitates the mapping of dates to periods or records to slowly changing dimensions, useful for creating a fully functioning data model across the appropriate time dimensions in your business requirements. The implementation of IntervalMatch requires a few additional steps than simply to apply the function if we are to avoid synthetic keys being created in our data structure. IntervalMatch() is a script statement that has the same functionally as BETWEEN used in a SQL statement. There is one downside to IntervalMatch(), it creates a synthetic table ($Syn table). $Syn tables can have a high cost in 65 QlikView Developer II | 7 SCRIPTING AND DATA MODELING CHALLENGES memory and User Interface performance can suffer. One solution to explore is to LEFT JOIN the IntervalMatch() table into a parent table. Here is a small example of IntervalMatch(). We are maintaining the approach of keeping the examples small so that they can be easily verified. In this exercise we will use IntervalMatch() to find the hours that an employee is working on-site. 66 QlikView Developer II | EXERCISE Exercises: Advanced Scripting and Design Do: Link Tables Exercise 1 2 3 4 5 Launch QlikView and save a working copy of the QlikView file in the working directory for this chapter and section (C:\QlikViewTraining\DeveloperII\Chapter07\LinkTables\Linktable.qvw). Open the LinkTable.XLS Excel file and examine the Sales as well as the Budget fields. You will see that four customers have a Budget and four customers purchase goods each month but not the identical customers that have a Budget. Now reload your working copy of the LinkTable.qvw file. All the information looks correct. Go to the Table Viewer and look at the structure of the Data Model. A Synthetic Key and a Synthetic Table have been created. This can add processing overhead to the document and, in some rare cases, can return unexpected results. Comment the script on the SynKey tab, uncomment the script on the Using a Key tab and reload the document. Note that we are trying eliminate the Synthetic Key by concatenating the fields that are causing the Synthetic table. Check the result from the QVW and compare them to the Excel sheet. You can see that we are returning incorrect information because of key field mismatches; customers are missing from each table. Comment the script on the Using a Key tab and uncomment the script on the Link Table tab and reload the document. Here we are loading the information from the Sales and Budget table two times. This generates an intermediate table that has common information from both the tables. The level of detail is maintained in separate tables for both the Sales and Budget. The link table must be loaded Distinct (only unique key combinations) and it will establish correct relationships. Create a Table Box that includes all the columns. 67 QlikView Developer II | EXERCISE 6 7 Comment the script from step 3 (on the Link Table tab) and uncomment the script on the Concatenate tab. Reload the document. Note the use of a RecSource field to differentiate concatenated records. Note also the use of explicit references to CONCATENATE and the table into which the concatenation will happen. Finally, observe the LEFT JOIN that adds the Customer field to the table and note that this results in a Data Model with a single table. Suggest an alternative way to accomplish the same result. Look at the result. You will see the same results as Step 1 and Step 3. Notice that there are null values. Now if you sum Sales Amount and Budget Amount, they will balance. Note: This is similar to a union in SQL. Null values do not have a high cost in QlikView as they normally do in SQL. Remember: Link tables resolve differences in granularity between fact tables joining to the same dimensions. 68 QlikView Developer II | EXERCISE Do: Join Exercise 1 Open the LeftJoin.QVW file located in the LeftJoin folder, save a working copy and run the script on the Previous tab. Create two List Boxes and use the fields Units and Dept. 2 Select the Unit numbered 54543. Create a Table Box using all fields and look at the counts. We still don’t have a full count for the units at Dept A2. We would have to reload the table again. But where do we stop? The solution is to aggregate the data using a GROUP BY clause from the Tracking table data and LEFT JOIN the result to the Tracking table. Comment the information on the Previous tab, uncomment the script on the Left Join tab, and reload the document. With this approach you now can find the total number of times a Unit is utilized across all Depts in any Week. This was done with one additional RESIDENT load. Your result should look like this: 3 4 5 6 69 QlikView Developer II | EXERCISE Now you can calculate the percent of utilization of a Unit in a Dept for a given Week. Note: The ORDER BY clause is required here, but it will only work for a RESIDENT LOAD or in a SQL SELECT statement. ORDER BY will not work with a LOAD FROM statement. Remember: Group by statements in combination with left join operations allow for aggregation of values living in tables low down in a parent-child hierarchy and appending to the higher tables, such as summing the value of individual order line items into a single value per order. Do: Date Island Exercise 1 Open the file DateIsland.qvw in the Date_Island folder, save a working copy of the file and add the following code in the Calendar tab below the MasterCalendar: line in the script. DateIsland: LOAD DISTINCT monthstart(OrderDate) AS DateIsland, MonthYear AS DateMonthYear RESIDENT MasterCalendar; 2 3 4 70 Reload the script. Create a List Box and a Pivot Table. In the Pivot Table use Country and any CategoryType. For the List Box show DateMonthYear. Use two of the three expressions, below (hint: one of them violates a best practice): sum(LineSalesAmount * InMonth (OrderDate,DateIsland,0) *-1)) sum(if(InMonth (OrderDate,DateIsland,0),LineSalesAmount,0)) sum(LineSalesAmount) Select a single DateMonthYear. The result should look like this: QlikView Developer II | EXERCISE 5 6 Last, you need to set a property of the List Box to always have only 1 value selected. Note you cannot do this unless you selected a single value in the step above. Now select various DateMonthYear values and you will see Sales change in one column but not the other. Remember these key points: • Filtering can be achieved without affecting the rest of the data structure. • This is achieved through the use of conditional statements and presenting the selection criteria of such filters in fields that do not link to the data structure. • Inter-record functions can be used to calculate rolling averages and performing period comparison in straight and pivot tables. 71 QlikView Developer II | EXERCISE Do: Class () Exercise 1 2 3 4 Open the file, Class.QVW in the Class folder and save a working copy of the file. Create variables called vDate (set vDate to a current date and format vDate as a date, not a numeric) and vWidth (using a pre-pended v or var to denote variables is a best practice) on the Variables tab under the Settings | Document Properties menu Create a Calendar Object, click the Variable(s) radio button, and choose vDate as the variable assigned to the Calendar Object. Create an Input Box and choose vWidth as the only Displayed Variable. Figure 1. Variable settings Figure 2. Calendar and Input Box Objects 5 6 Next create a Pivot Table with CompanyName as the dimension and sum(LineSalesAmount) as the expression Last, we will create a calculated dimension in the Pivot Table. Add the class() function using the following: =class(num(OrderDate - $(vDate)),$(vWidth),'Dt') 72 QlikView Developer II | EXERCISE Here we used 2 variables to dynamically change the start period as well as the buckets that the sales or AR information falls in. The screenshots below show two different vWidth values. 73 QlikView Developer II | EXERCISE Do: Dynamic Aggregation Exercise 1 Open the file located in the DynamicAggregation folder called Dynamic Aggregation.QVW, save a working copy and reload it. Next create a pivot table chart that looks like Where the expression is sum(LineSalesAmount) 74 QlikView Developer II | EXERCISE 2 When you have finished the chart, edit the script creating the following INLINE table and reload. (Note this could also be done by creating and loading an external text or Excel file – a best practice). 3 Next create a variable vMyAgg with the value, =Formula as show below. Remember the equal sign: 4 Create a copy of the first Chart and replace the expression sum(LineSalesAmount) with if(Desc = 'Count', num($(vMyAgg),'###0'),num($(vMyAgg),'$###.00')) 5 6 Note the test to determine how to format the numeric display (integers or currency). You might try including the format string with the expression in the INLINE table as an additional field and then change the expression accordingly. Add two List Boxes with the columns Desc and Formula plus a Text Box with =vMyAgg in the text area. The result is that you can change your KPIs on the fly. Your result should look as follows: 75 QlikView Developer II | EXERCISE 7 This technique can be used to change the presentation of entire tables and pages by changing the Units of Measure or the calculations done within the Sheet Object (as above). It can be used to Show/Hide tables and Charts based on selections made in a List Box. You can create an external file that is a library of expressions and then load the file and create variables that contain your expressions. Do: Interval Match Exercise 1 2 3 76 Open the file IntervalMatch.QVW and save a working copy. Within your working copy, create a table showing the sum of hours a person works and a table of the count of hours worked by each Employee (Emp). Notice that the line before IntervalMatch() is commented. Look at the result in the Table Viewer. You will see that this script has created a $Syn table. As we learned earlier, a $Syn table may have a high cost. QlikView Developer II | EXERCISE 4 Uncomment the statement before the IntervalMatch() and reload the document. Result: The $Syn table has been removed with an INNER JOIN into the table that has the start and stop values (TabB). This can reduce the overhead of a $Syn table. You also have the discrete records for all occurrences and can use this table to JOIN to other tables. Note that you have increased the size of TabB. The rows in TabB will increase to the number of rows that would be in the $Syn table. 77 QlikView Developer II | EXERCISE Extra Credit Do: Additional AGGR Exercise 1 2 3 Open the file, Aggr.QVW in the Aggr folder and save a working copy of the file. In this example we are going to find the average count of Orders by Country, Company, Year and Month using the aggr() function. avg(aggr(count(Distinct OrderID),Country,CompanyName, Year, Month)) The average LineSalesAmount by Country, Company, Year and Quarter with the expression below: 4 avg(aggr(sum(LineSalesAmount),Country,CompanyName, Year, Quarter)) And, finally, the Total Sales 5 sum(LineSalesAmount) Create the chart shown below using the expressions above. 6 Once you have created the chart, investigate further by changing the time dimension in the dimensional portion of the aggr() function. Determine how many Orders were placed in each Month and how many Months had Orders in them. Try to explain some of the resultant averages in each column. 79 QlikView Developer II | 8 DATA MODEL OPTIMIZATION 8 DATA MODEL OPTIMIZATION Objectives • • • • Discuss performance tuning Explore the impacts of appropriate document design Introduce security concepts Review best practices 8.1 Performance Tuning 8.1.1 What makes up the size of a QlikView document? • Number of rows • Number of columns • Number of distinct values / column • Data structure • Number of sheets / sheet objects Number of rows • Question: Is it really necessary to have 10 years of data in the same QlikView document? • Question: If there are too many detail rows, is it feasible to create a rollup version at a higher aggregate level? Number of Columns Be selective about what fields are included in the QlikView document • Focus on the larger fact tables first • But don’t ignore the dimension tables Eliminate fields that are not currently being used • All fields might be used in the future but are not used now • The goal is to have a Lean QlikView document Number of Distinct Values / Column Fields with highly distinct values use the most space Many of them can be eliminated / truncated altogether • System keys • Timestamps with minutes / seconds Others can be transformed by breaking them up into separate components • Phone Numbers • Timestamps 81 QlikView Developer II | 8 DATA MODEL OPTIMIZATION Data Structure Key Fields Denormalization vs. Normalization Normalization” Definition (Wikipedia): Normalization splits up data to avoid redundancy (duplication) by moving commonly repeating groups of data into a new table. Normalization therefore tends to increase the number of tables that need to be joined in order to perform a given query, but reduces the space required to hold the data and the number of places where it needs to be updated if the data changes. Number of sheets / sheet objects Remove hidden sheets and sheet objects that are not being used Remove unused variables Remember to keep your QlikView document as trim as possible 8.1.2 Document Design Avoid “Show Frequency” Forcing Proper Object Display • Calculation Conditions • Show Conditional Avoid too many active objects on the same sheet Minimized objects consume no resources, use them whenever appropriate 8.1.3 Security Impacts - Making the Right Choices QlikView Publisher Security Section Access Publisher Security Breaking up one large QlikView file into multiple smaller files based on row level security Effective for memory management if security profiles do NOT contain much overlapping data Section Access Dynamically reduces the QlikView file at logon based on user authorization 82 QlikView Developer II | 8 DATA MODEL OPTIMIZATION 8.2 Best Practices for QlikView File Optimization 8.2.1 Complex Dimensions and Expressions Many dimensions and expression that are to be placed in charts or tables require some degree of complex scripting such as IF THEN ELSE statements or WHERE [FIELD1] IS NULL. Many developers build their initial data model using the processes above but then stop amending the script and work solely within the dashboard/GUI. When designing/writing your script you should already be aware of some of the measures that you are looking to create in the end. Where ever possible you should look to place all complex formulas and statements within the script of the document and not in the actual dashboard/document objects. If you are to use complex expressions within a dimension or calculation then you should move as much of this as possible into the scripting of the QVW. 8.2.2 Resource Intensive Expressions Count ( Distinct 'FieldName') Replace the count() with sum() and the distinct qualifier by assigning the value '1' to each distinct occurrence as it is read in the script If ( Condition(Text),…..) Map Text to numeric e.g. by using autonumber and/or do the test in the script Sum ( If (Condition, 'FieldName'…)) Here the aggregation is independent of the table dimensions and the result is distributed over the dimensions of the table. The problem can be treated either by doing the test in the script and aggregating in the table or by doing the whole operation in the script. There are numerous techniques for this e.g. interval match, group by, peek, if….then…else. If ( Condition, Sum('FieldName')..) Included here to emphasize the difference to above. This aggregation is completely contextual If ( Condition1, Sum('FieldName'), If (Condition2, Sum('FieldName') The logic of nested If..then else.. is conceptually easy but can often become troublesome to administer. We have seen cases with hundreds of nesting levels. This will be memory and CPU intensive. Often the "Conditions" can be 83 QlikView Developer II | 8 DATA MODEL OPTIMIZATION replaced by transforming them. A typical example is aggregating quantity*price where price is variable. This can be handled by "extended interval match". If two conditions, e.g. " A AND B " are to be satisfied the test might be replaced by a condition "C". Sort text QlikView automatically evaluates if a Field is to be treated as numeric, text or general. Fields evaluated as text will be sorted as text which is the slowest sort operation. This can be replaced manually to sort by load order. Dynamic captions and text objects Expressions can be entered almost anywhere that you can enter text. The evaluation of an expression is however dependent on its environment. Expressions in charts and straight-and pivot-tables that are defined in the expressions dialog are embedded and only calculated when the object is active. For instance they are not calculated when the object is minimized. On the other hand if the object title is calculated this calculation is performed every time any change occurs. We also have numerous ways of defining show conditions, calculation conditions etc. These tests will also be performed at all times. Some expressions are more expensive than others and of course become more expensive the more frequently they have to be evaluated. The introduction of asynchronous calculation has shifted the behavior and these effects may have become more noticeable in your documents. The time functions e.g. Now(), Today() will be evaluated whenever a recalculation has to be done. Especially the Now() function can become quite costly since it causes a recalculation of the document every second. For example If ( ReloadTime()+3>Now(), 'Old Data', 'New Data') Here one might consider… If ( ReloadTime()+3>Today(), 'Old Data', 'New Data') As a simple test, put the expressions into textboxes. Then try sizing the textbox with Now() in it. 8.2.3 Adding Aggregatable Columns in to Your Script It is sometimes good to add manual columns in to your script to give your document the ability to sum up over these values. This will mean you can then place the complex statement (If) in to your script and have a simple sum in your dashboard object. To do this you should simply place an IF THEN ELSE statement in to your script that substitutes a database column or a 1 or 0 as a value to enable a summing/count to take place. 84 QlikView Developer II | 8 DATA MODEL OPTIMIZATION Examples: IF(ACTIVE='Y',1,0) IF(ACTIVE='Y',sales_amount,0) Forcing through a 0 then takes out all of the unnecessary / unwanted values when you apply your SUM. 8.3 Creating Incremental Loads An incremental load is a common database task. Incremental loads are used when loading only the new or changed records from a database. QVD files are used to do incremental loads in QlikView. Properly engineered incremental loads can significantly improve performance. 85 QlikView Developer II | EXERCISE Exercises Do: In this exercise, we will tie together several Qlikview concepts, including: • QVD incremental loading • Binary Loading Your production system is overloaded when QlikView pulls all history. The CIO comes to you and asks that this stop now. How do you fix it? 1 2 3 Navigate to the course material folder for this chapter, C:\QlikViewTraining\DeveloperII\Chapter08 Open the file in the QVDs folder called BaseLineDataExtraction.QVW reload the file and then choose File | Save As and save the file as BaseLineDataModel.QVW in the QVDs folder. Note that you now have a QVW that contains your Data Model but only has data through 2006 for Orders, OrderDetails, and Shipments. Also note that no Master Calendar has been built yet. Binary Load 1 Close any open QVWs. Create a new QVW and save it as CreateQVDfromBinary.QVW in the QVDs folder. Edit the script or click the Qlikview File button in the Script Editor to add the BINARY load of the BaseLineDataModel.QVW file you just saved in the same folder. Your script should look like this. Binary baselinedatamodel.qvw; SET ThousandSep=','; SET DecimalSep='.'; SET MoneyThousandSep=','; SET MoneyDecimalSep='.'; SET MoneyFormat='$#,##0.00;($#,##0.00)'; SET TimeFormat='h:mm:ss TT'; SET DateFormat='M/D/YYYY'; SET TimestampFormat='M/D/YYYY h:mm:ss[.fff] TT'; SET MonthNames='Jan;Feb;Mar;Apr;May;Jun;Jul;Aug;Sep;Oct; Nov;Dec'; SET DayNames='Mon;Tue;Wed;Thu;Fri;Sat;Sun'; 87 QlikView Developer II | EXERCISE 2 Add the following code to the bottom of your script. SET vDataDir = ‘Datasources\QVDs’; for i = 0 to NoOfTables() - 1 LET d = TableName(i); store $(d) into $(vDataDir)\$(d).QVD; next LET j = NoOfTables(); 3 4 5 6 88 do while j > 0 let d = TableName(0); drop table $(d); let j = NoOfTables(); loop Reload and save the file and look in the Datasources\QVDs folder. You should see: Close any open QVWs. Create a new QVW and save it as MyIncrementalQVDApplication.QVW in the QVDs folder. Open the script editor. On the Main tab create a connection to the QWT.MDB data base. Next edit the script to load all the previously generated QVD files except Orders and Shipments. Create a new script tab called Load QVDs and load the QVDs by clicking the Table Files button, navigating to the Datasources\QVDs folder, and choosing the first QVD file. Repeat the process until all QVD files except Orders, and Shipments have been QlikView Developer II | EXERCISE 7 8 added to the script. Don’t forget to format your script according to best practices and remember to explicitly name each table. Save your work frequently. Create a new script tab called New Orders and add the following code to the script: SQL SELECT * FROM Orders WHERE year(OrderDate) > 2006 ORDER BY OrderDate ASC; Create another new tab called New Order Details and add the following code to the script: OrderDetails: LOAD LineSalesAmount - CostOfGoodsSold AS Margin, * ; LOAD OrderID & '-' & LineNo AS OrderLineKey, Discount, OrderID, ProductID, LineNo, Quantity, UnitPrice, UnitPrice * Quantity * (1 - Discount) AS LineSalesAmount, applymap('UnitCostMap', ProductID, 0) * Quantity AS CostOfGoodsSold WHERE exists(OrderID, OrderID) ; SQL SELECT * FROM `Order Details`; 89 QlikView Developer II | EXERCISE 9 Create another new tab called New Shipments and add the following code to the script: Shipments: LOAD OrderID & '-' & LineNo AS OrderLineKey, ShipmentDate WHERE exists(OrderID, OrderID) ; SQL SELECT * FROM Shipments ORDER BY ShipmentDate; 10 Add another new tab called Load Baseline QVDs and load the information from the Orders.QVD file we created by clicking the Table Files button and choosing the Orders.QVD file. Add the CONCATENATE keyword to the LOAD statement and remember to explicitly specify the table into which you are loading the baseline Orders data. 11 Do the same for OrderDetails and Shipments. They can be placed on the Load Baseline QVDs tabs along with Orders. 90 QlikView Developer II | EXERCISE 12 Add the following code after Shipments on the Load Baseline QVDs tab. This code calculates an OrderSalesAmount and joins it into the Orders table. LEFT JOIN (Orders) LOAD OrderID, sum(LineSalesAmount) AS OrderSalesAmount RESIDENT OrderDetails GROUP BY OrderID; 91 QlikView Developer II | EXERCISE 13 Last, create a Calendar tab (note that Calendar comes after our QVD tab) and add the following code to the script: //set this variable to define dates to generate Temp: LOAD min(OrderDate) AS minDate, max(OrderDate) AS maxDate RESIDENT Orders; LET varMinDate = Num(Peek('minDate', 0, 'Temp')); LET varMaxDate = Num(Peek('maxDate', 0, 'Temp')); DROP TABLE Temp; // varMinDate to varMaxDate TempCalendar: LOAD $(varMinDate)+Iterno()-1 AS Num, Date($(varMinDate)+Iterno()-1) AS TempDate AUTOGENERATE 1 WHILE $(varMinDate)+Iterno()-1<= $(varMaxDate); //Building the master calendar with most date dimensions MasterCalendar: LOAD TempDate AS OrderDate, week(TempDate) AS Week, Year(TempDate) AS Year, Month(TempDate) AS Month, Day(TempDate) AS Day, Year2date(TempDate)*-1 AS CurYTDFlag, Year2date(TempDate,-1)*-1 AS LastYTDFlag, inyear(TempDate,Monthstart($(varMaxDate)),-1) AS RC12, date(monthstart(TempDate), 'MMM-YYYY') AS MonthYear, applymap('QuartersMap', month(TempDate), null()) AS Quarter, Week(TempDate)&'-'&Year(TempDate) AS WeekYear, weekday(TempDate) AS WeekDay RESIDENT 92 QlikView Developer II | EXERCISE TempCalendar ORDER BY TempDate Asc; DROP TABLE TempCalendar; Here we created a temporary table (Temp), found the minimum and maximum OrderDates, and used the peek() function to find the contents of the two fields on the only row of this table. Note also that we could have done one more Resident Load to reorder the new, larger Orders table ascending and then used the original peek() functions to set our min/max date variables. That may have required us to change a table name and then drop the intermediate table after setting the variables – a minor complication. 14 Now reload the document and create a List Box for Year. All the information is in the document with Order, OrderDetails, and Shipment information prior to 2007 coming from our baseline QVDs and any new data going forward coming from a load from our production system. What’s Missing in all this? You don’t normally incrementally update data by Year; you do it every night, every 3 hours, or possibly on demand. We haven’t saved our newly updated Orders, OrderDetails, and Shipments tables (years 2007 -> 2010) for use in the next update cycle. Our parameters must be determined by when the QVD files were last reloaded; read the excellent Qlikview Help article entitled “QVD files and Incremental Load.” We need to create regularly scheduled processes that run our updates (with say, Qlikview Server as a starting point). Perhaps we should just do this for all our tables. We further assumed Orders, OrderDetails, and Shipments were not being changed or cancelled or that new Orders, OrderDetails, and Shipments were not being added into our earlier date ranges; thus, a CreateDate or LastModifiedDate would be handy to have in the data. The Help topic covers all these cases in more detail. Notes For development purposes or extended data manipulation, the binary load operation may come in handy. Only a single binary load statement is allowed in a script. For loops and do while/until loops are common script instruments for designing automation of repetitive script operations. 93 QlikView Developer II | EXERCISE Remember: Storing historical data that does not change into QVD files and then loading that data together with only recently changed data from other data sources is a very effective way of : • optimizing reload speed • reducing impact on source systems • allowing for multiple documents to access a single fast access source of common QVD data The File | Reduce Data option is a fast and flexible way of producing a subset of data based upon your current selection or dropping all data from memory during development. 94 QlikView Developer II | 9 DAILY AND TRANSACTION BALANCES 9 DAILY AND TRANSACTION BALANCES Objectives • • • Introduce the need for balances Explore methods for handling them in QlikView Review sample files 9.1 Overview Sometimes you will find yourself in a situation where you need to create daily balance information from some sort of transaction table, even for days when there are no transactions. In other situations, you might need to record a balance in some sort of transaction table based on the transactions themselves, such as warehouse transactions in/out when there might not be transactions made on all days and keys. With QlikView you can handle these situations. 9.2 Example: Balances at Specific Dates In a situation where the data has records for transaction dates, but where not every date has transactions, you might need to create the missing dates in order to do meaningful analysis on the transactions, such as to determine an Average Daily Balance. The following script creates date values for all possible dates. Note: you can review the source data and solution in: c:\QlikViewTraining\DeveloperII\Chapter09 • Inventory balances based on balances at specific dates.qvw • datasources\data saldon.xls SET SET SET SET SET SET SET SET SET SET ThousandSep=' '; DecimalSep=','; MoneyThousandSep='.'; MoneyDecimalSep=','; MoneyFormat='#.##0,00 kr;-#.##0,00 kr'; TimeFormat='hh:mm:ss'; DateFormat='YYYY-MM-DD'; TimestampFormat='YYYY-MM-DD hh:mm:ss[.fff]'; MonthNames='jan;feb;mar;apr;maj;jun;jul;aug;sep;okt;nov;dec'; DayNames='må;ti;on;to;fr;lö;sö'; 95 QlikView Developer II | 9 DAILY AND TRANSACTION BALANCES /*This script is for creating daily balance from an inventory transaction table. It creates a balance value for each day, even for days with out transactions. It is possible to create weeks or months, to limit the number of rows Table of inventory transactions, in-going balance on first date/key. Key= i.e. warehouse & ItemID This table is often very large and aggregated by day and key. The table only stores booked balances, some time not for all days . We need balance for every day */ tmpResident: Load Key, Date(Date,'YYYYMMDD') as Date, Balance FROM [datasources\data Balance.xls] (biff, embedded labels, table is [Sheet1$]) ; // Variables to set first date and number of dates to generate Let varStartDate=Num(Yearstart(today())-1); Let varNoOfDays=Num(today())-$(varStartDate); // Connects all Keys to all dates within the date range set by variables // Generates lots of rows i.e. 10 000 keys * 1 000 days = 10 000 000 rows tmpJoin: Load Distinct Key Resident tmpResident Order By Key ; Join Load Date($(varStartDate)+(RecNo()),'YYYYMMDD') as Date Autogenerate today()-$(varStartDate); // Mapping table created from transaction table. // Only actual transaction dates for each key mapValue: Mapping Load Key&Date as a, Balance as b Resident tmpResident 96 QlikView Developer II | 9 DAILY AND TRANSACTION BALANCES ; // Final table, accumulating sum. // Resident table from the join table. Has all combinations of key & date // Applymap() used to get inventory movements on acutual dates and 0 for other dates // Order by Key & Date to be able to use Peek(). // Checking the first row and if the previous row has the same key. Final: Load distinct %Key, BalanceDate, [Reg Balance], // Just for demo If([Reg Balance]='x',Peek([Daily Balance]),[Reg Balance]) as [Daily Balance] ; Load Key as %Key, Date as BalanceDate, Applymap('mapValue',Key&Date,'x') as [Reg Balance] Resident tmpJoin Order By Key, Date; Drop table tmpResident, tmpJoin; // Dates generated for demo demodates: Load Date as BalanceDate, Month(Date) as Month, Week(Date) as Week ; Load Date($(varStartDate)+(RecNo()),'YYYYMMDD') as Date Autogenerate today()-$(varStartDate) ; 97 QlikView Developer II | 9 DAILY AND TRANSACTION BALANCES Figure 1. Table Viewer preview showing the resulting values 9.3 Example: Balances for Transactions (in/out) A similar process is used to create the appropriate set of dates and keys for warehouse transaction records, including dates for which no transactions exist. 98 QlikView Developer II | 9 DAILY AND TRANSACTION BALANCES Note: you can review the source data and solution in: c:\QlikViewTraining\DeveloperII\Chapter09 • Inventory Balances based on Transactions.qvw • datasources\data trans.xls 99 QlikView Developer II | 10 QLIKVIEW SECURITY 10 QLIKVIEW SECURITY Objectives • • • Understand the components of QlikView document security Discuss access control and restrictions Practice implementing QlikView Section Access Computer security is an important element of most organizations. In this chapter we will go through some methods that can be used to limit the access to QlikView documents solely from the QlikView Desktop (e.g. without QlikView Server). It is important though to realize that this chapter is not a general chapter on QlikView security, but only an introduction to some of the methods you can use directly in QlikView to limit the access in a QlikView document. In this chapter we will go through how you can work with QlikView security by handing every user a user id and a password. We will also go through how to use NT Name and NT Domain SID to allow single sign on to a QlikView document. Finally, we will look into how you can dynamically reduce the amount of data shown to a user. 10.1 Access control A QlikView document is an encrypted file consisting of a database, script, layout, etc. The file format itself provides some intrinsic protection, since it is not possible to open the file if you do not have QlikView. It is also possible to include access levels in the load script. 10.2 Access levels Each user of the QlikView document can be assigned an access level: ADMIN or USER. An individual with ADMIN privileges can change everything in the document, whereas a person with USER privileges has restricted access. A user of a QlikView client will be automatically restricted to USER privileges, regardless of SECTION ACCESS settings. If no access level is assigned to a user in SECTION ACCESS, the user cannot open the QlikView document. For clarity, it may be useful to use other access levels, e.g. NONE. These will always be treated as “no access”. 101 QlikView Developer II | 10 QLIKVIEW SECURITY 10.3 Access control database All access control is managed via text files, databases or INLINE clauses in the same way as data is normally handled by QlikView. The tables are loaded in the normal way, but first an ACCESS section is loaded in the script in a section declared by the statement, SECTION ACCESS. TIP: Be aware that all field names and values will be automatically converted to upper case in SECTION ACCESS. This must be taken into consideration when using preceding LOAD or RESIDENT LOAD statements within SECTION ACCESS. If an ACCESS section is declared in the load script, the part of the script that loads standard data must be preceded by the statement SECTION APPLICATION There are several protected field names in the access control database, including: USERID, PASSWORD, SERIAL, NTNAME, NTDOMAINSID, NTSID, and ACCESS. Other user-defined fields may be added, e.g., GROUP or DEPARTMENT, to facilitate dynamic data reduction or for administration, but QlikView does not use the extra fields for limiting access to the document. None, all or any combination of the security fields may be loaded in the SECTION ACCESS. If none of the security fields is loaded, all the users will have ADMIN rights. As another example, it is not necessary to use USERID – a check can be made on SERIAL only. This fact can be used for command-line reloads of access-restricted documents. The protected field names are defined below: ACCESS A field that defines what access the user should have. USERID A field that should contain a user id that has the privilege specified in the field ACCESS. PASSWORD A field that should contain an accepted password. SERIAL A field that should contain a number corresponding to the QlikView Serial Number. Example: 4900 2394 7113 7304 NTNAME A field that should contain a string corresponding to a Windows NT Domain user name or group name. NTDOMAINSID A field that should contain a string corresponding to a Windows NT Domain SID. Example: S-1-5-21-125976590-467238106-1092489882 102 QlikView Developer II | 10 QLIKVIEW SECURITY NTSID A field that should contain a Windows NT SID. Example: S-1-5-21-125976590-467238106-10924898821378 OMIT A field that should contain a list of fields that should be omitted for this specific user. Wildcards may be used and the list may be empty. QlikView will compare the QlikView serial number with the field SERIAL, the Windows NT User name and groups with NTNAME, the Windows NT Domain SID with NTDOMAINSID and the Windows NT SID with NTSID. It will further prompt for User ID and Password and compare these with the fields USERID and PASSWORD. If a valid combination of user ID, a password and environment property is also found in the Section Access table, then the document is opened with the corresponding access level. If not, QlikView will deny the user access to the document. If the user ID and/or the password are not entered correctly within three attempts, the entire logon procedure must be repeated. In the logon procedure, QlikView will first check SERIAL, NTNAME, NTDOMAINSID, and NTSID to see if this information is sufficient to grant the user access to the document. If so, QlikView will open the document without prompting for USERID and PASSWORD. If only some of the access fields are loaded, actions appropriate to the missing data are taken, e.g., prompts for more information. All the field names listed in LOAD or SELECT statements in the section access must be written in UPPER CASE. Any field name containing lower case letters in the database will be converted to upper case before being read by the LOAD or SELECT statement. However, the USERID and the PASSWORD entered by the end-user opening the QlikView documents are case insensitive. Section Access; LOAD * INLINE [ ACCESS, USERID, PASSWORD ADMIN, NEWDBA, ABC ]; Section Application; ..... 10.4 Inherited access restrictions A binary statement will cause the access restrictions to be inherited by the new QlikView document that contains the binary statement. A person with ADMIN rights to this new document may change the access rights of the 103 QlikView Developer II | 10 QLIKVIEW SECURITY new document by adding a new SECTION ACCESS. A person with USER rights can execute the script and change the script (by adding their own data to the file loaded with the binary statement). A person with USER rights cannot change the access rights. This makes it possible for a database administrator to control user access, including those that start with a binary statement. 10.5 Hidden script A hidden script is a password protected hidden area of script code that is always executed prior to the standard script during a reload. When choosing Edit Hidden Script from the File menu in the Edit Script dialog, you will be prompted for a password that will be required before giving access to the hidden script. If it is the first time you access the hidden script in a document (thereby creating one), you will have to confirm the new password. After this, the Hidden Script tab will appear to the left of all other script tabs and remain there until you close the document. Keep in mind the following characteristics of hidden scripts if you choose to use them: • If a hidden script is used, the binary command cannot be used in the normal script, since it must be the first statement executed in a document script. • Tables generated by the hidden part of the script will not be represented by name in the $Table system field. • The Script Execution Progress dialog will not be updated during the execution of a hidden script. No entries will be made in the log file, if used. Note that as of QlikView version 7, there is available a Document Security override to Show Progress for Hidden Script. The progress information will also be written to the script execution log, if applicable. • If the hidden script contains a Section Access, such a section will not be permitted in the normal script nor in a script starting with a binary load of the QlikView file containing the hidden script. 10.6 Adding Section Access We will now add the necessary lines to our script to check the access rights of various users. It is generally good practice to place the script code for section access in the “hidden script” area. Before you start working with security in QlikView, make sure to save a back up of your document without security. This is a safety measure so that you can start from the beginning again if the security section does not work. 104 QlikView Developer II | 10 QLIKVIEW SECURITY Warning! IT IS STRONGLY SUGGESTED TO SAVE A DOCUMENT WITH SECTION ACCESSAS A NEW FILE NAME AFTER RELOAD, BUT BEFORE ATTEMPTING TO CLOSE AND REOPEN THE QlikView DOCUMENT. IF LOGICAL ERRORS EXIST IN SECTION ACCESS, IT MAY NO LONGER BE POSSIBLE TO OPEN THE DOCUMENT ONCE IT IS RELOADED. 105 QlikView Developer II | EXERCISE Exercise Do: Setting up Access Security on a QlikView file 1 2 3 4 5 6 7 8 Launch QlikView and save a working copy of the QlikView file in the working directory for this chapter (C:\QlikViewTraining\DeveloperII\Chapter10) Once again, be sure to save the document under another Name. e.g. QlikViewTraining_wSecurity. Open the Script Editor. Go to the File menu and Create Hidden Script… Enter the password hidden and confirm the password. Choose Section Access | Inline from the Insert menu. Select Basic User Access Table so the ACCESS, USERID and PASSWORD are checked. Click OK and add the following lines to the table. Figure 1. Using the Inline Data Wizard for Security. 107 QlikView Developer II | EXERCISE 9 Click OK. The wizard should have created the following script statement. Section Access; LOAD * INLINE [ ACCESS, USERID, PASSWORD ADMIN, ADMIN, ADMIN USER, USER, USER ]; Section Application; 10 Name this table Access01. NOTE: YOU MUST INCLUDE THE Section Application STATEMENT AFTER THE ACCESS LOAD TO PRODUCE A USABLE DOCUMENT. 11 Save and Reload the script. This simple access check will require the users to identify themselves when opening a document. The UserID, User and Password User will prevent the user from accessing the load script if that security is set in the Document Properties. A user belonging to the USER group is also denied access to the Security tab in the Document Properties and Sheet Properties dialogs. The UserID Admin together with the Password Admin will give the user the rights to make all changes to the document in QlikView Desktop. Do: 1 Exit QlikView and open your newly named document again. You will now see the following dialog box where you can enter your UserID and Password. Figure 2. The User Identification dialog. 108 QlikView Developer II | EXERCISE 10.7 Access control for certain commands The settings under the Security tabs in the Document Properties dialog and the Sheet Properties dialog in the Settings menu can prevent users from using certain menu commands and changing the layout. To use these settings as security measures, it is important, however, that the users have only User rights. All users who have Admin rights can change the security settings at any time. Do: Note: It is not possible to complete this exercise with QlikView Personal Edition. 1 2 3 4 Make sure you are logged in to the QlikView document as Admin. (You must have Admin rights to perform the following.) Go to the Settings menu and Document properties. Go to the Security tab and select what the Users should and should not be allowed to do. Make sure that a User is not allowed to Reload the script or to Save the document. Make sure to check the Admin Override Security check box so that the Admin always has permissions to do everything. Figure 3. Document Properties - Security 5 Click OK and Save the document. 109 QlikView Developer II | EXERCISE 6 Close the document, exit QlikView and open it again, and log on as a User. Note that you will not be able to Save the document or Reload the script. Tip: There is a Security tab in the Sheet Properties dialog as well where you can set security for the current sheet and apply to all sheets. 10.8 Further access control It is easy to increase the security control for those users who we believe will require access to a specific document. By adding a field to the previously created INLINE table, we can connect it to a new, two-column table in which we specify the serial numbers that have access to the document. In this way, we can restrict access to a specific document even further. The new, two-column table will be created in Notepad, or a similar text editor, and be called Access. We will save this new, tab-delimited text file in the DataSources directory. Do: 1 Add another field called COMPUTER to the previously existing Access01 INLINE table. Include one or two identifiers for course computers (these will act as connected fields) as shown below. Section Access; LOAD * INLINE [ ACCESS, USERID, PASSWORD, COMPUTER ADMIN, ADMIN, ADMIN, COURSE1 USER, USER, USER, COURSE2 ]; Section Application; 2 3 4 Open Notepad, or a similar text editor Create a two-column table with the fields COMPUTER and SERIAL. Include your own serial number as a field value; you will find this number under the About QlikView menu in QlikView. An example is shown below. COMPUTER Course1 Course2 Save this file as Access02.txt. SERIAL 2300 2394 7111 8000 2300 2394 7111 8001 It can be seen that only two license numbers have access to the document we have created, one with User rights and one with Admin rights. Also, 110 QlikView Developer II | EXERCISE 5 note that we are adding restrictions to existing UserIDs (User), and not replacing current restrictions. Open the load script, position the cursor and click on the Table Files button. Load the newly created table Access02.txt after the inline table, and prior to the SECTION APPLICATION statement, as shown below. Access02: Load COMPUTER, SERIAL FROM Datasources\Access02.txt (ansi, txt, delimiter is '\t', embedded labels); Section Application; 6 7 Save and Reload the document. Close the document and open it again as a User. Assuming that you have not entered your serial number in both records in the Access02.txt file, you may only log in as a User or Admin. It would be easy to add a third line to the access control tables which always gave every serial number User rights, assuming a valid User ID and Password. To do this, we can add a third computer (e.g. Course3) and enter * as the value in the Serial field. 10.9 Unattended Command Line Reload Considerations To create security access for a non-intervention command line reload process, you would enter the Serial registered to the user assigned to the reload process on the reload computer. Then connect this to UserID and Password with * as values (* here means all possible values, which would avoid the USerID and Password prompts). You should also set the Access field to Admin for this user. If you add the following record to the Access01 LOAD INLINE statement, this will allow the Course2 computer to be used for unattended reloads. *,*,ADMIN,COURSE2] 10.10 Access restrictions on selected field values QlikView secured access provides a feature to prevent users from viewing parts of the data in a document. This feature was primarily developed for QlikView Server, but can also be used in QlikView, with a few considerations. 111 QlikView Developer II | EXERCISE The selection of values to be shown or hidden is controlled by having one or more fields with the same names in SECTION ACCESS and SECTION APPLICATION. When the user has logged in, QlikView will copy the (upper case) selected values in SECTION ACCESS to fields in SECTION APPLICATION with the same name. QlikView will permanently conceal, from the user, all the data excluded by this process. All field names and values used to connect SECTION ACCESS and SECTION APPLICATION must be written in upper case, since all field names and field values are, by default, converted to upper case in SECTION ACCESS. To use this feature, the option Initial Data Reduction Based on Section Access on the Opening page of the Document Properties dialog must be checked. If this feature is used in documents that are to be distributed by other means than via QlikView Server, the option Prohibit Binary Load, on the same page, must be selected to maintain the integrity of data protection. TIP: There is a known issue in Dynamic Data Reduction QlikView documents where a fully executed reload will override dynamic data reduction settings – allowing users to see “all” data. To mitigate this security risk, QlikView prohibits data reloads in documents that have dynamic data reduction in effect. 10.11 Field value limitation in Section Access We will now show how to limit the amount of data shown in our QlikView document. We want to distribute the file to the employees involved in sales. Each salesperson will, however, not have access to data pertaining to their peers. Therefore, we will add a limitation to the script, which ensures that people only have access to their own data. We will use two text files for this purpose. The first file will establish the SECTION ACCESS fields for each allowed user. The second text file will be loaded in SECTION APPLICATION and limit the document data that each allowed user will be able to view once they open the QlikView document. Both text files are located in the Datasources directory. We must also bear in mind that we need an administrator to manage the document. One of the salespersons is also the Sales Manager of the company, and he should naturally have access to the entire document to be able to assess the performance of each salesperson. We also have a Sales Coordinator in Lund who should have access to the data on all salespersons. This access can be implemented through use of a null field value specified in the connecting field when loaded in the SECTION ACCESS section. You could use the * value for this field, as we used earlier for the UserID and Password 112 QlikView Developer II | EXERCISE fields, but it is generally preferable to use null for connecting fields, since this will allow access to ALL data, regardless of whether it has a logical connection to the connecting field. Do: 1 2 3 4 5 Open the load script and File - Edit Hidden Script (note that you must have Admin privileges to edit the hidden script). Verify that your cursor is positioned on the Hidden Script tab. Now, comment the previously loaded INLINE tables so that they will not interfere with our new SECTION ACCESS tables. The first text file to load is SalesSecurity.txt, located in the Datasources directory. Label this logical table as Access01. Then, add the SECTION APPLICATION statement. Next, create a load statement for the SalesInitials.txt file, located in the Datasources directory. It is good practice to use the Upper function against the connecting field (SP), since the value must be uppercase to match the value from SECTION ACCESS. The new statements should resemble the following. Section Access; Access01: Load [USERID], [ACCESS], SP /* Connecting field for data reduction */ FROM Datasources\SalesSecurity.txt (ansi, txt, delimiter is '\t', embedded labels); Section Application; Access_Application: Load upper(SP) as SP, /* Connecting field for data reduction */ [SalesPerson] FROM Datasources\SalesInitials.txt (ansi, txt, delimiter is '\t', embedded labels); 6 7 8 Save and Reload the document. Go to the Settings menu and to Document Properties. Select the Opening tab and check Initial Data Reduction Based on Section Access. Make sure to uncheck Strict Exclusion. Also, check Prohibit Binary Load. 113 QlikView Developer II | EXERCISE 9 Go on to the Security tab and make sure that a User cannot edit or reload the script. Save should not be allowed either (uncheck the checkboxes Edit Script, Reload, Partial Reload, Save Document and Allow User Reload). 10 Save again and exit the document. 11 Open the document again and log on with Leif as UserID. Notice that you can view data for this user, as well as the Sales Persons, Tom Lindwall and Frank Roll. 12 Close the document and open it again, this time using James. You will now be able to see all data again. 114 QlikView Developer II | 11 ADVANCED DATABASE CONNECTIVITY 11 ADVANCED DATABASE CONNECTIVITY Objectives • • • Explore the QlikView Custom Data tab Understand the sequence for connecting to custom data sources Show the Connect and Select statements and familiar dialogs that generate QlikView load script syntax So far we have focused on loading data using the different options on the Data page of the script editor. Figure 1. The data page in the QlikView Script Editor Data can also be loaded using a custom data source. 11.1 Custom Data The Database dropdown allows you to get data from custom data sources into QlikView. QlikView offers an open-source plug-in interface, providing possibility to program custom interfaces to various types of data sources not covered from the traditional file, ODBC or OLEDB interfaces. The typical case is data available via Web Services. The plug-in should be programmed according to specifications shown in a template code provided (on request) as open-source from QlikTech and compiled as a dll. The dll is then placed next to the QV.EXE file making the custom source available to use. It will then appear in the drop-down box for selection. 115 QlikView Developer II | 11 ADVANCED DATABASE CONNECTIVITY Figure 2. The dropdown selector in QlikView Script Editor The Connect button Opens the Connect dialog box for connecting to the custom data source. This dialog may look in different ways depending on the data source used. Once connected, the Select button opens the Select button opens a dialog from which users can select fields and tables to be included in the load script. The script is generated based on your selections. Figure 3. Sample script 11.2 SAP Connector QlikView offers an SAP Connector as a separately licensed product for data extraction and analysis from SAP ERP systems. This is an SAP Certified integration. QlikView offers: • Connector • ScriptBuilder • ExtractSAP • BW Cube QVD Generator • Templates / Demo documents 116 QlikView Developer II | 11 ADVANCED DATABASE CONNECTIVITY Figure 4. Initial (General settings portion) load script 117 QlikView Developer II | 12 BUSINESS CASE WORKSHOP 12 BUSINESS CASE WORKSHOP Objective • • Build a working QlikView analysis document based upon the requirements Review it with your instructor and classmates The Business Case Workshop is designed to give you an opportunity to use the expertise and knowledge you have gained in training to build a working QlikView document based upon a set of business requirements and data provided by your instructor. Although not formally an exam, this activity should be comprised of your own work. Certainly, when you need help, you should ask for it, either from your instructor or your classmates. You will find the high-level requirements for the QlikView document outlined in the scenario section below. Subsequently, a detailed list of the source data and field definitions follow. As with any real world example, you will find problems with the data. These will require you to use some of the solutions and workarounds presented in the class. Finally, we would appreciate receiving your comments and suggestions for improving both the standard course materials and this business case workshop. Good luck. 12.1 Scenario ACME Inc., is a food & drink distributor selling to different types of stores across the United States and also internationally. They are interested in getting a better understanding of their Sales and Margin performance across their business. They have asked you to develop a Sales Analytics QlikView document for them. The document will be used by their top executives, their product managers and also their salespeople. 119 QlikView Developer II | EXERCISE Requirements ACME has listed their requirements for the solution as follows: Do: Build a QlikView document 1 2 3 4 They want to be able to analyze their sales figures and do comparison with previous years and compare against their budget. They are also interested in analyzing their Sales margin. They would like to see this across many of their business dimensions. For example: • Division • Country • Region • State/Province • Sales Rep • Product Line • Product Group • Product and Customer They are also keen to analyze their average sales both per transaction but also per customer. In conclusion they are also interested in following up on the number of customers during a given period for example YTD versus LY YTD. Do: For Extra Credit 1 They are interested in analyzing their delivery performance how they are delivering compared to what they have promised. Note: they count each invoice as a delivery so use the max promised date and actual delivery date for each invoice. They only are interested to analyze delivery performance for 2008. 2 Describe how could they could easily distribute this information across their different user groups. That is to say, different user groups want to analyze the same data but from different perspectives. 12.2 Data Structure The following tables outline information about ACME’s source data to be used to complete the QVW document in support of the business requirements. 12.2.1 SALESDETAILS.QVD This table contains the company sales and order transactions. 121 QlikView Developer II | EXERCISE Field# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 122 Field Name Actual Delivery Date Address Number CustKey Description The Actual date of Delivery Not used A unique ID of the Customer. Used as a key field Backlog Amount The backlog amount of an order BackOrder Amount Amount on Backorder DateKey Not Used Discount Amount Discount Amount Doc Type The Document Type RI = Invoice RM = Credit Invoice Family Class Not Used Invoice Date The date of the Invoice Invoice Number The unique identifier of an Invoice, used as a Key field Item-Branch Key The Key field to link to the Item Branch Table Item Class Not Used Item Number Not Used Line Desc 1 The Description of the Item Line Number The Line Number on the Invoice Line Type Not Used List Price The List price for Item Order Number The order number Parent Address Number Not Used Payment Terms The payment Terms Promised Delivery Date The date the order was promised for Delivery Sales Amount The Actual Sales Line Amount Sales Amount Based on List Price The Sale Line Amount based on the List Price Sales Cost Amount The Actual Sales Cost Amount QlikView Developer II | EXERCISE 26 Sales Margin Amount 27 28 29 Sales Price Sales Quantity Sales Rep 30 31 Sales Unit Cost Price U/M 32 Unit Price The Actual Sales Margin Line Amount The Sales Price of the item The Sales Quantity The Sales Rep in Charge of the transaction (Sale) The Cost price of the Item The Unit of Measure used for the Quantity Not Used 12.2.2 BUDGET.QVD This table contains the budget data. Field# 1 Field BudgetPeriod 2 3 4 Budget Amount BudgetYear Customer Number 5 textBudgetPeriod Description The budget period 1 = January 12 = December The budget Amount The Year of the Budget The CustomerID Used as a key field The budget period as text January, February etc. 12.2.3 CUSTOMERS.QVD This table contains Customer information. . FieldNo 1 Field Address Number 2 3 4 5 Business Family Business Unit Customer Customer Number 6 Customer Type Description A unique address number for the customer. Used as a key field Not Used Not Used The Name of the Customer The unique Customer ID used as a Key Field Not Used 123 QlikView Developer II | EXERCISE 7 Division 8 9 10 Line of Business Phone Region Code 11 12 Regional Sales Mgr Search Type Indicates the Division the customer belongs to. Used as a key field Not Used Not Used Indicates the Region the customer belongs to. Used as a key field Not Used Not Used 12.2.4 CUSTOMERADDRESS.QVD This table contains the address information for the customer. Field# 1 Field Address Number 2 3 4 City Country Customer Address 1 5 6 7 8 Customer Address 2 Customer Address 3 Customer Address 4 State 9 Zip Code Description A unique address number for the customer. Used as a key field The city The Country The address of the customers The address of the customers The address of the customers The address of the customers The State / Province code used as a key field The Zip Code / Postal Code of the customer 12.2.5 STATEDESCRIPTION.QVD This table contains the state descriptions. 124 Field# 1 Field State 2 3 state_abbr state_name Description The State / Province code used as a key field Abbriviated state name (code) The name of the state/province QlikView Developer II | EXERCISE 12.2.6 REGION.QVD This table contains the Region descriptions. Field# 1 2 Field Region Name Region Code Description The Name of the Region The region code. Used as a Key Field 12.2.7 DIVISION.QVD This table contains the Division descriptions. $Field# 1 2 $Field Division Name Division Description The Name of the Division The Division code. Used as a KeyField 12.2.8 SALESREP.QVD This table contains information about SalesReps. FieldNo 1 Field Sales Rep 2 Sales Rep Name Description The salesrep code. Used as a key field The Name of the Sales Rep 12.2.9 ITEMBRANCH.QVD This table contains Item Branch information. Main purpose is to link to the ItemMaster table FieldNo 1 2 3 Field Item Branch 2nd Item Number Item Branch Category Code 6 Item Branch G/L Category 4 Item-Branch Key 5 Item Branch Reorder Quantity 6 Short Name Description Not used Not used May be used by Finance department Item Branch key. Used as a Key field The reorder point at the branch Used a Key Field (unique Item Identifier) 125 QlikView Developer II | EXERCISE 12.2.10 ITEMMASTER.QVD This table is the Item Master table. $Field# 1 $Field Master Planning Family 2 3 Product Department Product Group 4 Product Line 5 6 Product Price Group Product Sub Group 7 8 Product Type Short Name Description The planning family for the item Not Used The product group code. Used as a key Field The product Line code. Used as a key Field Not Used The product sub group code. Used as a key Field Not Used Used a Key Field (unique Item Identifier) 12.2.11 PRODUCTGROUP.TXT This table contains the Product group descriptions. . $FieldN # 1 $Field Description Product Group 2 Product Group Desc The product group code. Used as a key Field The product group description 12.2.12 PRODUCTLINE .TXT This table contains the Product Line descriptions. Field# 1 Field Product Line 2 Product Line Desc Description The product Line code. Used as a key Field The Description of the product line 12.2.13 PRODUCTSUBGROUP .TXT This table contains the Product subgroup descriptions. . $Field# 126 $Field Description QlikView Developer II | 12 BUSINESS CASE WORKSHOP 1 Product Sub Group 2 Product Sub Group Desc The product sub group code. Used as a key Field The product Sub group Description 127
Copyright © 2024 DOKUMEN.SITE Inc.