QV - Developer - II - Course - Manual - V9.00 - PRINT
QV - Developer - II - Course - Manual - V9.00 - PRINT
1 INTRODUCTION 7
Installing the Course Materials 7
Program versions 7
Text formats 7
2 FDEVELOPER TOOLS 9
Troubleshooting 9
The Debugger 9
3 MAPPING TABLES 19
Mapping Quarters to the Orders table 19
MonthYear 23
Cleaning up the table structure 26
5 ADVANCED SCRIPTING 37
Condition on a field in a table 37
Aggregating Data 37
Joining tables 37
Concatenation 38
Preceding Load on Preceding Load 39
AGGR Function 54
10QLIKVIEW SECURITY 99
Access control 99
Access levels 99
Access control database 100
Inherited access restrictions 101
Hidden script 102
Adding Section Access 102
Access control for certain commands 106
Further access control 107
Unattended Command Line Reload Considerations 109
Access restrictions on selected field values 109
Field value limitation in Section Access 110
4
QlikView Developer II | CONTENT
5
QlikView Developer II | CONTENT
6
QlikView Developer II | 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.
Program versions
This course was created using the English version of QlikView 9.00 running
on WindowsXP. If other operating systems or languages are used, minor dif-
ferences may be noted in the visual appearance of windows and dialog
boxes.
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 con-
taining a sequence of steps.
1 Click on the Start button
2 Locate the QlikView icon
3 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
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
7
QlikView Developer II | INTRODUCTION
8
QlikView Developer II | FDEVELOPER TOOLS
2 FDEVELOPER TOOLS
Objectives
• Understand the importance of troubleshooting
• Use the debugger
• Introduce additional tools and methods
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 appli-
cation but will point you in the direction of where to look if your applica-
tion 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 application.
Also, during script execution in debug mode, the debugger allows for moni-
toring 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.
The Debugger
9
QlikView Developer II | FDEVELOPER 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 semi-
colon 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.
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 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder.
2 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
3 Open the file \Debugging\Variable.qvw. Enter the debugger from the
script editor and check the breakpoints that have been set in the script
4 Use the 'Run' button to execute the script up until the following break-
point.
5 Note that the variable mySetVar is not listed in the bottom right variable
monitor pane.
6 Hit Run again and note that the value of the mySetVar variable has been
set.
7 Hit Run once more and exit the script.
8 Repeat steps 3 to 6 and note on step 4 that the variable mySetVar still
retains the value from the previous execution.
9 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 | FDEVELOPER TOOLS
You can also see where NULL values happen across tables and within fields.
NULL values can adversely effect an application and the selection of data.
12
QlikView Developer II | EXERCISE
Exercise
Do:
1 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder.
2 Open the application 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.
3 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 relation-
ships. Only included / possible values are displayed in a table box.
13
QlikView Developer II | FDEVELOPER TOOLS
14
QlikView Developer II | EXERCISE
Exercise
Do:
1 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder.
2 Open the application KeyFields.qvw
3 Comment the script on the Standard Join tab and uncomment the script
on the Copy of Keys tab.
4 Save and reload.
5 Note that the key field in each table has been renamed uniquely, i.e., Key
AS Key1_Table1.
6 Create List Boxes for all fields.
7 SELECT ALL on one of the aliased key fields.
8 SELECT EXCLUDED on the Key field (right click in the Key field List Box
and choose SELECT EXCLUDED).
9 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.
Do:
1 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder.
2 Open the ComplexEquations.QVW.
3 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
15
QlikView Developer II | EXERCISE
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 sys-
tems, 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 for-
mat is consistent throughout the entire key field.
Do:
1 Navigate to the C:\QlikViewTraining\DeveloperII\Chapter02 folder.
16
QlikView Developer II | EXERCISE
2 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:
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 dis-
plays 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 deci-
mal 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.
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 | MAPPING TABLES
3 MAPPING TABLES
Objectives
• Understand mapping tables
• Use mapping tables to add Quarters to the Orders table
• Clean up the table structure
19
QlikView Developer II | MAPPING TABLES
Figure 2. Month field with key indicator in the Available Fields listing.
20
QlikView Developer II | EXERCISE
Exercise
Do:
1 Launch QlikView and save a working copy of the MappingTables.qvw
QlikView file in the working directory for this chapter
(C:\QlikViewTraining\DeveloperII\Chapter03).
2 Open the Edit Script dialog.
3 Now, let us change the Quarters table load into a mapping load.
4 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.
5 Add _Map to the table name.
6 On the next line, type MAPPING in front of the LOAD statement.
7 When complete, verify that this section of your script resembles the fol-
lowing:
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. How-
ever, 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 ] )
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 con-
tain any matching value for expr. If no default is provided, the value of
expr is returned as NULL.
8 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
22
QlikView Developer II | MAPPING TABLES
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.
Open the Edit Script dialog from the menu or toolbar.
23
QlikView Developer II | EXERCISE
Exercise
Do:
1 Return to the MappingTables.qvw file you have been working on in this
chapter.
2 Open the Edit Script dialog from the menu or toolbar.
1 Locate the Orders table LOAD statement.
2 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 Order-
Date 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 Month-
Year 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), 'MMM-
YYYY') AS
MonthYear,
OrderID,
OrderID AS OrderIDCounter,
ShipperID;
24
QlikView Developer II | EXERCISE
SQL SELECT *
FROM Orders;
3 Save and Reload the script.
4 Add a List Box for the new MonthYear field to your sheet.
25
QlikView Developer II | MAPPING TABLES
26
QlikView Developer II | EXERCISE
Exercise
Do:
1 Return to the file you have been working on in this chapter.
2 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.
27
QlikView Developer II | EXERCISE
6 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), 'MMM-
YYYY') AS
MonthYear,
OrderID,
OrderID AS OrderIDCounter,
ShipperID,
applymap('Shippers_Map', ShipperID,
'MISSING')
AS Shipper;
SQL SELECT *
FROM Orders;
7 Save the document and Reload the script.
8 Take a look in the Table Viewer to see that in fact the Shipper field is
now a part of the Orders table.
28
QlikView Developer II | EXERCISE
29
QlikView Developer II | EXERCISE
StateProvince;
SQL SELECT *
FROM Customers;
30
QlikView Developer II | LOADING BUDGET DATA
Objectives
• Understand cross tables
• Use the File Wizard to transform the data and create load script
• Create an input field to use in the budget prognosis
In our example data, there is a Budget table for Employees and Offices. We
are going to load this into our 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.
31
QlikView Developer II | EXERCISE
33
QlikView Developer II |
12 Click Finish. You should have the following table in the script.
CROSSTABLE(BudgetYear, BudgetAmount, 2)
LOAD Office,
EmployeeID,
[2005],
[2006],
[2007],
[2008],
[2009]
FROM Datasources\Budget.xls
(biff, header is line, embedded labels, table is
[Sheet1$], filters(Replace(1, top, StrCnd(null))
));
13 Name this table Budgets.
14 Save and Reload the document.
Open the Table Viewer. As you can see, there is a synthetic key between
the Budgets and the Employees table. We want to remove this synthetic
key. All values in the Budget table for Office and Employees should be
in the Employees table. This means that we can resolve this synthetic key
by concatenating the fields involved into a key field, and just keep them
in the Employees table.
15 Go to the Script Editor.
16 Change the Budget table to the following script. Make sure you change
the CROSSTABLE statement to have only one qualifying field.
Budgets:
CROSSTABLE(BudgetYear, BudgetAmount, 1)
LOAD Office&'-'&EmployeeID AS BudgetKey,
[2005],
[2006],
[2007],
[2008],
[2009]
FROM Datasources\Budget.xls
(biff, header is line, embedded labels, table is
[Sheet1$], filters(Replace(1, top, StrCnd(null))
));
17 Go to the File Data tab and add the following line to the top of the
Employees table.
Office&'-'&EmpID AS BudgetKey,
18 Save and Reload the script.
34
QlikView Developer II |
Do:
1 Return to the QlikView file you have been working on in this chapter.
2 Go to the Script Editor and place the cursor right after the SET state-
ments on the Main tab.
3 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.
4 Go to the Budget tab and modify the Budgets table into a BudgetsTemp
table as seen below. This will allow us to create the BudgetPrognosis
field. By loading the BudgetAmount values first, we can then use it as a
default value for our Budget Prognosis input field.
BudgetsTemp:
CROSSTABLE(BudgetYear, BudgetAmount, 1)
LOAD Office & '-' & EmployeeID AS BudgetKey,
[2005],
[2006],
[2007],
[2008],
[2009]
FROM Datasources\Budget.xls (biff, header is line,
embedded labels, table is [Sheet1$], filters(
Replace(1, top, StrCnd(null))
));
Budgets:
LOAD *,
BudgetAmount AS BudgetPrognosis
RESIDENT BudgetsTemp;
DROP TABLE BudgetsTemp;
5 Save and Reload the script.
Now, we can use the INPUT field BudgetPrognosis to set different bud-
get values if we need to alter the budget to correspond to the actual val-
ues.
6 Create a new Table Box titled Sales Budget consisting of the following
fields: SalesPerson, BudgetYear, BudgetAmount, and BudgetPrognosis.
35
QlikView Developer II |
7 Move your mouse cursor over the BudgetPrognosis column in the table
box. An entry arrow icon will appear.
8 Click on the Input icon on any row and enter any number.
9 Right-click on the BudgetPrognosis column. Notice the related options
of Restore Single Value, Restore Possible Values, and Restore All
Values.
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.
36
QlikView Developer II | 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
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 LineSale-
sAmount, but we want to have a total amount for each Order. To accom-
plish 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.
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 data-
base 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!
37
QlikView Developer II | ADVANCED SCRIPTING
Concatenation
Another way to join data together from multiple tables is to use concatena-
tion. There are three ways to concatenate data. We will explore each of these
methods.
Automatic Concatenation
If the field names and the number of fields of two or more loaded
tables are exactly the same, QlikView will automatically concate-
nate 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.
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.
38
QlikView Developer II | ADVANCED SCRIPTING
Prevent Concatenation
If two tables have the same set of fields and thus would normally
be automatically concatenated, you can prevent the concatena-
tion 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.
39
QlikView Developer II | EXERCISE
Exercises
Do: Condition on a Field in a Table
1 Launch QlikView and save a working copy of the AdvancedScript-
ing.qvw QlikView file in the working directory for this chapter
(C:\QlikViewTraining\DeveloperII\Chapter05).
2 Open the Edit Script dialog and go to the Dimensions tab.
3 Find the Categories table and place the cursor after the last field of this
table.
4 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 )
The condition should be evaluated to be either true or false. If the condi-
tion is true, the then part will be processed. However, if the condition is
false, the else portion of the statement will be processed.
5 Save the script and Reload.
6 Look at the fields. You can now see that we have a new field named Cat-
egoryType.
Do: Aggregation
1 Open the QlikView file you have been working on in this chapter.
2 Open the Script Editor and place the cursor after the OrderDetails table
on the Orders tab.
3 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 combi-
nations 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.
41
QlikView Developer II | EXERCISE
Do: Concatenation
1 Open the Edit Script dialog in the QlikView file you have been working
on in this chapter.
2 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.
3 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 Click OK and Save the QlikView document.
5 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 auto-
matic concatenation.
You can avoid a number of potential problems with automatic concate-
nation by using the concatenate prefix on load statements that you know
should be concatenated.
42
QlikView Developer II | EXERCISE
6 Add the concatenate prefix to the new Employee LOAD statement, and
specify the Employees table.
This will always concatenate these two tables together, even if inadver-
tent 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 automati-
cally 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 fol-
lows:
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,
43
QlikView Developer II | EXERCISE
//[Hire Date],
//Year([Hire Date]) AS [HireYear],
//Office,
//Extension,
//[Reports To],
//[Year Salary]
//FROM Datasources\Employees_New.xls (biff, embedded
labels, table is [Employee$]);
8 Save the revised script and the QlikView document. Then Reload, and
verify the Employee data has not changed.
9 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?
CostOfGoodsSold;
We combine the applymap function with a calculation and create the
CostOfGoodsSold field directly in the preceding LOAD of the OrderDe-
tails 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
44
QlikView Developer II | EXERCISE
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.
4 We will use this functionality to create the Margin field.
5 Put the cursor after the OrderDetails label.
6 Create a preceding load by adding the following script.
LOAD
LineSalesAmount - CostOfGoodsSold AS
Margin,
*
;
7 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`;
45
QlikView Developer II | EXERCISE
46
QlikView Developer II | EXERCISE
Extra Credit
Do:
1 Launch QlikView and save a working copy of the AdditionalExer-
cises.qvw QlikView file in the extra cradit folder for this chapter
(C:\QlikViewTraining\DeveloperII\Chapter05\ExtraCredit_Chapter05).
2 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 Create a pivot table with CategoryType and CategoryName as dimen-
sions.
4 Create the following four expressions:
Sales Sum(LineSalesAmount)
COGS Sum (CostOfGoodsSold)
Margin Sum (Margin)
Margin % Sum (Margin)/ Sum (LineSalesAmount)
5 Format the table the way you want to.
Category- Catego- Sales COGS Margin Margin %
Type ryName
Clothing Baby Clothes $1004182.7 $865657.81 $138524.89 14%
0
Children's $672992.08 $556478.81 $116513.27 17%
Clothes
Men's $1103597.9 $965081.48 $138516.51 13%
Clothes 9
47
QlikView Developer II | EXERCISE
48
QlikView Designer II | 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
Set Analysis
QlikView has always been good at calculating aggregates for the current
selection of data. However, when you wanted to compare results for differ-
ent 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 aggrega-
tion 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 selec-
tions, previous selections, all data, etc.
The possibilities are endless and yet the syntax is fairly simple and straight-
forward.
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}.
49
QlikView Designer II | ADVANCED CALCULATIONS IN SHEET OBJECTS
Set Identifiers
There are two constants that can be used to denote record sets. They are 0
and 1. They represent an empty set and a full set of all the records in the
application, respectively.
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.
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:
50
QlikView Designer II | ADVANCED CALCULATIONS IN SHEET OBJECTS
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.
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 selec-
tion 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.
51
QlikView Designer II | ADVANCED CALCULATIONS IN SHEET OBJECTS
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 ele-
ments 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’.
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. <Prod-
uct = {"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 selec-
tion 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 exclu-
sion. If you want to force exclusion of specific field values, you will need to
use “~” in front of the field name.
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.
52
QlikView Designer II | 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).
53
QlikView Designer II | ADVANCED CALCULATIONS IN SHEET OBJECTS
Example:
$(=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
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 com-
bination of dimension values may generate more than one return value,
depending on underlying data structure. If the expression argument is pre-
ceded by the distinct qualifier, or if no qualifier is used at all, each combina-
tion 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 ))
54
QlikView Designer II | EXERCISE
Label -
=Only(Year)-1
Expression -
Sum({$<Year={$(=Only(Year)-1)}>} Sales)
Label -
=Only(Year) & ' vs ' & (Only(Year)-1)
Expression -
Sum({$<Year={$(=Only(Year))}>} Sales) -
Sum({$<Year={$(=Only(Year)-1)}>} Sales)
9 Click Finish
55
QlikView Designer II | EXERCISE
10 Save your QlikView file and then continue to edit the Annual Compari-
son straight table.
11 Set the Sort order to match the depiction, below, remembering that Cus-
tomer should be set to Text.
56
QlikView Designer II | EXERCISE
12 On the Visual Cues tab, make the negative values for the year-to-year
comparison red and the positive values green.
57
QlikView Designer II | EXERCISE
15 Type: Select a Year to compare with a previous year in the Custom Mes-
sage box and click OK.
58
QlikView Designer II | EXERCISE
Solution:
sum({$<CategoryName={'Babywear'}, Office={4}>} Sales)
sum({$<CategoryName={'Children´s wear'}, Office={4}>} Sales)
59
QlikView Designer II | EXERCISE
3 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
4 Next you need a count of customers to populate the # of order “buck-
ets” we created in the first step.
Count(distinct CustomerID)
5 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(Sales),OrderID)
gets you that number and adding the avg() gives you the requested aver-
age order amount
avg(aggr(sum(Sales),OrderID))
60
QlikView Developer II | 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
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.
When fact tables contain the same granularity of information and a com-
mon 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 dif-
ference between the sales amount and the budget amount.)
61
QlikView Developer II | SCRIPTING AND DATA MODELING CHALLENGES
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.
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
62
QlikView Developer II | SCRIPTING AND DATA MODELING CHALLENGES
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
application showing aged accounts. Another way of thinking of Class() is
that you can group your dimension values.
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.
IntervalMatch
The IntervalMatch function facilitates the mapping of dates to periods or
records to slowly changing dimensions. The implementation of Interval-
Match 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 function 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 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.
63
QlikView Developer II | SCRIPTING AND DATA MODELING CHALLENGES
In this exercise we will use IntervalMatch() to find the hours that an employee
is working on-site.
64
QlikView Developer II | EXERCISE
65
QlikView Developer II | EXERCISE
6 Comment the script from step 3 and uncomment the script on the Con-
catenate tab. Reload the application. Note the use of a RecSource field
to differentiate concatenated records. Note also the use of explicit refer-
ences 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.
7 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.
66
QlikView Developer II | EXERCISE
2 Select the Unit numbered 54543. Create a Table Box using all fields and
look at the counts.
3 Here you see that 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?
4 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.
5 Comment the information on the Previous tab, uncomment the script on
the Left Join tab, and reload the application. 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.
6 Your result should look like this:
67
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.
DateIsland:
LOAD DISTINCT
monthstart(OrderDate) AS DateIsland,
MonthYear AS DateMonthYear
RESIDENT
MasterCalendar;
68
QlikView Developer II | EXERCISE
5 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.
6 Now select various DateMonth values and you will see Sales change in
one column but not the other.
69
QlikView Developer II | EXERCISE
70
QlikView Developer II | EXERCISE
=class(num(OrderDate - $(vDate)),vWidth,'Dt')
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.
71
QlikView Developer II | EXERCISE
72
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(Line-
SalesAmount) with
if(Desc = 'Count',
num($(vMyAgg),'###0'),num($(vMyAgg),'$###.00'))
Note the test to determine how to format the numeric display (integers
or currency). You might try including the format string with the expres-
sion in the INLINE table as an additional field and then change the
expression accordingly.
5 Add two List Boxes with the columns Desc and Formula plus a Text Box
with =vMyAgg in the text area.
6 The result is that you can change your KPIs on the fly. Your result should
look as follows:
73
QlikView Developer II | EXERCISE
74
QlikView Developer II | EXERCISE
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 over-
head of a $Syn table. You also have the discrete records for all occur-
rences 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.
75
QlikView Developer II | EXERCISE
76
QlikView Developer II | EXERCISE
Extra Credit
Do: Additional AGGR Exercise
1 Open the file, Aggr.QVW in the Aggr folder and save a working copy of
the file.
2 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))
3 The average LineSalesAmount by Country, Company, Year and Quarter
with the expression below:
avg(aggr(sum(LineSalesAmount),Country,CompanyName,
Year, Quarter))
4 And, finally, the Total Sales
sum(LineSalesAmount)
5 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. Deter-
mine how many Orders were placed in each Month and how many
Months had Orders in them. Try to explain some of the resultant aver-
ages in each column.
77
QlikView Developer II | EXERCISE
78
QlikView Developer II | DATA MODEL OPTIMIZATION
Objectives
• Discuss performance tuning
• Explore the impacts of appropriate application design
• Introduce security concepts
• Review best practices
Performance Tuning
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 roll-
up version at a higher aggregate level?
Number of Columns
Be selective about what fields are included in the QlikView document
1 Focus on the larger fact tables first
2 But don’t ignore the dimension tables
Eliminate fields that are not currently being used
1 All fields might be used in the future but are not used now
2 The goal is to have a Lean QlikView document
79
QlikView Developer II | DATA MODEL OPTIMIZATION
2 Timestamps
Data Structure
Key Fields
Denormalization vs. Normalization
Normalization” Definition (Wikipedia):
Normalization splits up data to avoid redundancy (duplication) by mov-
ing 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.
Application Design
Avoid “Show Frequency”
Forcing Proper Object Display
1 Calculation Conditions
2 Show Conditional
Avoid too many active objects on the same sheet
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
80
QlikView Developer II | DATA MODEL OPTIMIZATION
If ( Condition(Text),…..)
Map Text to numeric e.g. by using autonumber and/or do the test in the
script
If ( Condition, Sum('FieldName')..)
Included here to emphasize the difference to above. This aggregation is com-
pletely contextual
81
QlikView Developer II | DATA MODEL OPTIMIZATION
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.
82
QlikView Developer II | 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.
83
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 Navigate to the course material folder for this chapter,
C:\QlikViewTraining\DeveloperII\Chapter08
2 Open the file in the QVDs folder called BaseLineDataExtraction.QVW
reload it and do File | Save As and save the file as BaseLineData-
Model.QVW in the QVDs folder.
3 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 CreateQVD-
fromBinary.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';
85
QlikView Developer II | EXERCISE
for i = 0 to NoOfTables() - 1
LET d = TableName(i);
store $(d) into $(vDataDir)\$(d).QVD;
next
LET j = nooftables();
do while j > 0
let d = TableName(0);
drop table $(d);
let j = nooftables();
loop
3 Reload and save the file and look in the Datasources\QVDs folder.
You should see:
4 Close any open QVWs. Create a new QVW and save it as MyIncremen-
talQVDApplication.QVW in the QVDs folder.
5 On the Main tab create a connection to the QWT.MDB data base.
6 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
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.
86
QlikView Developer II | EXERCISE
7 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;
8 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`;
87
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 informa-
tion 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.
88
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;
89
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
90
QlikView Developer II | EXERCISE
TempCalendar
ORDER BY
TempDate Asc;
DROP TABLE TempCalendar;
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.
91
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 applications 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 sub-
set of data based upon your current selection or dropping all data from
memory during development.
92
QlikView Developer II | DAILY AND TRANSACTION BALANCES
Objectives
• Introduce the need for balances
• Explore methods for handling them in QlikView
• Review sample files
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 trans-
action table based on the transactions themselves, such as warehouse trans-
actions in/out when there might not be transactions made made on all days
and keys.
With QlikView you can handle these situations.
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
93
QlikView Developer II | DAILY AND TRANSACTION BALANCES
*/
tmpResident:
Load Key,
Date(Date,'YYYYMMDD') as Date,
Saldo
FROM [datasources\data saldon.xls] (biff, embedded labels, table is
[Sheet1$])
;
tmpJoin:
Load Distinct
Key
Resident tmpResident
Order By Key
;
Join
Load
Date($(varStartDate)+(RecNo()),'YYYYMMDD') as Date
Autogenerate today()-$(varStartDate);
94
QlikView Developer II | DAILY AND TRANSACTION BALANCES
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;
95
QlikView Developer II | DAILY AND TRANSACTION BALANCES
96
QlikView Developer II | 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
97
QlikView Developer II | QLIKVIEW SECURITY
10 QLIKVIEW SECURITY
Objectives
• Understand the components of QlikView document security
• Discuss access control and restrictions
• Practice implementing QlikView Section Access
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 possi-
ble to include access levels in the load script.
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 (subject to product limitations), whereas a person with USER
privileges has restricted access. A user of a QlikView client will be automati-
cally 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”.
99
QlikView Developer II | QLIKVIEW SECURITY
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 APPLI-
CATION There are several protected field names in the access control data-
base, 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 reduc-
tion or for administration, but QlikView does not use the extra fields for
limiting access to the document. None, all or any combination of the secu-
rity 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 privi-
lege 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
100
QlikView Developer II | QLIKVIEW SECURITY
101
QlikView Developer II | QLIKVIEW SECURITY
administrator to control user access, including those that start with a binary
statement.
Section Access;
LOAD * INLINE [
ACCESS, USERID, PASSWORD
ADMIN, NEWDBA, ABC
];
Section Application;
.....
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 nor-
mal 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.
102
QlikView Developer II | QLIKVIEW SECURITY
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.
103
QlikView Developer II | EXERCISE
Exercise
Do: Setting up Access Security on a QlikView file
1 Launch QlikView and save a working copy of the QlikView file in the
working directory for this chapter (C:\QlikViewTraining\Develo-
perII\Chapter10)
2 Once again, be sure to save the document under another Name. e.g.
QlikViewTraining_wSecurity.
3 Open the Script Editor.
4 Go to the File menu and Edit Hidden Script…
5 Enter the password hidden and confirm the password.
6 Click on the User Access… button to get to the Access Restriction
Table Wizard.
7 Select Basic User Access Table so the ACCESS, USERID and PASS-
WORD are checked.
8 Click OK and add the following lines to the table.
9 Click OK. The wizard should have created the following script state-
ment.
Section Access;
LOAD * INLINE [
ACCESS, USERID, PASSWORD
ADMIN, ADMIN, ADMIN
USER, USER, USER
105
QlikView Developer II | EXERCISE
];
Section Application;
10 Name this table Access01.
Do:
1 Exit QlikView and open your newly named document again. You will
now see the following dialog box where you can enter your user ID and
password.
106
QlikView Developer II | EXERCISE
Do:
1 Make sure you are logged in to the QlikView document as Admin.
2 Go to the Settings menu and Document properties.
3 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.
4 Make sure to check the Admin Override Security check box so that the
admin always has permissions to do everything.
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.
107
QlikView Developer II | EXERCISE
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 edi-
tor, 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 com-
puters (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 Open Notepad, or a similar text editor
3 Create a two-column table with the fields COMPUTER and SERIAL.
Include your own serial number as a field value; you will find this num-
ber under the About QlikView menu in QlikView. An example is shown
below.
COMPUTER SERIAL
Course1 2300 2394 7111 8000
Course2 2300 2394 7111 8001
4 Save this file as Access02.txt.
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, note that we are adding restrictions to existing USERIDs (USER),
and not replacing current restrictions.
Open the load script and click on the Table Files button. Load the newly
created table Access02.txt after the inline table, and prior to the SEC-
TION APPLICATION statement, as shown below.
Access02:
Load
COMPUTER,
SERIAL
FROM Datasources\Access02.txt
(ansi, txt, delimiter is '\t', embedded
108
QlikView Developer II | EXERCISE
labels);
Section Application;
5 Save and Reload the document.
6 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.
109
QlikView Developer II | EXERCISE
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.
Do:
1 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.
2 Now, comment the previously loaded INLINE tables so that they will not
interfere with our new SECTION ACCESS tables.
3 The first text file to load is SalesSecurity.txt, located in the Datasources
directory. Label this logical table as Access01.
4 Then, add the SECTION APPLICATION statement.
110
QlikView Developer II | EXERCISE
5 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 Save and Reload the document.
7 Go to the Settings menu and to Document Properties.
8 Select the Opening tab and check Initial Data Reduction Based on Sec-
tion Access. Make sure to uncheck Strict Exclusion. Also, check Pro-
hibit Binary Load.
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 check-
boxes 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 Lind-
wall 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.
111
QlikView Developer II | EXERCISE
112
QlikView Developer II | 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 gen-
erate QlikView load script syntax
So far we have focused on loading data using the different options on the
Data page of the script editor.
Custom Data
The Custom Data page contains commands for getting 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 accord-
ing 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.
113
QlikView Developer II | ADVANCED DATABASE CONNECTIVITY
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.
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 inte-
gration.
QlikView offers:
• Connector
• ScriptBuilder
• ExtractSAP
• BW Cube QVD Generator
• Templates / Demo applications
114
QlikView Developer II | ADVANCED DATABASE CONNECTIVITY
115
QlikView Developer II | BUSINESS CASE WORKSHOP
Objective
• Build a working QlikView analysis application based upon the
requirements
• Review it with your instructor and classmates
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 get-
ting a better understanding of their Sales and Margin performance across
their business.
They have asked you to develop a Sales Analytics QlikView application for
them.
The application will be used by their top executives, their product managers
and also their salespeople.
117
QlikView Developer II | EXERCISE
Requirements
ACME has listed their requirements for the solution as follows:
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 ana-
lyze 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.
Data Structure
The following tables outline information about ACME’s source data to be
used to complete the QVW application in support of the business require-
ments.
SALESDETAILS.QVD
This table contains the company sales and order transactions.
119
QlikView Developer II | EXERCISE
120
QlikView Developer II | EXERCISE
CUSTOMERS.QVD
This table contains Customer information.
.
121
QlikView Developer II | EXERCISE
CUSTOMERADDRESS.QVD
This table contains the address information for the customer.
STATEDESCRIPTION.QVD
This table contains the state descriptions.
REGION.QVD
This table contains the Region descriptions.
DIVISION.QVD
This table contains the Division descriptions.
122
QlikView Developer II | EXERCISE
SALESREP.QVD
This table contains information about SalesReps.
ITEMBRANCH.QVD
This table contains Item Branch information. Main purpose is to link to the
ItemMaster table
123
QlikView Developer II | EXERCISE
PRODUCTGROUP.TXT
This table contains the Product group descriptions.
.
PRODUCTLINE .TXT
This table contains the Product Line descriptions.
PRODUCTSUBGROUP .TXT
This table contains the Product subgroup descriptions.
.
124