Chers tous,
J'ai souvent besoin de données provenant de différentes sources et je les combine. Comme certaines requêtes peuvent prendre beaucoup de temps, j'ai écrit un script pour lancer plusieurs requêtes en arrière-plan et combiner les données à la fin. Cependant, il n'est pas si simple de trouver le déclencheur, quand toutes les requêtes sont terminées et quand commencer le traitement des résultats. Dans le script ci-dessous, j'ai testé deux approches (définition de l'indicateur par "OnRunComplete" et test de l'existence d'une table de résultats). Ils fonctionnent assez bien, mais je pense qu'il existe peut-être un moyen encore meilleur.
Un problème est que la boucle s'exécutera à l'infini si l'une des requêtes ne fournit aucune table. Un autre problème est que le script ne contrôle pas vraiment si les requêtes sont toujours actives.
Le script est actuellement défini en mode débogage, où aucune connexion à la base de données n'est nécessaire pour tester ce comportement.
Des idées d'amélioration ? Merci et 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 " );Je ne pense pas avoir rencontré le même problème. Si vous continuez à rencontrer des problèmes, pouvez-vous publier le résultat du journal avec l'erreur ou, si vous pouvez le résoudre, pouvez-vous me faire savoir comment procéder afin que je puisse mettre à jour l'exemple de script ?
Il existe un paramètre ODBC dans les préférences qui a conduit à un mauvais comportement similaire pour moi. Si l'option "Exécuter les requêtes en arrière-plan si possible" est cochée, décochez-la et réessayez votre script. Je pense qu'il y a un compromis entre la vitesse et la stabilité en faisant cela, mais cela vaut la peine d'expérimenter si vous ne l'avez pas déjà fait.

Merci @ih pour votre solution, elle est sympa et bien programmée, je vais donc essayer de travailler avec.
Lors d'un premier test, j'ai encore constaté un problème de timing (je suppose), car une référence n'était (pas encore) valide.
L'introduction d'une attente de plusieurs secondes dans l'instruction "onRunComplete" a ensuite fonctionné, mais n'est pas la solution.
Je pense que c'est pourquoi j'ai décidé plus tôt d'interroger les tables disponibles avant de les référencer. Je vais le tester davantage.