Das Notes Forum

Domino 9 und frühere Versionen => ND8: Entwicklung => Thema gestartet von: buzi am 30.09.15 - 11:30:40

Titel: Verschachtelte @If-Abfragen
Beitrag von: buzi am 30.09.15 - 11:30:40
Hallo zusammen,

ich habe eine Frage wie man verschachtelte If-Abfragen in Formelsprache am besten formuliert. Es geht darum, dass ein Preis in Abhängigkeit der Mitgliedschaft (ja/nein) und der ausgewählten Kategorie berechnet wird. Zunächst wird anhand des Namens das Kunden-Dokument gefunden, um herauszufinden ob er Mitglied ist oder nicht (das funktioniert nach meinen Tests). Aber die If-Fragen laufen immer bis zum Ende durch also am Schluß steht "n.b.8" im Preis-Feld.

Die Formel meines Preis-Felds sieht bislang so aus:

key := @If(iTeFirma="";iTeNachname + " " + iTeVorname;iTeFirma +" "+ iTeNachname +" " + iTeVorname);
values := @DbLookup ( "":"Nocache"; "":""; "vwKunden "; key; "iTeMitgliedVon" );
isMitglied := @IsMember("Verband B"; values);

@If(iTeKategorie!="" & @Contains(iTeKategorie;"1.") & isMitglied ; "10 € / 1. Jahr"; "n.b.1");
@If(iTeKategorie!="" & @Contains(iTeKategorie;"1.") & !isMitglied ; "20 € / 1. Jahr"; "n.b.2");

@If(iTeKategorie!="" & @Contains(iTeKategorie;"2.") & isMitglied ; "20 € / 1. Jahr"; "n.b.3");
@If(iTeKategorie!="" & @Contains(iTeKategorie;"2.") & !isMitglied ; "30 € / 1. Jahr"; "n.b.4");

@If(iTeKategorie!="" & @Contains(iTeKategorie;"3.") & isMitglied ; "40 € / 1. Jahr"; "n.b.5");
@If(iTeKategorie!="" & @Contains(iTeKategorie;"3.") & !isMitglied ; "50 € / 1. Jahr"; "n.b.6");

@If(iTeKategorie!="" & @Contains(iTeKategorie;"4.") & isMitglied ; "60 € / 1. Jahr"; "n.b.7");
@If(iTeKategorie!="" & @Contains(iTeKategorie;"4.") & !isMitglied ; "70 € / 1. Jahr"; "n.b.8");

Hinweis: Wenn ich nur die erste If-Zeile stehen lasse, und im Kategorie-Feld "1." auswähle, klappt es - dann steht "10 € / Jahr" im Preis-Feld. Aber sobald die anderen IF-Zeilen dazu kommen geht es schief.

Kann man das in Formelsprache überhaupt elegant lösen oder braucht man Lotus Script dafür?
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: tks am 30.09.15 - 11:41:51
Auszug aus der Designer-Hilfe:

@If( condition1 ; action1 ; condition2 ; action2 ; ... ; condition99 ; action99 ; else_action )

Also nicht für jede Bedinung ein @If, sonder alles in eines.
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: Peter Klett am 30.09.15 - 12:35:03
Ich würde das ganze erst einmal etwas entzerren und ggf. @Return verwenden.

Annahme: Du gibst kein Ergebnis, wenn iTeKategorie leer ist

@If (iTeKategorie = ""; @Return (""); "");

Dann hast Du Kategorien, von denen Du nur den Zahlenwert zur Berechnung verwenden willst. Den würde ich mir einmalig in eine Variable rechnen

_k := @If (@Contains (iTeKategorie; "1."); "1" ; @Contains (iTeKategorie; "2."); "2"; @Contains (iTeKategorie; "3."); "3"; @Contains (iTeKategorie; "3."); "3"; @Contains (iTeKategorie; "4."); "4"; "");

Möglicherweise beginnt die Kategorie mit der Zahl, dann wäre es einfacher so

_k := @Left (iTeKategorie; 1)

oder

_k := @Left (iTeKategorie; ".")

Für die Mitgliedschaft würde ich mir auch noch einen Wert ermitteln

_m := @If (isMitglied; "1"; "0");

Danach kannst Du diese Werte zusammenfassen und damit wesentlich einfacher rechnen

_km := _k + _m;

@If (_km = "11"; "10 €"; _km = "10"; "20 €"; ...


da Nichtmitglieder anscheinend immer 10 € mehr bezahlen, ließe sich das auch noch anders in die Formel einbauen, indem am Ende nur einmalig die 10 € aufgeschlagen werden, falls kein Mitglied.

Die "schöne" Formulierung solcher Mehrfachbedingung ist prinzipiell nicht von der Sprache abhängig, auch in Script kann man das krautig schreiben.


Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: thkn777 am 01.10.15 - 13:20:28
Mi­ni­mal­in­va­siv an Deinem ursprünglichen Code geändert:

Code
x := @If(iTeKategorie!="" & @Contains(iTeKategorie;"1.") & isMitglied ; "10 € / 1. Jahr"; "n.b.");
x := @If(x="n.b." & iTeKategorie!="" & @Contains(iTeKategorie;"1.") & !isMitglied ; "20 € / 1. Jahr"; x);
x := @If(x="n.b." & iTeKategorie!="" & @Contains(iTeKategorie;"2.") & isMitglied ; "20 € / 1. Jahr"; x);
...
x := @If(x="n.b." & iTeKategorie!="" & @Contains(iTeKategorie;"4.") & !isMitglied ; "70 € / 1. Jahr"; x);
x

Das ist zwar nicht "verschachtelt" in dem Sinne, geht die Möglichkeiten aber - so wie von Dir geplant - der Reihe nach durch. Die einzelnen Abfragen schleppen "n.b." als (Zwischen-)Wert für x solange mit, bis ein Wert ermittelt werden kann. Oder bis zum bitteren Ende.

Ansonsten das, was tks vorschlug: einfach so machen, wie in der Designer-Hilfe steht, ich finde das jetzt nicht wirklich schlimm:

Code
@If(
	iTeKategorie!="" & @Contains(iTeKategorie;"1.") & isMitglied ; "10 € / 1. Jahr"; 
	iTeKategorie!="" & @Contains(iTeKategorie;"1.") & !isMitglied ; "20 € / 1. Jahr";
	iTeKategorie!="" & @Contains(iTeKategorie;"2.") & isMitglied ; "20 € / 1. Jahr";
	...
	iTeKategorie!="" & @Contains(iTeKategorie;"4.") & !isMitglied ; "70 € / 1. Jahr";
	"n.b."
);

Was genau Du unter elegant verstehst, weiß ich nicht. Gute Planung und ein sinnvolles Vorgehen beim Prüfen und Ermitteln derartiger Werte ist aber eine gute Idee und kommt nicht nur der Lesbarkeit des Codes sondern auch der Performance zugute. Ideen dazu hat ja schon Peter geäußert.

Ich wünsche viel Erfolg.
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: Bastel123 am 01.10.15 - 13:34:14
Noch ein Hinweis:

X:= @If(iTeKategorie!="" & @Contains(iTeKategorie;"1.") & isMitglied ; "10 € / 1. Jahr"; "n.b.1");
X:= @If(iTeKategorie!="" & @Contains(iTeKategorie;"1.") & !isMitglied ; "20 € / 1. Jahr"; "n.b.2");
etc.

geht durch alle @IF-Formeln, d.h ich kann den Wert auch "überschreiben", der letzte hat gewonnen.

X:= @If(
      iTeKategorie!="" & @Contains(iTeKategorie;"1.") & isMitglied ; "10 € / 1. Jahr"; "n.b.1";
      iTeKategorie!="" & @Contains(iTeKategorie;"1.") & !isMitglied ; "20 € / 1. Jahr"; "n.b.2");
      "n.b.?"
      )

bricht nach der ersten gültigen Formel ab, d. h. der erste gewinnt.

Da stolpert man schon mal drüber  >:(

Sebastian
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: thkn777 am 01.10.15 - 14:55:21
Noch ein Hinweis:

X:= @If(iTeKategorie!="" & @Contains(iTeKategorie;"1.") & isMitglied ; "10 € / 1. Jahr"; "n.b.1");
X:= @If(iTeKategorie!="" & @Contains(iTeKategorie;"1.") & !isMitglied ; "20 € / 1. Jahr"; "n.b.2");
etc.

geht durch alle @IF-Formeln, d.h ich kann den Wert auch "überschreiben", der letzte hat gewonnen.

Stimmt. Genau DAS ist ja das ursprüngliche Problem von buzi, das man durch das einfache Voranstellen von "X:=" in jeder Zeile auch nicht lösen kann.

Zitat
X:= @If(
      iTeKategorie!="" & @Contains(iTeKategorie;"1.") & isMitglied ; "10 € / 1. Jahr"; "n.b.1";
      iTeKategorie!="" & @Contains(iTeKategorie;"1.") & !isMitglied ; "20 € / 1. Jahr"; "n.b.2");
      "n.b.?"
      )

bricht nach der ersten gültigen Formel ab, d. h. der erste gewinnt.
Da stolpert man schon mal drüber  >:(
Sebastian

Ich kann mir nicht vorstellen, wie diese Formel überhaupt sinnvoll funktionieren soll.

Zusammenfassung:  ???
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: Andrew Harder am 01.10.15 - 16:02:36
Man kann auch einfach doppelte Abfragen vermeiden, das spart Platz und ist damit lesbarer.

Also so etwa in der Art:
Code
@If (iTeKategorie = ""; @Return (""); "");
	
@If(isMitglied = @True;
	@If(
		@Contains(iTeKategorie;"1."); "10 € / 1. Jahr";
		@Contains(iTeKategorie;"2."); "20 € / 1. Jahr";
		@Contains(iTeKategorie;"3."); "40 € / 1. Jahr";
		@Contains(iTeKategorie;"4."); "60 € / 1. Jahr";
		"value for member not found")
	;
	@If(
		@Contains(iTeKategorie;"1."); "20 € / 1. Jahr";
		@Contains(iTeKategorie;"2."); "30 € / 1. Jahr";
		@Contains(iTeKategorie;"3."); "50 € / 1. Jahr";
		@Contains(iTeKategorie;"4."); "70 € / 1. Jahr";
		"value for non-member not found")
)





Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: Tode am 01.10.15 - 17:58:22
also ich persönlich würde ja mit Zahlen arbeiten und dann den Text ganz am Ende ergänzen. Wenn die Logik so ist, wie sie sich darstellt, dann wäre mein Code:
Code
_isMitglied := @IsMember("Verband B"; values);

REM "Abbrechen, wenn Kategorie leer";
@If( iTeKategorie = "" ; @Return( "" ) ; "" );
_nr := @TextToNumber( @Left( iTeKategorie ; "." ) );

REM "Abbrechen, wenn die am Anfang der Kategorie keine Zahl steht";
@If( @IsError( _nr ) ; @Return( "" ) ; "" );

REM "Rechnung: Kategorie * 10 + 10 € für Nichtmitglieder";
_amount := _nr * 10 + @If( _isMitglied ; 0 ; 10 );

REM "Text zurückgeben";
@Text( _amount ) + " € / 1. Jahr"


So ganz nebenbei würde ich den Betrag komplett als Zahl in einem eigenen Feld speichern, und den Text dann einfach auf das Feld beziehen... wer weiß, wann man den Betrag mal irgendwo braucht (Fiktive Anforderung: "Kannst Du uns zeigen, wie viel Euro das insgesamt sind?" )
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: Peter Klett am 02.10.15 - 09:07:36
Hallo Torsten,

das passt fast, nur ist die Beziehung zwischen Kategorienummer und Betrag nicht so linear. Mit einer kleinen Ergänzung geht das aber. Und um pingelig zu sein, könnte man die ersten beiden Zeilen weglassen, da _nr auch bei leerer Kategorie keine Zahl wird

_isMitglied := @IsMember("Verband B"; values);

REM "Abbrechen, wenn Kategorie leer";
@If( iTeKategorie = "" ; @Return( "" ) ; "" );
_nr := @TextToNumber( @Left( iTeKategorie ; "." ) );

REM "Abbrechen, wenn am Anfang der Kategorie keine Zahl steht";
@If( @IsError( _nr ) ; @Return( "" ) ; "" );

REM "Preis der Kategorie";
_preis := @Select (_nr; 10; 20; 40; 60; -1);
@If (_preis < 0; @Return (""); "");

REM "Rechnung: _preis + 10 € für Nichtmitglieder";
_amount := _preis + @If( _isMitglied ; 0 ; 10 );

REM "Text zurückgeben";
@Text( _amount ) + " € / 1. Jahr"

Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: buzi am 07.10.15 - 12:17:33
Hallo zusammen,

danke für die zahlreichen Ideen und Hilfestellungen. Die Lösung von Torsten optimiert von Peter finde ich am "elegantesten"! Mit elegant meinte ich wenig Zeilen, keine redundante Formulierung und wenig Fehleranfälligkeit. Allerdings funktioniert bei mir die Funktion @TextToNumber nicht, sie gibt immer leer zurück. Wenn ich debugge, kann die iTeKategorie = "1. XXXX" sein, @Left macht's noch richtig, bringt die 1 zurück, aber @TextToNumber bringt "" zurück. Wen ich die Beschreibung von @TextToNumber richtig verstehe, müsste es in dem Fall ja sogar ohne @Left gehen aber das tut auch nicht...
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: Peter Klett am 07.10.15 - 12:38:34
Also dieser Testagent funktioniert (mit Berechnung, um zu sehen, dass es wirklich als Zahl interpretiert wird

_kat := "2. XXX";
_nr := @TextToNumber (@Left (_kat; "."));
@Prompt ([Ok]; ""; @Text (_nr * 10));

Sind alle Klammern korrekt gesetzt?

Evtl. noch ein @Text mit einfügen, um sicherzustellen, dass in der Kategorie auch wirklich Text steht (wüsste aber nicht, was es sonst sein sollte)

_nr := @TextToNumber (@Text (@Left (iTeKategorie; ".")));
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: Tode am 07.10.15 - 13:25:32
ACHTUNG: Hast Du wirklich "@TextToNumber" verwendet, oder die ähnlich klingende Funktion "@ToNumber" ? Bei @ToNumber hatte ich auch schon solche Phänomene...
Titel: Re: Verschachtelte @If-Abfragen
Beitrag von: buzi am 08.10.15 - 11:36:51
Also nach nochmal vielen Versuchen habe ich eine Lösung gefunden die funktioniert. Und zwar indem ich die @Left und @TextToNumber Aufrufe nicht verschachtle sondern jeweils in einer Variablen zuweise und dann weiter verwende. DANKE an alle Helfer!!!