Le #GlobalSummit est le lieu idéal pour accélérer votre développement, en rencontrant InterSystems et son écosystème.
- Se connecter pour publier des commentaires
Le #GlobalSummit est le lieu idéal pour accélérer votre développement, en rencontrant InterSystems et son écosystème.
Merci @Eduard Lebedyuk et @Lorenzo Scalese pour cette information très utile ![]()
Sous Mac, l'accès aux "snippets" (ou extraits) se fait depuis Code > Règlages > Configurer les extraits de l'utilisateur
Standard vs. Norme
Si vous voulez une norme, il faut prendre les profils français créés par l’ANS par exemple.
Les profils permettent de normaliser le standard FHIR pour le rendre beaucoup plus contraignant." Luc
FHIR pour les développeurs
C’est vraiment sur la partie modélisation de la données de santé que FHIR est une révolution." Luc
"Clairement il n'y a pas photo entre HL7 V2 et HL7 FHIR. Avec le FHIR je me retrouve dans ma zone de confort de développeur en informatique industrielle, avec des API standardisées, au format JSON, avec des grappes d'objet ; c'est une révolution pour un développeur." Guillaume
Cas d'Usage
Le plus gros cas d’usage, que l’on attend depuis des années, c’est la communication ville-hôpital. C’est de pouvoir partir avec son dossier médical quand on déménage." Luc
FHIR est le Web 3.0 des données de santé
Avec FHIR, moi j’ai un rêve, c’est que mon dossier patient soit stocké sur mon téléphone, pour que quand je voyage, quand je déménage, quand j’ai une consultation chez mon médecin traitant ou à l’hôpital, j’autorise le professionnel de santé à accéder à mon dossier, pour qu’il amende mon dossier et que je le récupère. » Guillaume
Entrepôts de Données de Santé (EDS)
« La grande différence entre l’OMOP et le FHIR réside dans le fait qu’OMOP est à la base orienté stockage des données médicales avec un modèle de données travaillant sur les couches basses alors que FHIR est un standard à la base d’échanges et d’interopérabilité sur les couches hautes. » Guillaume
OMOP
« FHIR stocke les données au format documentaire, ce qui ne facilite pas les recherches dynamiques (ex: en SQL), à l’inverse de l’OMOP dont le format des données est basé sur un modèle relationnel, typique des requêtes exprimées en langage SQL. InterSystems rompt cette barrière en permettant de projeter les données FHIR en relationnel, sans duplication des données, et donc de les ouvrir à de la recherche médicale. » Guillaume
CQL
« Le gros bénéfice, c’est qu’avec le CQL et le FHIR, les règles deviennent portables ; on n’a plus besoin de regrouper toutes les règles et les données au même endroit ; on à juste à répliquer les règles pour les appliquer sur différents entrepôts de données, pour ensuite regrouper les résultats. » Guillaume
FHIR SQL Builder
Le FHIR® SQL Builder, ou Builder, est un outil de projection sophistiqué utilisé pour créer des schémas SQL personnalisés à l'aide de données dans un référentiel FHIR sans déplacer ni dupliquer les données vers un référentiel SQL distinct. Le Builder est conçu spécifiquement pour fonctionner avec les référentiels FHIR et les bases de données multimodèles dans les produits InterSystems.
L'objectif du Builder est de permettre aux analystes de données et aux développeurs de Business Intelligence de travailler avec FHIR à l'aide d'outils analytiques familiers, sans avoir à apprendre une nouvelle syntaxe de requête. Les données FHIR sont codées dans un graphe orienté complexe et ne peuvent pas être interrogées à l'aide de la syntaxe SQL standard. Un langage de requête basé sur des graphes, FHIRPath, est conçu pour interroger les données FHIR, mais il n'est pas relationnel. En permettant à un gestionnaire de données de créer une projection SQL personnalisée de son référentiel FHIR, à l'aide de tables, de colonnes et d'index, le générateur permet aux analystes de données d'interroger les données FHIR sans la complexité de l'apprentissage de FHIRPath ou de la syntaxe de recherche FHIR.
Fyrstain compte à ce jour 4 certifiés FHIR, ce qui est remarquable puisque cela représente 50% des certifiés en France.
.png)
Bonjour @lilian taroua
pour avoir une traduction de la doc en ligne, je vous conseille d'ajouter une extension (ex: Chrome Google Traduction).
Le résultat n'est pas parfait (Traduttore, traditore 🤔) mais permet quand même de répondre en partie au besoin assez rapidement et de manière efficace.
Exemple ci-dessous :
.png)
Bonjour @lilian taroua,
s'il y a des points particuliers que vous souhaitez aborder dans un premier temps, merci de nous les indiquer pour qu'on puisse vous répondre plus précisément.
Bonjour,
vous pouvez aussi utiliser une méthode "low-code" en utilisant le langage DTL avec l'action REMOVE
utils.HL7.transfo.removeSegment
Class utils.HL7.transfo.removeSegment Extends Ens.DataTransformDTL [ DependsOn = EnsLib.HL7.Message ]
{
Parameter IGNOREMISSINGSOURCE = 0;
Parameter REPORTERRORS = 1;
Parameter TREATEMPTYREPEATINGFIELDASNULL = 0;
XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ]
{
<transform sourceClass='EnsLib.HL7.Message' targetClass='EnsLib.HL7.Message' sourceDocType='2.6:ADT_A01' targetDocType='2.6:ADT_A01' create='copy' language='objectscript' >
<assign value='' property='target.{EVN}' action='remove' />
<assign value='' property='target.{DG1()}' action='remove' />
</transform>
}
}.png)
.png)
Faire la modification depuis la classe %SYSTEM.CSP en utilisant $system.CSP.SetConfig:
CSS>d $system.CSP.DisplayConfig()
...
CSS>w $system.CSP.GetConfig("DefaultPasswordChangePage")
%CSP.PasswordChange.cls
CSS>d $system.CSP.SetConfig("DefaultPasswordChangePage","CSS.CSP.ChangePassword.cls")
CSS>w $system.CSP.GetConfig("DefaultPasswordChangePage")
CSS.CSP.ChangePassword.clsBonjour @Taher C,
je te suggère de créer des API REST dans IRIS et de les consommer depuis PowerApps/PowerAutomate.
Tu trouveras ici un exemple de comment envoyer une requête http depuis PowerAutomate :
https://www.spguides.com/rest-api-in-power-automate/
NB : Hubic est le nom historique du projet chez CFAO, qui n'a pas d'équivalence avec InterSystems Ensemble ni IRIS 😉
La réponse parfaite avec l'API appropriée à utiliser a été donnée par @Vitaliy Serdtsev
USER>zn "%sys"
%SYS>w ##class(SYS.Database).%OpenId("/is/iris/mgr/irisaudit").Size
11
%SYS>w ##class(%SYS.Audit).Erase(1)
1
%SYS>w ##class(SYS.Database).%OpenId("/is/iris/mgr/irisaudit").Size
1Avec dans le messages.log :
08/24/23-17:31:00:649 (23676) 0 [Database.FullExpansion] Expansion completed for database /is/iris/mgr/irisaudit/. Expanded by 10 MB. 08/24/23-17:33:38:885 (48001) 0 [Generic.Event] Dismounted database /is/iris/mgr/irisaudit/ (SFN 4) 08/24/23-17:33:39:955 (48001) 0 [Database.MountedRW] Mounted database /is/iris/mgr/irisaudit/ (SFN 4) read-write.
.png)
La solution consiste à utiliser les filtres Schémas / Utilisateurs :
.png)
En ajoutant '%' dans les schémas / utilisateurs à exclure :
.png)
En fait, exclure tous les schémas '%' ne fonctionne pas très bien : avec cette option tous les noms de schémas sont masqués et quand on veut voir les données, les requêtes échouent du fait que toutes les tables sont considérées comme appartenant au schema par défaut SQLUser.
La syntax correcte à utiliser pour exclure les schémas système est :
\%*
.png)
Avec embedded Python, vous pouvez avoir un code assez simple en utilisant pandas :
/// Convert an Excel file to a CSV file
ClassMethod XLStoCSV(source As %String = "/data/sample.xlsx") As %Status [ Language = python ]
{
import pandas as pd
read_file = pd.read_excel(source)
read_file.to_csv(source+'.csv', index = None, header=True)
}
Merci @Iryna Mykhailova pour ce brillant article !
Très clair et intelligemment présenté.
NB : pour le stockage orienté colonne indiqué au niveau de la table via l'instruction WITH STORAGETYPE = COLUMNAR , il est à noter qu'IRIS se laisse la liberté de choisir pour vous le stockage le plus communément optimal (en ligne ou en colonne), en fonction des types de données.
Exemple :
l'instruction suivante :
CREATE TABLE a.addressV1 (
city varchar(50),
zip varchar(15),
country varchar(15)
)
WITH STORAGETYPE = COLUMNAR
Ne créera aucun stockage orienté colonne, lié au risque de données trop disparates, du fait du nombre de caractères autorisés dans chaque colonne (15 ou 50) :
Class a.addressV1 Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {_SYSTEM}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = addressV1 ]
{
Property city As %Library.String(COLLATION = "EXACT", MAXLEN = 50, STORAGEDEFAULT = "ROW") [ SqlColumnNumber = 2 ];
Property zip As %Library.String(COLLATION = "EXACT", MAXLEN = 15, STORAGEDEFAULT = "ROW") [ SqlColumnNumber = 3 ];
Property country As %Library.String(COLLATION = "EXACT", MAXLEN = 15, STORAGEDEFAULT = "ROW") [ SqlColumnNumber = 4 ];
Parameter STORAGEDEFAULT = "columnar";
Parameter USEEXTENTSET = 1;
alors que l'exemple donné dans l'article, retient bien une colonne (et une seule) en stockage orienté colonne, puisqu'ayant seulement 5 caractères autorisés pour la colonne zip.
CREATE TABLE a.addressV2 (
city varchar(50),
zip varchar(5),
country varchar(15)
)
WITH STORAGETYPE = COLUMNAR
Class a.addressV2 Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {_SYSTEM}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = addressV2 ]
{
Property city As %Library.String(COLLATION = "EXACT", MAXLEN = 50, STORAGEDEFAULT = "ROW") [ SqlColumnNumber = 2 ];
Property zip As %Library.String(COLLATION = "EXACT", MAXLEN = 5) [ SqlColumnNumber = 3 ];
Property country As %Library.String(COLLATION = "EXACT", MAXLEN = 15, STORAGEDEFAULT = "ROW") [ SqlColumnNumber = 4 ];
Parameter STORAGEDEFAULT = "columnar";
Parameter USEEXTENTSET = 1;
Pour activer l'ensemble des événements d'AUDIT système, il suffit d'exécuter la requête SQL suivante depuis l'espace de noms %SYS :
update security.events set enabled=1 where flags = 1
exemple :
set tRes = ##class(%SQL.Statement).%ExecDirect(,"update security.events set enabled=1 where flags = 1")
if tRes.%SQLCODE=0 {
set ^["USER"]TRACE("%SYS Security.Events")=tRes.%ROWCOUNT_" successfully enabled"
} else {
set ^["USER"]TRACE("%SYS Security.Events")=tRes.%Message_" SQLCODE:"_tRes.%SQLCODE
}
Le moyen le plus simple de toujours rester dans le siècle en cours est :
$ZDATEH("26/05/23",4,,6)Il suffit d'utiliser yearopt = 6 pour obtenir toutes les dates qui n'ont que 2 chiffres dans le siècle courant.
w $zdt($ZDATEH("26/05/23",4,,6),3)
2023-05-26
w $zdt($ZDATEH("26/05/1923",4,,6),3)
1923-05-26Bonjour @Yuri Marx,
en le tout premier sujet, je mettrai en tête de liste :
0. meilleures performances
Cela peut paraître évident, mais IRIS est **vraiment** plus rapide que Caché.
.png)
Et cette diapositive date de plus de 2 ans...
Bonjour @yurimarx Marx,
et aujourd'hui, vous pouvez ajouter à cette liste :
Bonjour Franck,
une autre façon consiste à définir un mapping utilisant le SQLStorage (comme nous avions commence à l'explorer ensemble).
Même si Lorenzo t'a déjà donné la solution avec $Query, à toute fin utile pour d'autres cas, je t'invite à consulter les articles de @Brendan Bannon
Bonjour @Franck Hanotin
en utilisant un paramètre, tu peux utiliser le même code sur plusieurs globales :
Class dc.axiell
{
Query data(globalName As %String) As %Query(ROWSPEC = "key1:%String,key2:%String,key3:%String,key4:%String,key5:%String,key6:%String,datavalue:%String") [ SqlProc ]
{
}
ClassMethod dataExecute(ByRef qHandle As %Binary, globalName As %String) As %Status
{
Set qHandle("node") = globalName
Quit $$$OK
}
ClassMethod dataFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Boolean) As %Status [ PlaceAfter = dataExecute ]
{
Set sc = $$$OK
Set qHandle("node") = $Query(@qHandle("node"), 1, data)
If qHandle("node") = "" Set Row = "", AtEnd = $$$YES Quit $$$OK
; feeds the key x fields based on the subscripts of the global
For i=1:1:$QLength(qHandle("node")) Set $List(Row, i) = $QSubscript(qHandle("node"), i)
If i < 6 { ; if we do not have 6 subscripts, we feed the rest with an empty string
For j = i+1:1:6 Set $List(Row, j) = ""
}
Set $List(Row, 7) = data, AtEnd = $$$NO
Quit sc
}
ClassMethod dataClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = dataExecute ]
{
Kill qHandle Quit $$$OK
}
/// just for some test data
ClassMethod set() As %Status
{
set sc = $$$OK
kill ^AFO
s ^AFO("Site","Ville")="66722,3743"
s ^AFO("Site","Ville","111BB","OBT")=",MMM,XXX,"
s ^AFO("Site","Ville","111OW","OBT")=",XXX,MMM,"
s ^AFO("Site","Ville","AANVRBIBS","zzz") = "1^^1"
s ^AFO("Site","Ville","AANVRBIBS","zzz","*","dut") = "*afhalen waar gevonden"
s ^AFO("Site","Ville","AANVRBIBS","zzz","*","eng") = "*Pickup where found"
s ^AFO("Site","Ville","AANVRBIBS","zzz","*","fre") = "*Lieu où trouvé"
kill ^AAA
s ^AAA(1,2)="66722,3743"
s ^AAA(1,2,"3","4") =",MMM,XXX,"
s ^AAA(1,2,"4","5") =",XXX,MMM,"
s ^AAA(1,2,3,4) = "1^^1"
s ^AAA(1,2,3,4,"*","dut") = "*afhalen waar gevonden"
s ^AAA(1,2,3,4,"*","eng") = "*Pickup where found"
s ^AAA(1,2,3,4,"*","fre") = "*Lieu où trouvé"
kill ^BBB
s ^BBB("en") ="Hello"
s ^BBB("en","sub") ="World"
s ^BBB(1,2,3) ="BBB"
s ^BBB(1,2,3,4) = "BBB^^BBB"
kill ^CCC
s ^CCC("fr") ="Bonjour"
s ^CCC("fr","sub") ="la Communauté"
s ^CCC(1,2,3,"QUATRE","CINQ","SIX") ="6"
s ^CCC(1,2,3,4,"5","6") ="6"
s ^CCC("UN","DEUX","TROIS") ="3"
return sc
}
}
IRISAPP>:sql
SQL Command Line Shell
----------------------------------------------------
The command prefix is currently set to: <<nothing>>.
Enter <command>, 'q' to quit, '?' for help.
[SQL]IRISAPP>>select * from dc.axiell_data('^AFO')
34. select * from dc.axiell_data('^AFO')
key1 key2 key3 key4 key5 key6 datavalue
Site Ville 66722,3743
Site Ville 111BB OBT ,MMM,XXX,
Site Ville 111OW OBT ,XXX,MMM,
Site Ville AANVRBIBS zzz 1^^1
Site Ville AANVRBIBS zzz * dut *afhalen waar gevonden
Site Ville AANVRBIBS zzz * eng *Pickup where found
Site Ville AANVRBIBS zzz * fre *Lieu où trouvé
7 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0003s/4/139/0ms
execute time(s)/globals/cmds/disk: 0.0023s/11/3,294/0ms
query class: %sqlcq.IRISAPP.cls59
---------------------------------------------------------------------------
[SQL]IRISAPP>>select * from dc.axiell_data('^AAA')
35. select * from dc.axiell_data('^AAA')
key1 key2 key3 key4 key5 key6 datavalue
1 2 66722,3743
1 2 3 4 1^^1
1 2 3 4 * dut *afhalen waar gevonden
1 2 3 4 * eng *Pickup where found
1 2 3 4 * fre *Lieu où trouvé
1 2 4 5 ,XXX,MMM,
6 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0002s/4/139/0ms
execute time(s)/globals/cmds/disk: 0.0014s/10/3,099/0ms
query class: %sqlcq.IRISAPP.cls59
---------------------------------------------------------------------------
[SQL]IRISAPP>>select * from dc.axiell_data('^BBB')
36. select * from dc.axiell_data('^BBB')
key1 key2 key3 key4 key5 key6 datavalue
1 2 3 BBB
1 2 3 4 BBB^^BBB
en Hello
en sub World
4 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0003s/4/139/0ms
execute time(s)/globals/cmds/disk: 0.0045s/8/2,702/0ms
query class: %sqlcq.IRISAPP.cls59
---------------------------------------------------------------------------
[SQL]IRISAPP>>select * from dc.axiell_data('^CCC')
37. select * from dc.axiell_data('^CCC')
key1 key2 key3 key4 key5 key6 datavalue
1 2 3 4 5 6 6
1 2 3 QUATRE CINQ SIX 6
UN DEUX TROIS 3
fr Bonjour
fr sub la Communauté
5 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0002s/4/139/0ms
execute time(s)/globals/cmds/disk: 0.0018s/9/2,899/0ms
query class: %sqlcq.IRISAPP.cls59
---------------------------------------------------------------------------
[SQL]IRISAPP>>q
IRISAPP>
@Alexander Koblov vient de me donner la solution.
La commande GRANT ... ON SCHEMA ... répond parfaitement au besoin.
GRANT SELECT ON SCHEMA data TO ROLE|USER
Et ce qui est cool, c'est que dès que votre utilisateur a reçu un GRANT sur un schéma, lorsque vous modifiez ensuite l'utilisateur dans le portail de gestion de la sécurité, vous pouvez voir dans l'onglet Tables SQL toutes les tables apparaître au fur et à mesure de leur création.
.png)
Cela fonctionne aussi pour tous les objets d'un namespace :
GRANT SELECT ON * TOROLE|USER
Oui, le GRANT on SCHEMA ou GRANT on * simplifie clairement la chose 😀
Cela fait partie du standard SQL mais on n'y pense pas d'emblée.
@Ben Spead a donné une première réponse en proposant d'utiliser Embedded Python :
Cela ressemble à un exemple classique d'exploitation de Python intégré dans IRIS pour utiliser le très grand nombre de bibliothèques Python qui font à peu près n'importe quoi :) Voici un article que j'ai trouvé lors d'une recherche rapide sur Google sur la façon de procéder en Python :
https://www.geeksforgeeks.org/convert-pdf-to-image-using-python/
Vous pouvez simplement exploiter les capacités Python d'InterSystems IRIS pour utiliser la façon dont ce problème a été résolu en Python !
Malheureusement, l'environnement de @Gilberto Alves n'est pas prêt à utiliser Embedded Python.