Verehrte Gäste,
Ich benötige oft Daten aus verschiedenen Quellen und kombiniere sie. Da einige Abfragen viel Zeit in Anspruch nehmen können, habe ich ein Skript geschrieben, um mehrere Abfragen im Hintergrund zu starten und am Ende Daten zu kombinieren. Allerdings ist es nicht so einfach, den Auslöser zu finden, wann alle Abfragen abgeschlossen sind und wann mit der Verarbeitung der Ergebnisse begonnen werden soll. Im folgenden Skript habe ich zwei Ansätze getestet (Setzen des Flags durch „OnRunComplete“ und Testen auf Existenz der Ergebnistabelle). Sie funktionieren einigermaßen, aber ich denke, es gibt möglicherweise noch einen besseren Weg.
Ein Problem besteht darin, dass die Schleife endlos läuft, wenn eine der Abfragen keine Tabelle liefert. Ein weiteres Problem besteht darin, dass das Skript nicht wirklich kontrolliert, ob die Abfragen noch aktiv sind.
Das Skript ist derzeit auf einen Debug-Modus eingestellt, in dem keine Datenbankverbindung erforderlich ist, um dieses Verhalten zu testen.
Irgendwelche Verbesserungsvorschläge? Danke und BR
// Purpose:
// Start two database Queries (from different sources) in parallel and in background
// Wait for queries to finish
// and combine result
// JMP 15.0 Win10
//
// Details:
// After both queries are started in background
// a loop is started, that queries when both tables are existing
// In a previous version I worked with setting a flag ("OnRunComplete( B_QUERY_FINISHED = 1 )")
//
// Problem:
// A better solution would be to test, whether DB query is still running, but how?
// If the database query ends unexpectedly (by passing no table), the loop runs infinetely
Names Default To Here( 1 );
Clear Log();
// debug_mode: 0 - query from database / 1 - make table
// for database query the connectionstring must be correct
debug_mode = 1;
A_QUERY_FINISHED = 0;
B_QUERY_FINISHED = 0;
A_NAME = "A_Table";
B_NAME = "B_Table";
// new function to check whether background query is finished (= table does exists)
table_exists = Function( {table_name},
Names Default To Here( 1 );
table_lst = Get Data Table List();
table_name_lst = {};
For( i = 1, i <= N Items( table_lst ), i++,
Insert Into( table_name_lst, table_lst[i] << get name() )
);
Return( If( Contains( table_name_lst, table_name ) > 0, 1, 0 ) );
);
If( table_exists( A_NAME ) | table_exists( B_NAME ) ,
Throw( eval insert ("^A_NAME^ or ^B_NAME^ open! Please close " ))
);
// Define query
sql_str = "Select * from dual";
A_sql_str = sql_str;
B_sql_str = Substitute( sql_str, "A_scheme", "B_scheme" );
// Database query expression in backgroud
nsqlq_A_expr = Expr(
New SQL Query( Connection( "ODBC:DSN=XXX;DBQ=YYY;" ), QueryName( A_Name ), CustomSQL( A_sql_str ) ) <<
Run Background( OnRunComplete( A_QUERY_FINISHED = 1 ) )
);
nsqlq_B_expr = Expr(
New SQL Query( Connection( "ODBC:DSN=ZZZ;DBQ=AAA;" ), QueryName( B_Name ), CustomSQL( B_sql_str ) ) <<
Run Background( OnRunComplete( B_QUERY_FINISHED = 1 ) )
);
// Create table expression for Debugging
A_expr = Expr(
New Table( "A_Table", Add Rows( 1 ), Compress File When Saved( 1 ), New Column( "DUMMY", Character, "Nominal", Set Values( {"X"} ) ) )
);
B_expr = Expr(
New Table( "B_Table", Add Rows( 1 ), Compress File When Saved( 1 ), New Column( "DUMMY", Character, "Nominal", Set Values( {"X"} ) ) )
);
// start queries only in case of no debug_mode
If( debug_mode == 0,
Eval( nsqlq_A_expr );
Eval( nsqlq_B_expr );
);
start_time = Tick Seconds();
timestep = 1;
While( (table_exists( A_NAME ) & table_exists( B_NAME )) != 1,
Wait( timestep );
time_running = Round( Tick Seconds() - start_time, 0 );
Print( "waiting " || Char( time_running ) );
Show( table_exists( A_NAME ) );
Show( table_exists( B_NAME ) );
// For debugging only: create Table A after 5 seconds and Table B after 10 seconds
If( debug_mode == 1,
If( time_running > 5 & !table_exists( A_NAME ),
Eval( A_expr )
);
If( time_running > 10 & !table_exists( B_NAME ),
Eval( B_expr )
);
);
);
Wait( 1 );
Print( "Queries Finished" );
end_time = Tick Seconds();
Print( "Duration: " || Char( Round( end_time - start_time ) ) );
// concatenate
Try( Data Table( A_Name ) << Concatenate( Data Table( B_Name ), Append to first table ), Throw( Print( "Concatenate error" ) ) );
// Close( Data Table( B_Name ), nosave );
Data Table( A_Name )<< set name("Result Table");
Print( "Concatenating finished, script end " );Ich glaube nicht, dass ich das gleiche Problem hatte. Wenn Sie weiterhin Probleme haben, können Sie die Protokollausgabe mit dem Fehler posten, oder wenn Sie ihn beheben können, können Sie mir dann mitteilen, wie ich das Beispielskript aktualisieren kann?
Es gibt eine ODBC-Einstellung in den Einstellungen, die bei mir zu einem ähnlichen Fehlverhalten geführt hat. Wenn die Option „Abfragen nach Möglichkeit im Hintergrund ausführen“ aktiviert ist, deaktivieren Sie sie und versuchen Sie es erneut mit dem Skript. Ich denke, dass man dabei einen Kompromiss zwischen Geschwindigkeit und Stabilität eingehen muss, aber es lohnt sich, damit zu experimentieren, falls Sie es noch nicht getan haben.

Danke @ich h Ihre Lösung ist schön und gut programmiert, daher werde ich versuchen, damit zu arbeiten.
Bei einem ersten Test habe ich immer noch ein Timing-Problem gesehen (vermutlich), weil eine Referenz (noch) nicht gültig war.
Das Einführen einer Wartezeit von mehreren Sekunden in der Anweisung „onRunComplete“ hat dann funktioniert, ist aber nicht die Lösung.
Ich denke, das ist der Grund, warum ich früher beschlossen habe, verfügbare Tabellen abzufragen, bevor ich darauf verweise. Ich werde es weiter testen.