Philip Shemella wrote:
There seems to be no way to create a multi-datasource filter that is driven by a parameter.
Why not create a field to store this in the data ?
There's a few ways to solve this, but the simplest might be a "client" filter in the data and then you simply change the filter, create the extract and save the workbook.
You could also play with the XML of the TWB file if you wanted to use either of your first 2 methods. Keep a backup just in case, but I would suggest creating a batch file (maybe in Python) to change the data source details in the XML.
If I export ALL data, then I do indeed have a field that I can filter on. But the filter needs to be at the highest level (the data connection), and not at the report level.
At the moment, I'm trying out with a parameter in the 4 data source filters. It should work in theory, but I'm getting strange results after I refresh (no data). It doesn't refresh automatically when I change the parameter.
I did a test of the data source filters. With one client selected, by parameter, and a live CSV datasource (no extract), I did an "Export Packaged Workbook". The data that the report was showing was correct, but I wanted to see what data was shipped with the file.
With that test file, which should have a subset of the data, I renamed from TWBX to ZIP, unpackaged, when to the datasources folder, opened a CSV, and found ALL the data.
So on privacy grounds, the data source filter doesn't seem to be very useful in my case with CSV files. Additionaly, sharing a workbook with a parameter for other clients isn't desirable (but it could be hidden).
Here's my parameter-based data source filter:
Next attempt is to connect to Postgresql instead of CSV files (I can choose where and how data is written).
Since the schema determines the "path" of the tables, and the tables are identically named, I've set a custom SQL query with a parameter to determine the schema.
When I type the schema name in manually, it works. When I assign it from a parameter, it does not.
Not possible due to this (preventing SQL injection)
What does work is to make a SQL connection to ALL the data with a data source filter that includes the parameter matching.
Then from the TWB file do an "Export as packaged workbook". This workbook, as TWBX, contains a .hyper extract that only has the relevant data.
I'll leave the question open because I'm still looking to do it on a per-client basis, and not from the full dataset and parsed down per customer. If I use Tableau Online, then I would have to carefully check what data is uploaded and is available (even if hidden) to the user.
UPDATE: since I am using Postgresql instead of CSV, I will create unique databases, and when I open the TWB file, because I am prompted for the DB password, will manually set which client the report corresponds to. Then I can be sure there is no cross-contamination of the data with data sources filters.
UPDATE2: it does work to switch databases when opening a report, but it's not so consistently asking for log-ins, so I have to manually "edit connection" for each connection each time I want to work with a different client's data.
UDPATE3: Using Tableau's document API (python), I was able to make a modified script that loops over all connections and sets them to a new parameter. This is much safer and easier than modifying multiple connections in Tableau Desktop itself.
Note that at the time of writing, documentation has the object "sourceWB._datasources" without the underscore, which is an error.
#!/usr/bin/env python # -*- coding: utf-8 -*- # modified from: http://tableau.github.io/document-api-python/docs/ from __future__ import print_function from tableaudocumentapi import Workbook def main(): file_path = 'report.twb' db_name = 'new_db' sourceWB = Workbook(file_path) for i in xrange(len(sourceWB._datasources)): print ('INFO: datasource',str(i)) for j in xrange(len(sourceWB._datasources[i].connections)): print ('INFO: connection',str(j)) if sourceWB._datasources[i].connections[j].dbname != db_name: print('INFO: old',sourceWB._datasources[i].connections[j].dbname) sourceWB._datasources[i].connections[j].dbname = db_name print('INFO: new', sourceWB._datasources[i].connections[j].dbname) print() else: print('INFO: nothing to change') # other db params to change #sourceWB._datasources[i].connections[j].server = "MY-NEW-SERVER" #sourceWB._datasources[i].connections[j].username = "postgres" sourceWB.save() if __name__ == "__main__": main()