QlikTip #25: How do you organize your QlikView projects in your file system?

In the last three years I have quite often changed my standard concept of structuring my (customers’) QlikView projects in the file system. But for about 1 1/2 years “my” concept seems to be stable :-) :

My favourite way of organizing the QlikView projects in the file system

Some hints:

  • In 0_Scripts all included scripts are saved
  • 1_Resources includes all Excel-files, settings files and other resources (eg. images, pictures, CSV-files, …) to be used within the load-script.
  • Under 2_QvdGenerators I place all my QlikView files generating QVD-files. All the QVD-files are placed within the subfolder “QVD” (and sometimes certainly subfolders of QVD)
  • In 3_DataModell I save my QlikView-file generating the datamodell, putting all QVD-files together to a nice datamodell.
  • In 4_Application the final result of my application is located, just loading the data modell with a BINARY LOAD and adding the user-interface to the available data.

Important notes and advantages of this approach

  • This structure does only work, if you have relative paths enabled. If doing so you can easily copy the development solution to the production folder or even to the production-system on another server.
  • Obviously this is just a standard structure, in smaller projects some of the folders would not be used, in larger projects I would add some sub-folders, but in general the structure remains the same …
  • When working in large projects (e.g. applications with 50 GB) you can easily work with a smaller datamodell (only a subset of the final dataset) and create your user interface without having to save each time a 50GB large file … for doing so just change the BINARY LOAD in your development environment and change it again to the large file in PRODUCTION ENVIRONMENT …
  • You can easily put this structure to your production environment just via copy&paste

How do you structure your QlikView projects?

I am interested in your personal way of organizing the projects.
Please use the comment functionality below to post your ideas.

Bookmark and Share

QlikTip #3: Check whether a field exists or not (translated and improved)

If you want to load all fields in a table or a QVD file in loading scripts (so typically SELECT * FROM... scenarios), it is often necessary to know whether a field (within a table) exists or not.

The following code example demonstrates how this can be achieved:

Customers:
LOAD * INLINE [
    CustomerId, PostalCode, City
    1, 1010, Vienna
    2, 8020, Graz
    3, 6020, Innsbruck
    4, 9020, Klagenfurt
];

// Now we would like to know if the field '<code>Country</code>' exists in the table '<code>Customers</code>'
LET X = FieldNumber('Country','Customers');

if $(X) = 0 then
    // field does not exist
    TRACE field 'country' does not exist;
        /*
        add your code here ...
        */
else
    // field exists
    TRACE field 'country' exists;
         /*
        add your code here ...
        */
end if

Explanation:
The function FieldNumber returns 0 if a field does not exist.

Simplification for better reuse:

By using a “user defined function” (UDF) we can simplify the code above for easier reuse:

// ******************************************************************
// Checks if a field exists.
// ~
// Parameters:
//	1st parameter: Name of the field
//	2nd parameter: Name of the table
// Usage:
// 	LET a = $(udfFieldExists('CountryId','Countries'));
//	TRACE field exists: $(a);
// Return value:
//	Will return true (-1) if the field exists, otherwise false (0).
// ******************************************************************
SET udfFieldExists = (FieldNumber($1,$2) <> 0);

// Now call the function as follows:
LET a = $(udfFieldExists('Country','Customers'));
LET b = $(udfFieldExists('CustomerId','Customers'));
TRACE udf-result (Country): $(a);
TRACE udf-result (CustomerId): $(b);

The original german version of this article can be found here.

Bookmark and Share

Tags: , , ,

QlikTip #24: Using line-styles in Line-Charts to differentiate between actual and planning figures

Some months ago I was asked how one could change the line style within a “Line Chart” for distinguishing between actual and planning figures.

The desired result:

The result: Different line-styles within a single chart

How can we manage that in QlikView?

First I added a field named IsForecast in my demo-application to differentiate between actual and planning figures:

LOAD * INLINE [
    Customer, Sales, IsForecast, Period
    CustomerA, 20, 0, 1
    CustomerA, 30, 1, 2
    CustomerA, 35, 1, 3
    CustomerA, 38, 1, 4
    CustomerA, 45, 1, 5
    CustomerA, 46, 1, 6
    CustomerA, 43, 1, 7
    CustomerA, 69, 1, 8
];

As you can see above both, actual and planning figures are stored in the field “Sales”.

Now just create your chart as usually, using “Customer” as dimension and “sum(Sales)” as expression.

And now the clue:
Go to “Line Styles” in the properties of your expression and add the following expression:

=if(IsForecast = -1, '<S3>', '<S1>')

Attribute expressions for setting the line-style

Just a little explanation:

You can define the line style by using the following options:

  • <S1> – continous (default)
  • <S2> – dashed
  • <S3> – dotted
  • <S4> – dashed/dotted

Furthermore you could use the tag <Wn>, where n defines the width of the line, e.g. <W2.5>.

Note:
It is really worth having a look at the chapter “Line Style” or in general “Attribute expressions” in the QlikView Reference Manual.

Bookmark and Share

Tags: , , ,

QlikTip #23: Deleting fields within a load-script dynamically

Some days ago I was asked how one could delete fields dynamically within/after a load-script in QlikView based on the name of the field/column.

So all columns for example with a prefix “F_” should be deleted after loading all tables from a database.

My first response was, that the “Table functions” (please have a look at the help-files of QlikView) could be used and I answered with the following pseudo-code using the builtin-QV-functions NoOfTables, TableName, NoOfFields, FieldName:

// ******************************************************************
// Note: this is just a pseudo-code …
// Note: this does not work, please finish reading this blog-post to
// the end for getting the correct code
// ******************************************************************
FOR t = 0 TO NoOfTables() -1

    LET vTableName = TableName(t);

    // Loop through all fields/columns within the table
    FOR vColumnCounter = 1 TO NoOfFields(vTableName)

        LET vFieldName = FieldName(vColumnCounter, vTableName);	

        // If the prefix matches the beginning of the fieldname => drop the field
        if (left(vFieldName,2) = ‘F_’) then
            DROP FIELD $(vFieldName) FROM $(vTableName);
        end if

    NEXT
NEXT

During the dog-walk some hours later, I realized that this would not work in some/most cases (if we have more than one field/column matching our prefix per table):

  • After deleting a column, the index of all columns with a higher index than the deleted one would change (decrease by one)
  • So maybe we would not fetch all appropriate fields/columns

But how can we change the script to get it to work?

The answer is quite easy:

  • We have to loop through all tables and fields/columns first (as demonstrated in the pseudo-code above)
  • While looping we would have to save the information which columns should be dropped and
  • Finally we would drop the “saved” columns

The first approach which came in my mind was just to save the information which tables should be dropped in a temporary-table, and this works nice:

// ******************************************************************
// Procedure for deleting all fields matching a given prefix.
// ~~
// Usage:
// Call DeleteFieldsByPrefix('F_') would delete all fields starting
// with "F_" within the whole QlikView-application
//
// Further information:
//     http://www.qlikblog.at/?p=662
// ******************************************************************
Sub DeleteFieldsByPrefix(prefix)

// Loop through all tables
FOR vTableCounter = 0 TO NoOfTables() -1

	// fetch the tableName
	LET vTableName = TableName(vTableCounter);

	// Loop through all fields/columns within the table
	LET vNumOfFields = NoOfFields(vTableName);
	FOR vColumnCounter = 1 TO vNumOfFields

		LET vFieldName = FieldName(vColumnCounter, vTableName);					

		// If the prefix matches the beginning of the fieldName
		// we "save" the TableName and FieldName for later
		// dropping ...
		if (left(vFieldName,len(prefix)) = prefix) then
			Temp_TableToDrop:
			LOAD
				'$(vTableName)' as TableName,
				'$(vFieldName)' as FieldName
			AUTOGENERATE (1);
		end if

	NEXT // fields looping

NEXT // table looping

FOR i = 0 TO NoOfRows('Temp_TableToDrop')-1

	LET vTableToDropFrom = peek('TableName',$(i),'Temp_TableToDrop');
	LET vFieldToDrop = peek('FieldName',$(i),'Temp_TableToDrop');

	TRACE Dropping field $(vFieldToDrop) from $(vTableToDropFrom) ...;
	DROP FIELD [$(vFieldToDrop)] FROM [$(vTableToDropFrom)];

NEXT

// Finally delete the temporary table
DROP TABLE Temp_TableToDrop;

// Reset/drop variables
LET i = null();
LET vTableName = null();
LET vTableCounter = null();
LET vColumnCounter = null();
LET vNumOfFields = null();
LET vFieldName = null();
LET vTableToDropFrom = null();
LET vFieldToDrop = null();

End Sub
// __________________________________________________________________
Bookmark and Share

Tags: , , , , , ,

QlikTip #22: Restarting/Stopping/Starting services in QlikView 9

Even if already published on another Qlikview related blog I just wanted to have this here because I am using it quite often.

For starting/stopping/restarting the QlikView Windows-services of QlikView server in version 9 I have prepared three batch-scripts which I call on demand:

Restarting all QlikView related Windows-services

@echo off
REM -------------------------------------------------------
REM - File: QlikViewServer9_Restart.bat
REM - Description: Restart's QlikView Services (v9)
REM - Author: Stefan WALTHER
REM -------------------------------------------------------
echo Restarting QlikView Services
echo ======================================================

net stop "QlikView WebServer"
net stop "QlikViewServer"
net stop "QlikView Publisher Command Center Service"
net stop "Qlikview Management Service"
net stop "QlikView Distribution Service"
net stop "QlikView Directory Service Connector"

net start "QlikView WebServer"
net start "QlikViewServer"
net start "QlikView Publisher Command Center Service"
net start "Qlikview Management Service"
net start "QlikView Distribution Service"
net start "QlikView Directory Service Connector"

echo ======================================================
echo QlikView restarted

REM pause

(Just) stopping the QV Windows-services:

@echo off
REM -------------------------------------------------------
REM - File: QlikViewServer9_Stop.bat
REM - Description: Stop all QlikView related services (v9)
REM - Author: Stefan WALTHER
REM -------------------------------------------------------
echo Stop QlikView Services
echo ======================================================

net stop "QlikView WebServer"
net stop "QlikViewServer"
net stop "QlikView Publisher Command Center Service"
net stop "Qlikview Management Service"
net stop "QlikView Distribution Service"
net stop "QlikView Directory Service Connector"

echo ======================================================
echo All QlikView related services have been stopped ...

REM pause

(Just) starting the QV Windows-services:

@echo off
REM -------------------------------------------------------
REM - File: QlikViewServer9_Start.bat
REM - Description: Starts all QlikView related services (v9)
REM - Author: Stefan WALTHER
REM -------------------------------------------------------
echo Beginning to start QlikView Services
echo ======================================================

net start "QlikView WebServer"
net start "QlikViewServer"
net start "QlikView Publisher Command Center Service"
net start "Qlikview Management Service"
net start "QlikView Distribution Service"
net start "QlikView Directory Service Connector"

echo ======================================================
echo All QlikView related services have been started ...

REM pause




Bookmark and Share

Tags: , , , , , ,

Nice Read #1: Gartner’s Magic Quadrants 2009/2010 and Qlikview

Gilles from www.quickqlearqool.nl has written a nice review of the new Gartner’s Magic Quadrant 2010:

Gartners Magic Quadrant 2009

Gartners Magic Quadrant 2010

The most interesting fact in Gartner’s analysis is that QlikTech/QlikView is not a visionary anymore!
Some quotes from Gilles article:

THERE ARE NO VISIONAIRIES ANYMORE!! Even Qlikview isn’t a visionary anymore.

… the explanation for Qlikview not being part of the visionaries anymore is quite understandable. Other parties are copying the unique selling points of Qlikview. Microsoft introduces PowerPivot, SAP created an easy entry proposition with Business Objects Explorer, and Cognos came with Express, all focusing at business users, some of them with in-memory techniques, enabling business users to what Gartner calls “Surf and Safe”. That “proves” that Qlikview is on the right track with the big vendors copying Qlikview’s approach.

One major issue that Gartner is pointing out in its analysis is that Qlikview could have had its momentum. Qlikview is/has been very successful with in-memory technology and 64-bit computing enabling scalability of Qlikviews model.

To summarize what Gartner says about Qlikview’s strengths, we can be very short: It is easier, simpler, cheaper, faster, quicker to deploy and is more feature rich than the competition.

To conclude this post: Qlikview is still going strong and has a very good product (and marketing), but Qlikview needs to show some vision on the short and medium term. Vision is not about incrementally adding new functionality, but more about how to service those large enterprise deployments. Qlikview has to do some serious work on an enterprise wide semantic data layer and better tools to manage large deployments.

Bookmark and Share

Tags: ,