Jedox Percentage on Percentage on Percentage Split with “instant” preview


Imagine you have a customer who wants to split revenue by multiple dimensions not based upon total figures nor on percentual splits. E.g. you plan 10k and split it to 3 Segments by

  • 20% Seg A
  • 40% Seg B
  • 40% Seg C

And after this by ProductGroup and Product which are in one Dimension

  • 20% ProdGroup I
    • 50% Prod A
    • 50% Prod B
  • 80% ProdGroup II


Important: I struggled by trying to solve this with a “one cube solution” as two many “unknown” levels are existing to identify the storage of the percentage value. So to get a stable an performant solution, you need to stick to the following steps:

  1. Identify the Split Points, in our example for the segments (which are the first split level) the percentages will be stored on the base elements for Seg A, B, C
  2. Then we need to create a helper Cube which will store the percentages for this first level, as we will have different percentages by Year, Version and Szenario, they need to be added to seperate the values later

Cube Layout within Integrator Constant Table Extract:

Definition of split cube step 1

From this extrace we go straight to the cube load:

Cube load – will create the cube on the first execution

So in your modeler a new cube should have appeared:

The “storage” cube for the factors on level 1 – segments

So within the worksheet (report designer) to keep it manageble I will add a named range to store the cube name:

Named Range within worksheet

So for the entry of the factors we create a DynaRange for the Segments:

And allow the user to enter the values on the base elements. Conditional Format on the ELEVEL information.

Check for Baseelements


The calculation of the “temp result” will be done in the Split 1 cube by using the formula

Rule within result cube

=[‘_Sales_Budget_Top_Down’:’_split_faktor_Segments’] = B:[‘_Sales_Budget_Top_Down’:’_faktor_Segments’] * PALO.DATA(“”,”SALES_BUDGET_LIC_REV_TOP_DOWN_REDUX”,!’Years’,”Total_Year”,!’Versions’,!’Szenario’,”Reporting_Currency”,”Total_Segments”,”Sales Hierachy”,”Total_TD_Account_Business_Type”,”Total_TD_Products”,”_input”) / 100

The next step is tricky, as we have the product group and the product in one dimension, so we aren’t able to store the value for the percentage on a base element as needed. to solve this issue we create a helper dimension for the product which will allow us to store the percentage on a base element. To do this, we first extract all values from the dimension that we wanna “split” to give it even more complexity, here we have a structure of different depths…

For our first helper, we actually focus on the values of level2. To do so, we need to get to an TreeFH Transformation step which will only be possible with a “in between step” using a tableview:

And after this the treeFH where we only use the first 2 levels:


As the tree fh will hold “no distinct” values, you can improve by adding like a aggregation inbetween, as we don’t have that many rows, I will step a head an create the dimension diretly
The big picture for the product level 1 helper dimension

So as we did for the segments, we will create a helper cube to store the factors, this time we need to take care that the factors are although related to the segments:

From here we proceed as above and the cube should look like this:

Then we need to add the following rule to this cube which looks like:

Faktor Segment * Faktor ProductGroup / 100 /  100

[‘_Sales_Budget_Top_Down’:’_split_faktor_TD_Products’] = B:[‘_Sales_Budget_Top_Down’:’_faktor_TD_Products’] *
PALO.DATA(“”,”SALES_BUDGET_LIC_REV_TOP_DOWN_REDUX”,!’Years’,”Total_Year”,!’Versions’,!’Szenario’,”Reporting_Currency”,”Total_Segments”,”Sales Hierachy”,”Total_TD_Account_Business_Type”,”Total_TD_Products”,”_input”) / 10000

After this you can again adopt the values in the worksheet to show the correct figures from within the 2nd helper cube.

For the products itself, it will become easy, as we can use the product dimension “as-is”. Which will mean we create a cube design as followed:

And here the cube:

Split By Step3 Product Level 2 (Base Elements)

Important, this time (as we stay in the same dimension) we only exchange the helper dimension of the products with the full product dimension and let it rock!

And pls. add the following rule

Faktor Segment * Faktor ProductGroup * Faktor Product / 100 /  100 / 100

[‘_Sales_Budget_Top_Down’:’_split_faktor_TD_Products’] = B:[‘_Sales_Budget_Top_Down’:’_faktor_TD_Products’] * PALO.DATA(“”,”SPLIT_BY_STEP1_SEGMENT”,!’Years’,!’Versions’,!’Szenario’,!’Segments’,”_faktor_Segments”) * PALO.DATA(“”,”SPLIT_BY_STEP2_PRODUCT_L1″,!’Years’,!’Versions’,!’Szenario’,!’Segments’,PALO.EPARENT(“”,”TD_Products”,!’TD_Products’,1),”_faktor_TD_Products”) * PALO.DATA(“”,”SALES_BUDGET_LIC_REV_TOP_DOWN_REDUX”,!’Years’,”Total_Year”,!’Versions’,!’Szenario’,”Reporting_Currency”,”Total_Segments”,”Sales Hierachy”,”Total_TD_Account_Business_Type”,”Total_TD_Products”,”_input_ABR”) / 1000000

Again we add the named range:

So like this you will be able to have like a report where you can show values by each “split” and written back to all base elements by helper cube.

Allgemeines Jedox

Jedox – User CRUD – Manage Dimensions within worksheet


Sometimes it´s needed that a user can add elements to a dimension without accessing the modeller – e.g. you wanna budget personal ressources and want to allow power users to add new placeholders to the employee dimension.

Entry mask for new employees

To get this working, you can use multiple ways on how to pass values from the worksheet, to the script – I prefered to use “names” for the parameters I wanna pass to my php:

Name Manager

Then with the “add” button, I use the following macro to insert the new element to the selected parent (trop down) and add the attributes.

* Author <philipp@frenzel.net>
* Create a new ressource with name - Full_Name, Start_Date

function _btnAdd_Click ()
  //First Read the values given by formula
  $connection = activeworkbook()->names->item("RNG_CONNECTION")->value;
  $inpFull_Name = activeworkbook()->names->item("crud_name")->value;
  $inpStart_Date = activeworkbook()->names->item("crud_start_date")->value;
  //Second retrieve variables
  $inpParentRessource = retrieve_variable("RESOURCES");
  //Third add a new Element to the dimension
  $key = $inpFull_Name . "(" . $inpParentRessource . ")";
  //Forth add the attrbutes to the new element
  return __recalc();

After you added the new element, with the recalc call at the end of the script, the dyna range should refresh immediatly and you should see the new element.


Jedox – Daten per Integrator Job und Worksheet kopieren


Sie möchten Ihren Nutzern eine einfache Möglichkeit zur Verfügung stellen, damit diese via Comboboxen und Button die Werte aus einer Sicht (bei Version) in eine andere Sicht (Version) kopieren können.

Bsp. Saisonalität

Die Saisonalität wird in einem Hilfswürfel gespeichert:


Enthalten sind die folgenden Dimensionen:

  • Jahr
  • Monat
  • Version
  • Saison_Typ (linear, effektiv oder prozentual)
  • _measure_saison


Worksheet zur Steuerung der aktuellen Daten, inkl. 4 Comboboxen mit Inhalt:

  • Jahr (Quelle/Ziel)
  • Version (Quelle/Ziel)

und ein Button, der die Werte überträgt.


Dann benötigen wir einen Cube-Extract für die aktuellen Werte und ein Cube-Slice zum Nullsetzen der Zielwerte bevor wir die Kopie einspielen.

Variablen im Integrator ETL

  • ficube_JAHR
  • ficube_VERSION
  • cubecopy_tJahr
  • cubecopy_tVersion

Nullsetzen der Zielversion

Kopieren der Werte

Wichtig ist die Übergabe der Variablen beim Cube-Extract:

Im Transformationsschritt werden dann die Zielkoordinaten mittels konstante und Variable übergeben (Achtung, im Screenshot fehlt die Kostenart):

Wichtig: alle Dimensionen des Würfels zzgl. des Wertes müssen beim Cube-Load vorhanden sein!

Die beiden ETL-Strecken werden dann in einem Job zusammen gefasst.

Die Benutzeroberfläche

Button und Makro

Im Sheet sind die folgenden Variablen definiert:

  • JAHR
require library('integrator');

 * @author Philipp Frenzel <philipp@frenzel.net>
 * @version 1.0.0
 * Kopieren der Werte für den Wüfel saison_koart
 * von einer in die nächste Version
function _cp_saison_koart ()
  	//1. Auslesen des Connection Strings (Named Bereich im Worksheet)
	$connection = activeworkbook()->names->item('_rngConnection')->value;
  	//2. Einlesen der Variablen aus der Oberfläche
    $jahrSource = retrieve_variable('JAHR');
    $versionSource = retrieve_variable('VERSION');
    $versionTarget = retrieve_variable('VERSION_TARGET');
	//3. Befüllen der Variablen, die an den Integrator-Job übergeben werden
    $variables = [
		['name'=>'ficube_Jahr' ,'value'=>$jahrSource],
  		['name'=>'ficube_Version' ,'value'=>$versionSource],
  	//4. Aufruf des Jobs, inkl. Übergabe der Parameter (id ist der Prozess)
    $id = integrator_start_job('ITECBase','_cp_saison_koart',$variables,TRUE);
    return __recalc();

ACHTUNG: Beim kopieren der Werte kann es sein, dass 1 nicht gleich 1 bleibt. In meinem Dokument musste ich die boolean Bedingungen umschreiben, dass sie auf “>0” prüfen. Dadurch klappt es dann!


Jedox Linux Backup Shell Script

To backup your jedox linux installation, you can use the following script. Pls. change Folders to match your local Jedox Installation:

# Programm: jedox_backup.sh
# Autor : Philipp Frenzel <frp@informatec.com>
# Inhalt : 
#   1. Jedox stoppen
#	2. Sicherung der Jedoxdaten (/mnt/data/Jedox/Data) und Anlegen einer Logfile als Tagessicherung / Vollsicherung am Montag und dann inkrementelle Sicherung am Di, Mi, Do, Fr.
#	3. Jedox starten
#	4. Aufraeumen: Logfiles, älter als 90 Tage, werden gelöscht/Backups älter 14 Tage werden gelöscht

# Datum : 23./29.10.2015
# Aenderung: 05.02.2016: Aufraeumem erweitert - Backups aelter 14 Tage werden gelöscht; Aufraeumen nur Montags
#	15.02.2016: .archived Dateien werden Montags geloescht;
#	22.02.2016: Aenderung der Eigentumerrechte, einmal Eigentuemer root für das Backup und dann wieder zurueckgeben an jedoxweb
#	10.10.2016: log-Aenderungen eingeführt, eigenes log für den olap Server unter Data.

# Funktionen:
echo "$2" | mailx -S smtp=server:port -s "$1" -v frp@informatec.com

# Variablen
DATUM=$(date +"%Y%m%d")
WOCHENTAG=$(date +"%u")

#check User
if [ `id -un` != "root" ]
echo "User ungueltig, benoetigt wird root"
sende_mail "Probleme beim Backup auf der $HOST" "User ungueltig, benoetigt wird root"
exit 1

echo $(date +"%H:%M:%S")": START - Jedox stoppen ----------------------------------------" >> ${LOGFILE}
sudo ${INSTALLPFAD}/jedox-suite.sh stop >> ${LOGFILE}
wait $(pgrep palo)

echo "Backup ${HOSTNAME} vom $(date +"%d.%m.%Y-%H:%M")----------------------------------------" >> ${LOGFILE}

#Prüfen, ob Ordner da ist - wenn dann ist $? gleich 0
if [[ $RC -ge 1 ]];
echo "Pfad nicht gefunden. Backup nicht ausgefuehrt!" >> ${LOGFILE}
sende_mail "Probleme beim Backup auf der ${HOSTNAME}" "Bitte die Logdatei des Backups ueberpruefen: ${LOGFILE}"
#echo "Bitte die Logdatei des Backups ueberpruefen: ${LOGFILE}" | mailx -S smtp=smtprelay1.s-v.loc:25 -s "Probleme beim Backup auf der ${HOSTNAME}" -v $MAILEMPFAENGER
exit 8

# Backup
echo $(date +"%H:%M:%S")": Beginn der Sicherung" >> ${LOGFILE}

#root die Eigentuemerrechte geben, damit er das Backup auch komplett ausfuehren kann
sudo chown -R root /mnt/data/Jedox/Data/

#gucken, ob Montag ist
if [[ ${WOCHENTAG} == 1 ]]; then
echo "Vollbackup: ${FILENAME}.tar" >> ${LOGFILE}

#snapshot Datei wird gelöscht
rm ${BACKUP_DIR}/usr.snar
tar -vcz --file=${FILENAME}.tar.gz --listed-incremental=${BACKUP_DIR}/usr.snar ${SOURCE} >> ${LOGFILE}

elif [[ ${WOCHENTAG} -ge 2 && ${WOCHENTAG} -le 5 ]]; then
SDATUM=$(date -d "last Monday" +"%Y%m%d")
echo "inkrementelles Backup: ${FILENAME}.tar" >> ${LOGFILE}

tar -vcz --file=${FILENAME}.tar.gz --listed-incremental=${BACKUP_DIR}/usr.snar ${SOURCE} >> ${LOGFILE}
#tar -vcf ${BACKUP_DIR}/Backup_${HOSTNAME}_${DATUM}.tar ${SOURCE} >> ${LOGFILE}

#Prüfen ob Kompression ohne Fehler
if [[ $RC -ge 1 ]];
rm ${FILENAME}.tar
echo $(date +"%H:%M:%S")": Tar nicht korrekt erstellt. Backup von ${HOSTNAME} wird nicht ausgefuehrt!" >> ${LOGFILE}
sende_mail "Probleme beim Backup auf der ${HOSTNAME}" "Bitte die Logdatei des Backups ueberpruefen: ${LOGFILE}"
exit 8
echo "$(date +"%H:%M:%S"): tar und compress erfolgreich." >> ${LOGFILE}
# echo "$(date +"%H:%M:%S"): TAR erfolgreich. Beginn Compress" >> ${LOGFILE}
# gzip ${FILENAME}.tar
# RC=$?
# #Prüfen ob Kompression ohne Fehler
# if [ $RC -ge 1 ];
# then
# rm ${FILENAME}.tar.gz
# echo "RC: $RC bei Compress " >> ${LOGFILE}
# echo $(date +"%H:%M:%S")": Compress nicht erfolgreich. Backup ueberpruefen!" >> ${LOGFILE}
# sende_mail "Probleme beim Backup auf der ${HOSTNAME}" "Bitte die Logdatei des Backups ueberpruefen: ${LOGFILE}"
# else
echo $(date +"%H:%M:%S")": Backup von ${HOSTNAME} wurde korrekt ausgefuehrt!" >> ${LOGFILE}

#	zum unterbrechen
#	read -p "Press [Enter] key to delete files..."

# Nachträgliche Aufräumarbeiten; immer Montags
if [[ ${WOCHENTAG} == 1 ]]; then
echo $(date +"%H:%M:%S") "Aufraeumen - folgende Dateien werden geloescht:" >> ${LOGFILE}
#Logfiles, älter 90 Tage löschen
find /mnt/data/Backup/Logdateien/ -type f -mtime +91 -exec ls {} \; >> ${LOGFILE}
find /mnt/data/Backup/Logdateien/ -type f -mtime +91 -delete 2>> ${LOGFILE}
#Sicherungsdateien, älter 14 Tage löschen
find /mnt/data/Backup/Backup_lxkad* -type f -mtime +14 -exec ls {} \; >> ${LOGFILE}
find /mnt/data/Backup/Backup_lxkad* -type f -mtime +14 -delete 2>> ${LOGFILE}
#.archived-Dateien löschen
find /mnt/data/Jedox/Data/ -name '*.archived' -type f -exec ls {} \; >> ${LOGFILE}
find /mnt/data/Jedox/Data/ -name '*.archived' -type f -delete 2>> ${LOGFILE}

#	zum unterbrechen
#	read -p "Press [Enter] key to start Jedox..."

#jedoxweb die Eigentuemerrechte zurueckgeben,
sudo chown -R jedoxweb /mnt/data/Jedox/Data/

echo $(date +"%H:%M:%S")": Jedox starten ----------------------------------------" >> ${LOGFILE}
#sudo ${INSTALLPFAD}/jedox-suite.sh start >> ${LOGFILE}
sudo ${INSTALLPFAD}/jedox-suite.sh start >> ${INSTALLPFAD}/log/olap_server.log
# eine Schleife, die 300 Sekunden lang prüft, ob die Dienste gestartet wurden
while [[ $z -lt 300 ]];
# Abfrage, ob die Jedox Dienste gestartet wurden
if pgrep "palo" && pgrep "core.bin" && pgrep "java" && pgrep -U jedoxweb "httpd";
echo $(date +"%H:%M:%S") "Alle Prozesse laufen - Jedox ordnungsgemaess gestartet!" >> ${LOGFILE}
sleep 30; z=`expr $z + 30`;

# Prüfung ob alle Dienste gestartet sind, falls nicht eine Benachrichtigung...
if ! pgrep "palo" || ! pgrep "core.bin" || ! pgrep "java" || ! pgrep -U jedoxweb "httpd";
then sende_mail "Probleme beim Backup auf der ${HOSTNAME}" "Jedox wurde nicht ordentlich gestartet. Bitte pruefen."

echo $(date +"%H:%M:%S") "Backup ENDE!" >> ${LOGFILE}

exit $RC



Jedox als Docker Contaier unter Windows ausführen

Vorbereitung der Umgebung

  1. Installieren Sie die neueste Version von Docker auf Ihrem Windows (www.docker.com)
  2. Erstellen Sie sich auf der Festplatte Ihrer Wahl ein Verzeichnis /docker
  3. Berechtigen Sie Docker für den Zugriff auf dieses Verzeichnis



Jedox Windows SSO

Anbindung von Jedox an das Active Directory

Sollten Sie den Wunsch haben, Ihre Jedox Installation im Bereich Benutzermanagement mit Ihrem Firmen AD zu verbinden, gehen Sie dazu bitte wie folgt vor.

Benutzer und Rollen Konfiguration

  1. Erstellen Sie min. 2 Gruppen in Ihrem AD für die Jedox Benutzer
    1. jedox-admin (Jedox Systemadministratoren)
    2. jedox-user (Jedox Benutzer)
    3. jedox-designer (Jedox Entwickler)
  2. Erstellen Sie einen Administrations-Account jdx-admin



Erstellen einer Startseite


Um eine attraktive und übersichtliche Startseite für Ihre Jedox-Lösung zu erstellen, haben Sie die folgenden Möglichkeiten innerhalb des Report Designers.

Technische Lösung

Damit man besser versteht was passiert ist es wichtig zu wissen, dass Jedox Web eine komplette Web-Lösung ist, die alle Vorteile einer Webapplikation sowie auch die Nachteile eine Webapplikation bietet.


  • Dezentrales Arbeiten am System (moderner Browser als Client erlaubt die komplette Verwaltung)

Jedox – Berechtigungen

Welche Rechte welcher Benutzer hat, wird in einem der Systemwürfel gespeichert. Zusätzlich gibt es für jede Dimension einen weiteren Rechtewürfel:

  • Bsp: Dimension Kostenstellen -> #_USER_Kostenstellen

Will man sich einen Überblick über die vergebenen Berechtigungen haben, so muss kann man eine View mit dem oben gennanten Systemwürfel erstellen und sieht dort die Berechtigung nach Benutzer. Folgende Berechtigungen sind möglich:

N: Users have no access to #_USER_ dimension1).
R: Users can see “user” objects in the #_USER_ dimension of System DB (or any other DB), but cannot edit/delete them.
W: Users are allowed to change “user” objects (rename users) and create new users.
D: Users are allowed to delete users.

Jedox – Erstellen einer generischen Dimension


Für die Minimierung der Wartung und die zentrale Datenadministration soll sich eine Dimension generisch (aus dem Vorsystem) erstellen, aktualisieren oder reduzieren. Ein komplettes löschen der Werte ist an dieser Stelle nicht vorgesehen.

Globale Variablen

varDocumentRoot Verzeichnis Das Verzeichnis in dem sich das Jedox Projekt befindet (hier die Import-Dateien)
varDBHostName String Name des OLAP Hostes – z.B. “localhost” oder “localhost_static”
varDBName String Name der OLAP Datenbank, in die per Default zurück geschrieben wird – z.B. “Projekt_001”


Damit die Dimension generisch erzeugt werden kann, muss zuerst eine Verbindung auf die Datenquelle hergestellt werden, in unserem Bsp. auf eine CSV-Datei. Danach wird diese geladen mittels “extract” und dann je nach Bedarf “transformiert” oder roh für den Aufbau “load” der Dimension übergeben.

Dabei verwende ich die folgende Namenskonvention:

  • ConDimDimensionsname
  • ExDimDimensionsname
  • TransDimDimensionsname (je nach Bedarf)
  • LoadDimDimensionsname

Dabei gibt es für den finalen Load einige wichtige Einstellungen in Bezug auf die Bestandslogik in der Hierarchie zu beachten.

Wie man hier gut erkennen kann, ist je nach ausgewähltem Modus ein anderes Ergebnis zu erwarten:

Welcher Modus also zum Ziel führt hängt auch davon ab, wie die Anforderung im Projekt lautet?

  • Mehrfachzuordnungen eines Kinderelementes möglich?
  • Wie sieht es mit der Historie der Werte aus?
  • Was passiert mit gelöschten Werten?

Folgende Einstellungen schlägt Jedox für den generischen Load vor: