Unlock a world of possibilities! Login now and discover the exclusive benefits awaiting you.
This forum is where any logged-in member can create a knowledge article.
Aside from filtering data records with Section Access, I'm usually requested to filter the objects and sheets to which users have access. To be honest, I don't like to filter individual objects since this implies a lot of mainteinance and a more complex Section Access table. So I usually describe the scenario to the IT people and Key users and they always ( so far ) decide to go for the Sheets-Security option. Which in my opinion is the best alternative because it's more common to hide a complete block of information/analysis from a user than just a single KPI.
I've seen some examples like this before in the Community, however everything I've found its exemplified based on the USERID field. So, when I tried to use those examples I ran into some common errors when dealing with Section Access, and now that I've solved them I want to share a small example about how to go when using NTNAME.
Also, I want to note that there are some easier/faster alternatives to this approach. For instance you may use the MATCH() method described in this thread: Secured sheets
However if you're already using Section Access to filter data, you have too many users and/or sheets to use the MATCH() method, or if you just need to handle those privileges outside of the .qvw ( e.g. a user will maintain an excel file), you can use/reuse Section Access to accomplish this requirement.
In my example I use INLINE loads in order to allow other people to reload the app, however you could load all tables, including the SECTION ACCESS table, from xls or qvd files.
So, in order to test this example you have to do the following:
Go to the following link to get the example file:
Sheets Security with Section Access File
I hope this example is useful and don't hesitate to ask if you have any doubt regarding it.
A question that gets asked regularly is how to calculate a rolling measure over a period of N-months (or weeks or days). For example a 12-month rolling total or a 4-week rolling average. There are several ways to do this. But these approaches have some limitations that need to be kept in mind. I'll try to explain these approaches and some of their limitations.
First let's load some sample data. The SalesData table below will contain sales amount values for twelve consecutive months.
SalesData:
load * inline [
Month, Amount
1,6
2,4
3,7
4,3
5,4
6,9
7,5
8,7
9,8
10,6
11,9
12,7
];
This is a very simple table with little data, but this enough for demonstration purposes.
Once this data is loaded it's possible to create a straight table chart object to display the amount per month and a running total. As expected Month is used as dimension. The expression sum(Amount) will display the amount per month. Now let's add an expression to calculate a running total over three month periods.
This can be done in two ways. The first uses the Accumulation option for expressions. The same expression sum(Amount) is used, but now the Accumulation option is set to 3 Steps Back:
The second option uses the rangesum function. That expression looks like this:
rangesum(above(sum(Amount),0,3))
This sums the Amount value on current row and on the previous two rows. The resulting straight table looks like this:
This looks good. The rolling 3 months amount is calculated correctly. But what happens if a selection of months is made?
The rolling 3 month amount for month 4 is now 3 instead of 14. This is because month 1,2 and 3 are no longer included in the calculation for the rolling 3 month total.
The accumulation option has another issue. It only works when only one dimension is used in the straight table. The rangesum expression can be modified so it can calculate across dimension borders, but the accumulation option can't. The modified rangesum expression adds the total keyword to the above() function:
rangesum(above(total sum(Amount),0,3))
This goes some way to doing what we want, but the issue of displaying the wrong rolling 3 month amount for month 4 isn't solved yet. Contrary to what I first thought there is a solution for this, as Henric pointed out to me in the comments below. By combining the rangesum with the aggr function it's possible to calculate the correct rolling 3 month amounts for each month. The expression needed for that looks like this:
sum(aggr(rangesum(above(total sum({<Month=>}Amount),0,3)),Month))
Read Elif's blog post Accumulative Sums for a more complete explanation.
How about set analysis expressions?
This expression should calculate the sum of amount for the three month period:
sum({<Month={'>=$(=only(Month)-2)<=$(=only(Month))'}>}Amount)
But notice the only() function. This requires that only one month value is selected. After selecting month 4 the result looks like this:
This shows the selected month, but also the two previous months. And the values are not accumulated.
Ok, but what about the max function instead of only?
sum({<Month={'>=$(=max(Month)-2)<=$(=max(Month))'}>}Amount)
That gives a different result, but still not what we're looking for:
Now only the last three months are shown and again the values are not accumulated.
The 'problem' is that the set is calculated once for the entire chart, not per row. This means that it's not possible here to use Month both as a dimension and in the set modifier in the expression.
There's still an option left to discuss: AsOf tables.
The AsOf table links a period with all the periods in the rolling period. In this example months are used, but it can be applied to any type of period like hours, days or weeks.
For the three month periods needed for a rolling 3 month total this means a month should be linked to itself, the previous month and the month before the previous month. The only exceptions are the first month, which is itself the rolling 3 month period, and the second month that together with the first month is its rolling 3 month period. There are no months before the first month so the first two months cannot run over 3 months.
The AsOf table needed for the rolling 3 month calculations looks like this:
This table can be created like this:
AsOfMonth:
load
Month as Month_AsOf,
Month + 1 - IterNo() as Month
Resident SalesData
while IterNo() <= 3;
right join load Month Resident SalesData;
What this does is create three records for every month using the while statement. But that also creates three records for month 1 and 2. This would create a month 0 and a month -1. The right join is used to remove those incorrect month values.
Now that the AsOfMonth table is created the Month_AsOf field can be used instead of the Month field in the straight table. The expression for the straigh table is simply sum(Amount).
The straight table now shows the correct rolling 3 month total for month 4.
This can be expanded a little so not only the rolling 3 month can be shown, but also the amount for the month itself. To achieve this the AsOf table is modified by adding a field to label the type of period. And records are added to the table so each Month_AsOf value is linked to the matching Month value:
AsOfMonth:
load 'Current' as Type,
Month as Month_AsOf,
Month as Month
Resident SalesData;
Concatenate (AsOfMonth)
load 'Rolling 3' as Type,
Month as Month_AsOf,
Month + 1 - IterNo() as Month
Resident SalesData
while IterNo() <= 3;
right join load Month Resident SalesData;
There are now two types of periods available: Current and Rolling 3. Additional period types can be added for example for Rolling 6, Rolling 12 month and Year-to-Date periods. You can find examples of these types in the attached AsOf Table Examples.qvw document.
The period type can be used in the chart expressions to calculate the amount for the wanted period:
Current amount: sum({<Type={'Current'}>}Amount)
Rolling 3 month amount: sum({<Type={'Rolling 3'}>}Amount)
Concluding, there are two solutions that do what we want:
1. The rangesum-aggr combination
2. The AsOf table
The first has the advantage that no changes to the data model are needed. It's also possible to dynamically change the period to aggregate over by using a variable instead of a hardcoded number of periods. A disadvantage is that that it's a somewhat complicated expression that also comes with a performance cost.
The AsOf needs changes in the data model to create the AsOf table and fill it with the necessary records. The advantage is that it likely performs better on large data sets. It's also quite versatile since you can add several sets of records to meet different scenario's. The expressions you end up with in the charts are also less complicated. That said, it will likely take you some time to fully understand the AsOf table concept and realize all the places where you can put it to good use.
In the end you'll have to decide for yourself which solution is appropriate in your situation. With regards to the performance of one or the other solution, you will simply have to test to discover if the performance is acceptable. But of course such testing is already part of your development process, right?
I'd like to thank John Witherspoon for introducing me to the AsOf tables concept and Henric for pointing out the solution using the rangesum function in combination with the aggr function.
A while ago, I conducted an internal research project with my colleagues @AlaneMiguelis, and Dr. @priscilarubim, aiming to validate the accuracy of a Two-Sample T-Test in Qlik by comparing it with the medical research gold standard: R. While we explored various hypothesis testing methods, we prioritized formalizing our findings on the T-Test. Recently, we decided to make this document available to the whole community.
The focus of our project was to assess whether the statistical results produced by Qlik matched those generated by R, particularly for the Two-Sample T-Test. Our methodology involved rigorous data analysis and repeated testing to ensure the reliability and consistency of our results. Through our detailed comparative analysis, we aimed to provide insights into the robustness of Qlik’s statistical capabilities. The code and dataset is available in a Git repository for those who want to reproduce the study.
Here is the abstract of our study. The full document can be accessed through the link at the end of this post.
ABSTRACT
Objective
The statistical determination of a large or small difference between two groups is not based on an absolute standard, but is rather an evaluation of the probability of an event.1,2 In the field of medical research, it is common to use statistical software for descriptive statistics as well as to perform statistical tests.3 However, most software provides ready-to-use functions, and the researchers have almost no information as to how those statistical tests are calculated inside those functions. This article evaluates the accuracy of two-sample Student’s t-test using Qlik analytics software. The gold standard used for this evaluation is the set of standard t-test functions available in R software, a widely used, robust, and reliable statistical software.5–7
Materials and Methods
The tests performed in this evaluation used a subset of Framingham heart study data. The dataset contains data on 4,434 anonymous participants, collected in three periods apart from each other by 6 years from 1956 to 1968. Five t-tests with 2 scenarios each were performed in Qlik analytics and in R and the results compared.
Results
In general, the results for multiple statistics obtained in Qlik analytics match the ones found in R for multiple scenarios: small and large sample sizes, small and large p-values, assuming and not assuming equal variance.
Discussion
Although Qlik analytics matches all statistics for t-test found in R, the p-value only matches up to four decimal points, which is concluded to be enough for testing hypothesis since the conventional levels of significance do not go lower than 0.1.
Conclusion
This research concluded that Qlik analytics can be used for two-sample t-tests in multiple scenarios.
Keywords: Qlik, t-test, r language, Framingham.
Link for the full article: Comparing Qlik Analytics and R Software for Accurate Two-Sample T-Tests Research Paper (ipc-global.com)
QlikView > Qlik Sense > Qlik Cloud...
Replatform is challenging and sometimes, different platforms have to coexist and interact to each other.
In this article I will show how can you call QlikView Tasks from Qlik Sense - and potentially from Qlik Cloud - using PowerShell Scripts.
# Open Powershell as Admin and Execute the following to allow Powershell Scripts execution
# Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
# Set-ExecutionPolicy Unrestricted
The PowerShell script is simple as it shows below. It requires two parameters:
param (
[Parameter(Mandatory=$true)]
[string]$QlikViewQMCServiceUrl,
[Parameter(Mandatory=$true)]
[string]$TaskID
)
$service = New-WebServiceProxy -Uri $QlikViewQMCServiceUrl -Namespace QlikViewServer -UseDefaultCredential
$serviceKey = $service.GetTimeLimitedServiceKey()
$hdrs = @{}
$hdrs.Add("SOAPACTION","http://ws.qliktech.com/QMS/12/2/IQMS2/RunTask")
$hdrs.Add("Content-Type", "text/xml;charset=utf-8")
$hdrs.Add('X-Service-Key',$serviceKey)
$body = @{}
$body = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<RunTask xmlns="http://ws.qliktech.com/QMS/12/2/">
<taskID>' + $TaskID + '</taskID>
</RunTask>
</s:Body>
</s:Envelope>'
$res = Invoke-WebRequest -Uri $QlikViewQMCServiceUrl -Method Post -Body $body -UseDefaultCredential -Headers $hdrs
We can Run the PowerShell Script in multiple ways:
For now, we'll run it through Qlik Sense Load Script:
EXECUTE powershell.exe -ExecutionPolicy Bypass -File "$(vTempPowerShellScriptFile)" -QlikViewQMCServiceUrl "$(vTempQlikViewQMCServiceUrl)" -TaskID "$(vRunningTask)";
To call the EXECUTE statement in the Load Script you must enable the Legacy Mode in your Qlik Sense Server.
That is it! Now from Qlik Sense Server we can call QlikView Tasks with minimum changes in our server environments.
The PowerShell Script in my example contains only the core of its functionality. I strongly recommend including log messages and error handling through try/catch/finally blocks.
I haven't tested this but here is my theory:
That should do the magic. Please let me know if you have tried this and if it has worked.
QUESTION:
How to display or hide one or more internal sheets of a one o more Qlik Sense App.
ANSWER:
For convenience, I use a simple INLINE table that reproduces 2 fields necessary for dynamic matching when opening the sheet: USER ID and SHEET ID
SA_SHEET:
LOAD * INLINE [
UTENTE,SHEET
55ad8d29ed671d80ecac0d1b4594546e8f88d730d23a63b4da55f51ed77f4ffb,8f3e7e83-00ef-4c34-9458-54ba3840c123
55ad8d29ed671d80ecac0d1b4594546e8f88d730d23a63b4da55f51ed77f4ffa,0af346e4-b0b3-4a20-b2ee-bf9e869412e2
];
// the green color is the correct record to match (ID USER and ID SHEET)
Add 3 variables:
the first in the load script;
LET USER = SUBFIELD(OSUSER(),'|',-1); // Extract the User ID session login ( one value only)
the second in variable editor:
ObjectId('sheet') // One value for each sheet in app
the third variable in the visualization condition of sheet properties:
=index(concat( {< UTENTE = {"$(USER)"} >} distinct SHEET,' '),$(vSHEET_ID))
the result will be that when the user ID and the sheet ID are equal to the user of the current session who opens the sheet within the App, the formula returns a value greater than zero, enabling the sheet.
These variables can be inserted more conveniently in an TXT file and loaded with an INCLUDE instruction so as to be able to quickly insert the code into all the published APPs (maximum efficiency) as for the INLINE table which can be included in the loading loads by hooking it if present , to that of ECTION acces for data profiling. Seeing is believing.
Good work
Valerio Fatatis wrote
Long time ago I have developed a vbscript application to open qlikview, reduce some data according salesman filter, export the sales pivot table to excel and send an email with the excel sheet attached to the salesman using the blat.exe application. The other day i was wondering if the same job could be executed using python. So after two minutes i was googling in search of some code snippets to easily make the python script. After half an hour I was quite disappointed to not found anything already made so I opened Pycharm and started to make the basic code: a class to make an instance of qlikview, open the document, export the table, close the document, close the qlikview app.
Here the code tested on python 3.7:
from win32com.client import Dispatch
import pythoncom
class QlikView:
def __init__(self):
self.app = Dispatch('QlikTech.QlikView')
def OpenDoc(self, docname):
doc = self.app.OpenDoc(docname)
return doc
def CloseDoc(self, doc):
doc.CloseDoc()
def ManageDocument():
docname = "c:\EXAMPLE.qvw"
q = QlikView()
version = q.app.QvVersion()
print(version)
doc = q.OpenDoc(docname)
chart = doc.GetSheetObject("exampletable")
chart.ExportBiff("c:\exampletable.xls"
q.CloseDoc(doc)
q.app.Quit()
if __name__ == '__main__':
ManageDocument()
This is the code that I've written at today , for sure i will go on and rewrite all the app to send report attached in emails, if someone need more information, just send me a message.
How could I make sure that certain data are only for certain users available?
The answer is SECTION ACCESS. Section access is a connection between an authorization table (commonly placed in a hidden script and/or outsourced in an include-variable) and the application data (most to a dimension table).
Further you need to enable section access within the document properties in tab open and especially to enable the strict exclusion is important then without this is section access more a comfortable usability function to avoid confusing by the users which needs only a small data-area from the application but not more suitable for real confidential data.
Introduction to Section Access
Data Reduction – Yes, but How?
Section Access: Strict Exclusion
QlikView Section Access Examples
Data Reduction Using Multiple Fields
Section Access (Data Reduction) using Active Directory
In addition to these there are more complex restrictions possible but before you build one think on alternatives like Document chaining whereby those applications then have a specialized and simpler section access.
Basics for complex authorization
Authorization using a Hierarchy
Restrictions based on section access could be applied on sheets and objects.
Sheets Security with Section Access
Sheets Security with Section Access File
Sometimes there is a need to mask or de-identify data for certain users, for this see: Mask or de-identify data for certain users using Section Access.
At least the most important remark: before thinking on section access makes one or more BACKUP's from your applications then there aren't any go backs by mistakes! One exception (which don't nullified the suggestion of having Backup's) could you find here: Bypassing QlikView Section Access – Infinity Insight Blog.
There is some content-overlapping within the above used links but I think the complement to each other is useful and of course you will find many more interesting postings here within the qlik community to these topic - the notes here are a good starting point to go further.
Have fun!
The attached file SectionAccess.zip contains several example documents that show how Section Access can be used to restrict access to specific users and to specific data.
This is not a guide on how to use Section Access, but instead shows some of the common errors and how to avoid them.
An excellent guide to Section Access can be found here http://community.qlik.com/docs/DOC-1853
Marcus_Sommer has accumulated a comprehensive list of Section Access Resources in this document Section Access
These examples will require a licenced copy of QlikView to open them, so they not suitable for users with QlikView Personal Edition.
The example documents will ask for a username and password to open them and set the Section Access permissions. The following usernames and passwords can be used to open the documents and see the different functionality with Section Access. When changing from one user to another, you must close QlikView before you can open a document as another user.
UserID, Password
ADMIN, ADMIN
JOHN, JOHN
MARY, MARY
PETER, PETER
SIMON, SIMON
You can view the load script to see how the Section Access and data is configured.
Section Access Example 1
This document attempt to restrict access to a list of named users, but this fails as the section access field names are not set as UPPERCASE in the script.
Section Access Example 2
The app is now correct and prompts for a username and password before users can access the data.
Examples 1 & 2 use the Basic section access data from SectionAccess.xlsx
Access, UserID, Password
USER, USER, USER
ADMIN, ADMIN, ADMIN
USER, JOHN, JOHN
USER, MARY, MARY
USER, PETER, PETER
ADMIN, SIMON, SIMON
Section Access Example 3
The data is restricted so users can only access the Cost Centre data as listed in the Cost Centre column in Section Access.
Access, UserID, Password, CostCentre
USER, USER, USER, *
ADMIN, ADMIN, ADMIN, *
USER, JOHN, JOHN, A
USER, MARY, MARY, B
USER, PETER, PETER, C
ADMIN, SIMON, SIMON, A
Section Access Example 4
This adds extra DUMMY rows to the section access table so the * entries can now access all cost centres.
Access, UserID, Password, CostCentre
USER, USER, USER, *
ADMIN, ADMIN, ADMIN, *
USER, JOHN, JOHN, A
USER, MARY, MARY, B
USER, PETER, PETER, C
ADMIN, SIMON, SIMON, A
DUMMY, DUMMY, DUMMY, D
DUMMY, DUMMY, DUMMY, E
DUMMY, DUMMY, DUMMY, F
DUMMY, DUMMY, DUMMY, G
DUMMY, DUMMY, DUMMY, H
Note – you cannot open the document as user DUMMY because DUMMY is an invalid Access value, only ADMIN and USER entries are allowed to open the document.
Section Access Example 5
This adds Region to the restrictions as well as CostCentre, but the restriction on Region fails as the
region fieldname is not UPPERCASE.
Access, UserID, Password, CostCentre, Region
USER, USER, USER, *, *
ADMIN, ADMIN, ADMIN, *, *
USER, JOHN, JOHN, A, North
USER, MARY, MARY, B, South
USER, PETER, PETER, C, East
ADMIN, SIMON, SIMON, A, North
ADMIN, SIMON, SIMON, A, East
DUMMY, DUMMY, DUMMY, D, North
DUMMY, DUMMY, DUMMY, E, South
DUMMY, DUMMY, DUMMY, F, East
DUMMY, DUMMY, DUMMY, G, West
DUMMY, DUMMY, DUMMY, H
Section Access Example 6
The Region fieldname is uppercase, but the restriction on Region still fails as the region data is not UPPERCASE.
Section Access Example 7
The Region restriction now works by loading the region data into a second field named REGION_SA and forcing the data in REGION_SA to UPPERCASE.
Version3 - The Region field has been removed from the Section Access table. This fixes the error identified by kanhomcake (March 27 2014).
Hopefully this will help avoid some of the basic errors that can be made when implementing Section Access.
Colin Albert.
This document will help those how are looking for solutions for creating flags with ytd/mtd/qtd & rolling averages in qlik sense or Qlikview.
I used HIC's Concept As-of Table https://community.qlik.com/t5/Design/The-As-Of-Table/ba-p/1466130 to implement this document is extension with rolling averages and creating flags.
Thanks
Vikas Mahajan
Everyone knows that sometimes we need to use chr() function to put paragraph sign - chr(13) – or single-quote - chr(39).
But sometimes you need a special symbol, but you don’t know the number. You can find it in the Internet, but I’ve found a Qlik way how to do it.
There is a faster way, If you found a symbol in the Internet and would like to know what is the number for this char.
For example delta sign
Δ
Use the ord() function
Ord(‘Δ’) gives you 916. So if you need to put this symbol somewhere you can use chr(916)
Some interesting codes are
=chr(9650) & chr(9651) & chr(9660) & chr(9661)
=chr(9733) and =chr(9734)
Be aware!
in the comments in different discussion jaimeaguilar mentioned that
"using chr() function you can display any ASCII / ANSI character (from chr 0 to 255) or Unicode chars (from chr 256 and up). The corresponding number in chr() function for the Unicode chars is the number referred as decimal, that can be found in plenty internet sites. Almost any Unicode char will display in ajax, but in some cases the correct displaying will depend on the page encoding."
Following upgrade from Qlikview 11.2 to 12.7, we've noticed that Access Point previously showed the qvw file name in mixed case, but now has in lower case.
Following screenshot shows example on old/new version.
Is there any way to revert to mixed case on latest version?
From NPrinting June 2019
Note: I have made a few changes to a copy of the sample Qlik Sense App found here and used that as the Connection source for these examples. The modified App and exported report are attached to this post.
Fields that exist in the source document that we use:
Variables that exist in the source document that we use:
Example 1.
Filtering for a date range.
With Advanced search filters you can filter for a date range in any of these ways:
Note: The above filters were defined on the Date field. You can also define the same filters for other fields just as you can use expression search in the source document if you want to search for values in associated fields. For example you could use the exact same filter definition for the Customer field to get different results:
Screenshots of the Filter editor showing the difference:
Example 2.
Filtering for the Top n
Here is an example using Advanced search filters and Aggr() to filter for the Top 10 Customers (most Sales). You can of course use a variable or an expression that results in an integer instead of hard-coding the number 10.
=Customer=aggr(if(rank(sum(Sales)) <=10, Customer), Customer)
Example 3.
Filtering for a range
Similar to example 1. Here again you can use variables or expressions instead of hard-coding the numbers.
=sum(Sales)>=300000 and sum(Sales)<=500000
Example using aggr() to get Customers with Sales above average but also less than or equal to $160,000
=sum(Sales)>Avg(TOTAL Aggr(Sum(Sales),Customer)) and sum(Sales)<=160000
Example 4.
Filtering using wildcards
Advance search filters supports the use of wildcards. This example filters for all Customer names that begin with IB or end with EX
=Customer like 'IB*' or Customer like '*EX'
I'm very excited to see the myriad ways this powerful feature will be used going forward. I hope this short introduction gets you started.
- Daniel.
To set up the example project:
Over a year and half ago, I published instructions for creating a class to communicate with Qlikview api using the Python language. Here is the link for your convenience: QLIKVIEW AUTOMATION WITH PYTHON
Many of you have written and sent me messages requesting to make a new post containing the instructions to extract Qlikview pivot tables in excel and send them via email.
So after more than a year and a pandemic in action, here is an example of extracting Qlikview tables and sending as an email attachment. All tested with Python 3.9
You can found the full files and code at GITHUB
Here I post only the Python script.
Basically, there is a configuration file of the email parameters and the path of the qlikview file. The qlikview script defines the table containing the people who must receive the emails with their addresses and the table fields to be filtered with the filter value to be used to reduce the data.
Hoping you like it, for question or issues write me on GitHub.
PyQlikSender.py
from win32com.client import Dispatch # pywin32 module
import smtplib
from email.message import EmailMessage
import os.path
from datetime import datetime
import configparser
import logging
current_path = os.getcwd()
config = configparser.ConfigParser()
config.read_file(open(r'PyQlikSenderConf.txt'))
QLIKVIEW_DOCUMENT = config.get('configuration','QLIKVIEW_DOCUMENT')
SMTP_ADDRESS = config.get('configuration','SMTP_ADDRESS')
SMTP_PORT = config.get('configuration','SMTP_PORT')
EMAIL_FROM = config.get('configuration', 'EMAIL_FROM')
EMAIL_LOGIN = config.get('configuration', 'EMAIL_LOGIN')
EMAIL_PASSWORD = config.get('configuration', 'EMAIL_PASSWORD')
LOGFILE = config.get('configuration', 'logfile')
QVRELOAD = config.get('configuration', 'QVRELOAD')
class QlikView:
def __init__(self😞
self.app = Dispatch('QlikTech.QlikView')
def opendoc(self, docname, username, password):
doc = self.app.OpenDoc(docname, username, password)
return doc
def reload(self,doc):
doc.Reload()
def clearall(self,doc):
doc.ClearAll()
def apply_field_filter(self, doc, filter_field, filter_value):
doc.Fields(filter_field).Select(filter_value)
def closedoc(self, doc):
doc.CloseDoc()
def sendmail(email, subject, name, surname, filename):
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = EMAIL_FROM
msg['To'] = email
content = 'Dear ' + name + ' ' + surname + ' your report is attached here'
msg.set_content(content)
try:
with open(filename, 'rb') as xls:
msg.add_attachment(xls.read(), maintype='application', subtype='octet-stream', filename=xls.name)
except Exception as e:
print('cannot open attachment to send, error :' + str(e))
try:
with smtplib.SMTP_SSL(SMTP_ADDRESS, SMTP_PORT) as smtp:
smtp.login(EMAIL_LOGIN, EMAIL_PASSWORD)
smtp.send_message(msg)
except Exception as e:
logging.info('cannot send email to : ' + email + ' , error :' + str(e))
def manage_document(docname, current_path, tb_email):
username = None
password = None
q = QlikView()
version = q.app.QvVersion()
print(version)
doc = q.opendoc(docname, username, password)
if QVRELOAD == 'Y':
q.reload(docname)
email_table = doc.GetSheetObject(tb_email) # the object table containing email to send and filter to apply
today_date = str(datetime.today().date()).replace('-', '_')
rowiter = 0
rows = email_table.GetRowCount()
while rowiter < rows:
title = email_table.GetCell(rowiter, 0).Text
name = email_table.GetCell(rowiter, 1).Text
surname = email_table.GetCell(rowiter, 2).Text
email = email_table.GetCell(rowiter, 3).Text
company = email_table.GetCell(rowiter, 4).Text
filter_field = email_table.GetCell(rowiter, 5).Text
filter_value = email_table.GetCell(rowiter, 6).Text
tb1 = email_table.GetCell(rowiter, 7).Text
print(title, name, surname, email, company)
rowiter = rowiter + 1
subject = "Qlikview report service for: " + company
if rowiter > 1:
filename = tb1 + '_' + name + '_' + surname + '_' + today_date + '.xls'
q.clearall(docname) # clear all filter
doc.Fields(filter_field).Select(filter_value) # apply filter
try:
chart = doc.GetSheetObject(tb1)
except Exception as e:
logging.info('error: ' + str(e))
chart_path = current_path + '/' + filename
chart.ExportBiff(chart_path)
sendmail(email, subject, name, surname, filename)
q.closedoc(doc)
q.app.Quit()
if __name__ == '__main__':
doc = current_path + '/' + QLIKVIEW_DOCUMENT
logging.basicConfig(format='%(asctime)s - %(message)s', filename=LOGFILE, encoding='utf-8',
level=logging.DEBUG)
tb_email = 'email' # qlikview table containing email address and info
manage_document(doc, current_path, tb_email)
About
What is it? What does it do?
This is a tool that I use to quick check shared file content and do some usual maintenance job on it. After playing with colleagues for a while, I think it'd be nice to share with the community and get some feedback about if/how I should proceed with this personal project.
This tool is a very simple one, it just can open both legacy ".Shared" and new ".TShared" formats of QlikView Shared File, show helpful info in it, and provide some very basic operations on shared objects (currently I have only add support for Bookmark because it's the most commonly used one day-today)
Why another Shared File Viewer?
There has been a Shared File Viewer already for quite a while (in PowerTools package)
The limitation of the existing one is it can't open the new "TShared" format that was introduced lately into QlikView. So if one wants to view new format, they have to convert "Tshared" to "Shared" first and convert it back afterwards, which is really annoying especially the shared file is *big*.
Another limitation for the current one is it provides small subset info of Shared file content and doesn't embed much shared file functions (cleaning, filtering) in it because its development toolchain is out of dated.
Lastly, I found it's not easy to run a Shared File Cleaner without GUI and want something more intuitive.
In short the legacy shared file viewer is inconvenient to use(to me at least 😅 ), especially when it comes to new "TShared" format.
So i think why not just write another tool myself to meet my need - here it comes.
Release Note
Current Stable Release: 0.2
You can find it in the attachment, where the zip file simply contains an exe file that you can run on Windows.
Features:
Hopefully you have time to download and play with it, and, most importantly, give me some feedback about how you think of it, and what other functions you want to include in it in future.
NOTE:
this tool is currently under preview only. and please be CAUTIOUS if you use it with production Shared files. I know the shared content is critically important, so make sure you have backup before touching any Shared Files.