搜索​​​​

清除过滤器
文章
Shanshan Yu · 七月 5, 2023

基于IntegratedML及Dashboard的数据分析应用

基于InterSystems的集成ML技术和Dashboard,根据上传的CSV文件自动生成相关预测和BI页面。前端和后端在Vue和Iris中完成,使用户可以通过简单的操作生成所需的数据预测和分析页面,并根据这些页面做出决策。 # ZPM 安装 zpm:USER>install IntegratedMLandDashboardSample # 部署流程 使用或创建新的命名空间 将代码导入相应的命名空间 在终端中执行: Do # # class (customizemashinelerningandaanalysis. Util. Tool) Deployment() 前端是Vue文件夹下的dist文件夹。在使用它之前,请打开dist-static config.js并修改后端服务器要使用的IP和端口。然后您需要将iframeUrl的测试修改为“Analysis”+后端使用的命名空间,例如“AnalysisUSER” 然后启动前端文件(可以将dist文件夹放在tomcat中开始使用) 访问地址为: Ip: port/dist # 如何使用 以women.csv为例 1.选择要上传的CSV文件,CSV文件名和数据列名不得包含空格等其他符号 2.填写需要预测的列名,如“高度” 3.单击“确定”按钮,等待界面返回 成功返回后,刷新当前页面,然后单击“模型列表”下的辅助选项。新生成的项目将出现 ① 填写完其他值后,点击②确定,在③处生成预测值 ④ 嵌入式虹膜仪表板显示以前导入CSV的一些数据 # 其他 CSV 展示 # 单元测试 Set ^UnitTestRoot=your modules dir +"\src"+namespace+"\integratedmlanddashboardsample\src" (such C:\InterSystems\HealthConnect\mgr\.modules\USER\integratedmlanddashboardsample\src) do ##class(%UnitTest.Manager).RunTest("UnitTests") #注意 由于页面上嵌入了iris的仪表板,如果您遇到无法正确显示的跨域问题,可以访问iris查看图表 非常棒的应用!那csv中的数据能不能是非数字呢?
文章
Tianyu wu · 三月 3, 2021

欢迎大家来给我们投票啦!

这是我们团队参加的第一届InterStstems编程竞赛! 快来看看投票给我们! 超额预订管理系统结合了酒店业的独特条件,例如房价,订购渠道,客户需求等。 本系统使用机器学习算法(例如:KNN / ES-RNN ...)来准确预测酒店的每日未入住和入住率,并进一步与收益结合以找到最佳的最大客房销售量,从而精准增加酒店的边际收益。 移步欣赏作品点击如下连接 https://github.com/BroadCastAir/hotel_api & https://github.com/BroadCastAir/Hotel_OverBooking_Sys 投票给我们点击: Check the related application on InterSystems Open Exchange 我们ISC 中国也想跟您聊一下合作事宜,请 @Jun.Qian 联系一下,谢谢! good! 很棒的应用! 非常棒!很好的应用!
公告
Nicky Zhu · 三月 30, 2021

2021年3月23日 - 提醒:HS2021-03,镜像Dejournaling的潜在数据完整性问题(HealthShare)

尊敬的HealthShare用户: 本帖是HealthShare HS2021-03提醒沟通流程的一部分,同样的信息也会以以下渠道分发: 邮件通知 HealthShare 用户 在 Product Alerts & Advisories 主页上通知 在 WRC Distribution Page InterSystems Documents主页上通知 提醒 产品版本和影响 风险等级 和评分 HS2021-03 -01:镜像Dejournaling的潜在数据完整性问题 这个问题会影响所有支持镜像的HealthShare产品和版本: HealthShare Unified Care Record/Information Exchange, Health Insight, and Patient Index version 15.02 and newer HealthShare Personal Community version 12.0 and newer HealthShare Provider Directory 2019.2, 2020.1 and 2020.2 HealthShare Health Connect and HSAP versions that support mirroring 2-低风险 (临床安全) 1-极低风险(隐私) 1-极低风险 (安全) 2-低风险 (运维) 如果您对本提醒有任何疑问,请联系 support@intersystems.com,并引述“HealthShare Alert HS2021-03”。
问题
xu hui · 六月 22, 2021

ERROR [HYT00] [Cache ODBC][State : HYT00][Native Code 450] [c:\windows\system32\inetsrv\w3wp.exe] Request timed out due to user timeout

我在用.net通过ODBC连接cache数据库,OdbcConnection connection = new OdbcConnection(dbConnection);connection.Open();打开链接时报这错,请教大佬们,这应该怎么解决吗?不胜感激! 您好!该问题请提交WRC服务 您可以登录网址:https://wrc.intersystems.com提交 第一个问题, 你是连本机还是远程?第2个问题, 你有没有测windows操作系统的cache odbc连接? 您好,非常感谢您的回复。我连接的是局域网内的其他远程服务器;我用同样的代码连接windows操作系统的DSN,是可以connection.Open();运行到这步并进行下去的。请问还有可能是什么原因吗?万分感谢@ 好的,初来乍到,不懂流程,抱歉。但我登录您所给的网址,提示 is not enabled for WRC login. If this is unexpected, please contact InterSystems Support.提交不了WRC服务
文章
Jingwei Wang · 六月 20, 2022

IRIS/HealthConnect 高可用机制 Mirror 的配置

安装Arbiter 为了将自动故障转移扩展到尽可能广泛的故障情况,InterSystems建议你为每个镜像配置一个仲裁机。 要充当仲裁者,系统必须有一个正在运行的ISCAgent进程。由于ISCAgent是与InterSystems IRIS一起安装的,任何承载一个或多个InterSystems IRIS实例的系统都符合这一要求,可以被配置为仲裁者而无需进一步准备;但是,承载一个或多个故障转移或DR异步镜像成员的系统不应该被配置为该镜像的仲裁者。 没有托管InterSystems IRIS实例的系统可以通过安装Arbiter方式的作为仲裁者。请从InterSystems公司下载适合你的仲裁者系统平台的ISCAgent安装包,然后,安装ISCAgent。 注意:Arbiter的版本要和InterSystems IRIS安装版本保持一致。 在Windows上安装Arbiter 在Windows系统上,只需执行安装文件,例如ISCAgent-2020.1.0.540.0-win_x64.exe。 在Linux上安装Arbiter [root@arbiterhost home]# gunzip ISCAgent-2020.1.0.540.0-lnxrhx64.tar.gz [root@arbiterhost home]# tar -xf ISCAgent-2020.1.0.540.0-lnxrhx64.tar [root@arbiterhost home]# ./ISCAgent/agentinstall 启动、停止、检查ISCAgent状态 systemctl start ISCAgent.service systemctl stop ISCAgent.service systemctl status ISCAgent.service 设置、终止开机自动启动ISCAgent sudo systemctl enable ISCAgent.service sudo systemctl disable ISCAgent.service 启动 ISCAgent 服务 在所有的服务器中(主机,备机,仲裁机),ISCAgent必须被配置为在系统启动时自动启动。 a. 进入管理工具——服务,选择ISCAgent,将启动类型改为自动。点启动ISCAgent。 b. Windows防火墙中允许ISCAgent TCP端口2188,同时新建出站、进站规则。允许web端口 52773,超级端口1972。 入站规则中运行文件和打印机共享(回显请求 - ICMPv4-In) 配置主failover成员(Primary failover成员) a. 进入Management Portal界面,选择菜单 系统管理 – 配置 – 镜像配置 – 创建镜像。如果选项为灰不可选,先点击 启动镜像服务,再选择 '服务已启用'。 b. 创建Mirror,输入相关信息并保存。 镜像信息部分 : 镜像名称(Mirror Name) : 有效的名称必须是1至15个字母数字字符;小写字母会自动替换为大写字母的对应物。 要求SSL/TLS (Use SSL/TLS): 指定是否要为镜像内的所有通信要求SSL/TLS安全(建议)。如果你选择了 "需要SSL/TLS",而实例还没有一个有效的SSL/TLS配置用于镜像,在完成这个程序之前,你可以直接点击设置SSL/TLS链接,在这个成员上创建所需的SSL/TLS配置。你也可以取消创建镜像程序,并浏览到SSL/TLS配置页面(系统>安全管理>SSL/TLS配置)。 使用仲裁器(Use Arbiter): 指定你是否要配置一个仲裁器(建议)。如果你选择使用仲裁器,你必须提供你想配置为仲裁器的系统的主机名或IP地址以及其ISCAgent进程使用的端口(默认为2188)。 使用虚拟IP(User Virtual IP):如果你选择使用虚拟IP,系统会提示你提供一个IP地址、无类别域间路由(CIDR)掩码和网络接口。 故障转移成员的压缩模式,异步成员的压缩模式 : 分别指定在从主站向备份和异步成员传输之前是否压缩日志数据,以及对每个成员使用哪种压缩类型;两者的默认设置都是 "系统选择",它优化了故障转移成员之间的响应时间以及主站和异步站之间的网络利用率。 一般使用默认设置。 Allow Paralle Dejournaling :确定哪种类型的镜像成员可以运行并行的Dejournal。Paralle Dejournaling允许多个作业在单个数据库中处理独立的globals,而不是只限于并行处理独立的数据库。 镜像故障转移成员信息: 镜像成员名:为你在这个系统上配置的故障转移成员指定一个名称(默认为系统主机名称和InterSystems IRIS实例名称的组合)。镜像成员名称不能包含空格、制表符或以这些标点符号 : [ ] # ; / * = ^ ~ ,字母字符在保存前会转换为大写字母。镜像成员名称的最大长度是32个字符。 超级服务器地址: 输入外部系统可用于与该故障转移成员通信的 IP 地址或主机名称。 代理端口: 输入此故障转移成员上 ISCAgent 的端口号,接受提示中提供的已安装代理的端口。 配置备failover成员(backup failover成员) 进入Management Portal界面,选择菜单 系统管理 – 配置 – 镜像配置 – 加入为故障转移。如果选项为灰不可选,先点击 启动镜像服务,再选择 '服务已启用'。 镜像名称:创建的镜像名称 其他系统上的代理地址: 输入您在配置第一个故障转移成员时指定的超级服务器地址。 代理端口 :输入您在配置第一个故障转移成员时指定的 ISCAgent 的端口。 InterSystems IRIS 实例名称 : 输入配置为第一个故障转移成员的InterSystems IRIS实例的名称。 配置异步镜像成员 选择 系统管理 – 配置 – 镜像设置 – 加入为异步。如果选项为灰不可选,先点击 启动镜像服务,再选择 '服务已启用'。 在‘加入为异步’页面填入创建的第一个镜像成员名称、地址、实例名称。 镜像名称:创建的镜像名称 故障转移系统的代理地址 :输入您在配置所选故障转移成员时指定的超级服务器地址。 代理端口 - 输入您为所选故障转移成员指定的 ISCAgent 端口。 InterSystems IRIS 实例名称 - 输入您配置为选定故障转移成员的 InterSystems IRIS 实例的名称。 选择合适的Async镜像成员类型 修改镜像设置 进入菜单 系统管理 – 配置 – 镜像配置 – 编辑镜像 可以修改设置的各个参数: 添加镜像数据库 创建一个镜像数据库 在主failover成员服务器上,选择系统管理– 配置 – 系统配置– 本地数据库 选择 新建数据库,按照提示输入数据库名称、存放数据库文件位置。注意在输入关于数据库的详情页面,镜像数据库? 选择 是。 在每一个failover成员服务器以及异步成员服务器按照上面步骤同样创建本地数据库。注意在输入关于数据库的详情中确保每一个成员的Mirror DB Name相同(本地的数据库名称可以不同)。 将已有数据库配置为镜像数据库 将主机已有数据库加入镜像 在主failover成员management port中,从菜单中选择 配置数据库 选中需要镜像的数据库,点击 添加到镜像 来添加需要mirror 的数据库 选择需要添加进入Mirror 的数据库并点击添加 此时从镜像监视器 中可以看到 镜像数据库 增加了我们刚才添加的数据库 数据库备份 对此主服务器的需要mirror 的数据库进行备份并获取备份文件,并拷贝至备机。执行备份可以通过management portal 运行实现。 management portal -> 系统管理 -> 配置-> 数据库备份 ->备份数据库列表 系统操作-> 备份 -> 完全备份列表 注意:这里需要关注主机本身journal 的保存时间,因为mirror 的同步机制是主机推journal 给备机,所以如果备份的时间为1月1 日零点,主机journal 保存时间为1天,备份需要2天,则中间1天的时间差所产生的数据是没有办法恢复的。 数据库备份恢复 在备Failover成员的%SYS 命名空间下使用^BACKUP routine, 将备份文件恢复至备机,则可在备机中看到恢复的数据库已只读方式被挂载 caught up 数据库 在备机上进入 系统操作 - 镜像监视器 ,可见备机的镜像有need activation 状态,点击Activate,结束后,下一步点击 catchup。 最终可见备机为 active,caught up 状态。 删除镜像配置 删除镜像配置必须按照下面顺序执行:删除异步成员,然后删除备份failover成员,最后删除主failover成员。 删除异步成员 进入菜单 系统管理 – 配置 – 镜像设置 – 编辑异步: 如果想要移除报表服务的异步成员,使用Leave mirror链接。 如果想要移除所有的链接异步成员以及相关配置,使用Remove Mirror Configuration按钮: 移除备failover成员 想要移除failover成员必须在%SYS命名空间下 执行^MIRROR routine。 a. 在 Terminal中切换到%SYS命名空间,执行d ^MIRROR b. 选择Mirror Configuration c. 选择Remove This Failover Member(如果在主failover服务器上操作则选择Remove Other Mirror Member) d. 按照提示操作,最后重启实例. 移除主failover成员 想要移除failover主成员必须在%SYS命名空间下 执行^MIRROR routine。 a. 在 Terminal中切换到%SYS命名空间,执行d ^MIRROR b. 选择Mirror Configuration c. 选择Remove This Failover Member d. 按照提示操作,最后重启实例. e. 选择Remove This Failover Member f. 按照提示操作,最后重启实例. 移除镜像数据库 从Async成员中移除数据库不会对failover成员的数据库有任何影响,但是如果从failover成员中移除数据库,也必须从其他failover成员以及Async成员中移除相应的数据库。想要从镜像配置中整体移除数据库需要遵循下面的顺序:主Primary failover成员 -> 备份Backup failover成员 -> Async成员。 a. 进入菜单 系统操作 – 镜像监视器 b. 在镜像数据库中点击 移除 断开连接/开始连接镜像成员 可以临时断开备failover镜像成员或者Async镜像成员。 进入菜单 系统操作 – 镜像监视器 选择 在这个成员上终止镜像 在虚拟环境下配置镜像操作 在虚拟环境下进行镜像配置,同时建议进行下面配置以提高可靠性: · 应该为每一个failover成员进行虚拟主机(virtual host)的配置,保证每一个failover成员不会指向同一个物理上的host。 · 为了避免单一指向存储的损坏,每一个failover成员上Caché实例使用的存储应该固定分配到相互隔离的磁盘阵列或者磁盘组中。 · 有些虚拟架构下自动执行的操作,比如虚拟主机迁移到备用存储,可能造成failover成员间的短暂连接中断。如果在记录中竟让发现类似这样的中断警告,可以进入修改镜像配置的页面,在Advanced Mirror Settings下适当提高QoS Timeout设置的时间。 · 当进行计划维护操作(比如快照snapshot管理)时,会引起镜像成员中的连接中断,可以在备机的Mirror Monitor页面选择Stop Mirror on this server,临时断开备份backup成员,以避免相应的mirror警告信息。 · 在配置Mirror主备服务器中,不建议使用systemctl 设置开机自动启动IRIS。因为在主备切换过程中,如果使用systemd启动关闭IRIS不是成对出现,或者使用iris start/stop instance 不是成对出现,则有可能出现不可预知错误。 配置成功状态 主机状态: 备机状态:
文章
Claire Zheng · 三月 1, 2021

欢迎为中文社区参赛者投票!

本周进入 InterSystems 编程大奖赛 的投票时间! 此次中国有多位参赛者,我们将其项目罗列在此,欢迎投票! 项目一: Dictionary comparison scheme of cache database Author: Weiwei Yang 概述:现场需要将各个科室部门内的数据统一汇总到医院总部,但是汇总后发现各个科室使用的字典并不统一,需要将表中的现存的字典统一更换为医院制定字典。例如:A科室中人员的性别字典使用0/1/2表示各种性别,B科室中性别字典使用F/M/O表示各种性别,但是现在医院要求所有性别字典保存Female/Male/Other性别信息,此时就需要替换原有的性别字典为新用字典。当初,此处只是列举了一个使用场景,未来有多个需要对照字典的工作都可以考虑此项目的设计和实现思想。 点击投票 项目二: HealthInfoQueryLayer Author: Botai Zhang 基于Intersystems IRIS平台整合医院信息查询业务解决方案 概述:随着医院信息化建设的逐步完善,医院子系统越来越多,系统间接口越来越多,同时接口费用不断增加,管理工作变得越来越复杂。其中,查询类业务接口根据业务类型分化,数量也是逐步递增,带来接口量大、开发工作繁重、代码冗余、维护困难等等问题。针对这一困境,我们基于Intersystems IRIS数据平台整合医院信息查询业务解决方案。该应用程序可通过配置完成查询业务接口实现,大大缩小开发、维护、实施等项目关键运转周期。 点击投票 项目三: Integration scheme for heterogeneous messages in heterogeneous systems Author: Deming Xu 异构系统和异构消息的集成方案 概述:随着现代医院建设的信息化程度越来越高,对接的子系统数量也越来越多,系统的架构、接口类型、消息结构越来越复杂,对医院系统之间的信息传递造成很大不便。为了解决该问题,我们采用HL7、XML等标准,使用Ensemble内置的数据转换工具(DT),将异构系统的接口进行标准化(通常引用Soap、REST、TCP/IP等标准协议),使得不同架构的系统,即时接口类型不同、消息模型不同,也能进行数据的传输。 关键词:HL7、XML、Settings、DataTransform、JDBC、SQL 点击投票 项目四: Create a unified hospital data extraction scheme based on IRIS for Health Author: Deming Xu 基于 IRIS for Health 创建医院数据统一提取方案 概述:随着医院信息化建设内容不断丰富,业务面覆盖越来越广,相关科研项目的数据需求也越来越多,医院对各个业务系统的数据管理提出了新的要求。由于科研项目背景多样,需求中的数据模型也不尽相同,各个系统的接口开发、接口管理、代码维护工作也变得越来越繁杂。针对这一困境,我们采用IRIS创建医院数据统一提取方案 。该应用程序提供一个公共的数据提取服务(BS),可通过配置完成获取多个不同数据源的接口开发(多个BO),大大缩小开发、维护、实施等成本。 点击投票 项目五: RESTFUL_API_For_Hotel_OverBooking_System Author: jingqi LIu Develop RESTFUL Data API in InterSystems IRIS Data Platform Development for Hotel Overbooking Management System. PS:The overbooking management system combines the unique conditions of the hotel, such as room prices, order channels, customer needs (etc...). System uses machine learning algorithms (such as: KNN/ES-RNN...) to accurately predict the daily no-show and occupancy rate of the hotel, and further combines with the revenue equation to find the best largest room sales volume, which can significantly increase the hotel marginal revenue. 这是一个在InterSystems IRIS中用ObjectScript构建的REST API应用的演示。它也有OPEN API规范,可以用Docker和VSCode开发,可以作为ZPM模块部署,可以作为Overbooking系统数据的REST api使用。 点击投票 Useful! 新用户投票前必读哦:如何成为社区活跃用户(Active user) 这几个医疗行业应用都非常不错,学习到很多! 欢迎为您喜欢的选手投票! 欢迎新加入的朋友们发言、评论、回复成为活跃用户后为中国参赛选手投票,每人可以投3票! @Hao.Wang @z.c @Zhaoying.Li @Neal.Wu @liu.yaquan @qu.qu @wang.wei @guo.meiya @yajing.xu @yue.li @权权.苏 @xiaohu.xiong @yadong.zhao @Yi.Han @Wen.Zhou @jie.zhang @张.恒 @guo.wenheng @Jing.Li3826 @迪.文 这个贴子很棒!完美的解决了我的问题! 欢迎新朋友,请大家发表内容时尽量在中文社区发表,多发表高质量内容,为中文社区多做贡献, 包括但不限于回答问题,撰写文章,贡献软件库、代码、工具等等,多谢支持! @young.zheng @an.xingqi2532 @jinhui.hu @wenyang.zhang @guoguo.wang @shikai.ren @chaolong.huang @yabin.duan @鹏飞.楚 @智辉.李 @shan.hu @Wendy.Wu 好的,谢谢 马上投票 发布完还要等24小时 你好,第一次发帖24小时后就可以投票吗 准备投票 是的 原来是这样,明白了 期望多一些应用,多多学习! 能够学习到具体的应用,很棒!👍 学习IRIS在国内多行业应用,棒👍 好的,谢谢! 感谢提醒,👍
文章
Johnny Wang · 十一月 21, 2021

适合工作的工具:我们聆听了医疗行业开发人员的声音

在医疗领域,开发创新可以挽救更多的生命。 这也是为什么我们更需要去倾听负责构建未来的人:开发人员。 他们需要什么工具才能更有效地使应用程序更加高效? 他们面对着什么样的障碍? InterSystems 不想去做无用的猜测,因此我们推动进行了一项研究,该研究综合了 200 名医疗行业开发者的反馈,深入了解了他们的最大需求。我们认为,这些研究结果为医疗单位和医疗技术公司提供了一个机会,可以帮助他们的开发团队为业务带来新机遇,同样也为临床医生和患者带来更光明的未来。 以下是三个关键要点: 1. 开发人员想要一个统一的医疗平台。 在接受本次研究采访的 200 名开发人员中,有88% 的受访者表示他们是医疗 IT 领域的专家或该领域的技术人员——他们都希望能有最好的、为他们的行业量身定制的开发工具。 这就是为什么一半的受访者将统一的、专注于医疗的数据平台列为购买新开发工具的关键原因。 一个合适的医疗行业开发平台应该包括互操作性/集成引擎、分析工具、面向医疗行业的自然语言处理功能、机器学习工具和 FHIR 服务器,以及其他组件。 如果一家公司能够提供一个包含所有上述组件的平台,那么超过 90% 的开发人员将对这项技术非常感兴趣。 2. 临床数据模型必不可少 近 90% 的开发人员表示,技术供应商提供的临床数据模型是必不可少的,如果按照 10 分制来统计,这个需求会达到8 分甚至更高。 来自 EHR 的临床数据被 60% 的开发人员列为最优先的一类。而其他数据还包括CRM、医疗设备、健康的社会决定因素、索赔、财务和运营的数据。 3. 健康数据是实现价值的最快途径 干净、健康的数据将高质量企业与其他企业区分开来。 在开发人员希望技术供应商提供更干净、更健康数据的大背景下,这次研究的受访者表示,选择能够提供最干净数据的平台尤为重要。 一站式医疗保健平台 根据该报告,一线开发人员及管理层都想要这样一个医疗保健数据平台: (1)专注于医疗IT行业 (2)可扩展性 (3)与现有的开发工具兼容 (4)安全 (5)便于使用 我们推动进行这项研究是为了帮助我们确定 InterSystems IRIS for Health™ 的发展方向,而这也是一个专门设计用于从医疗数据中提取价值的数据平台。 开发人员使用该平台、使用这些旨在满足现代医疗需求的、安全的工具来创建和扩展医疗应用程序。 我们对这次的研究结果感到鼓舞,我们也将继续专注以使平台变得更好! 医疗 IT 软件开发人员面临的关键问题。 点击阅读最新研究结果! 想试用 InterSystems IRIS 数据平台吗?立刻免费编码! 关于作者:Chris Walker 领导 InterSystems 的业务开发团队,该团队正在帮助合作伙伴使用软件工具和服务来加速和增强他们推向市场的数字解决方案。 在他职业生涯的早期,他为麻省总医院开发了临床信息系统,并在健康和生命科学信息管理方面拥有超过 25 年的经验。 点击查看原文
文章
姚 鑫 · 四月 7, 2021

第十九章 存储和使用流数据(BLOBs和CLOBs)

# 第十九章 存储和使用流数据(BLOBs和CLOBs) Intersystems SQL支持将流数据存储为Intersystems Iris ®DataPlatform数据库中的 `BLOBs`(二进制大对象)或 `CLOBs`(字符大对象)的功能。 # 流字段和SQL Intersystems SQL支持两种流字段: - 字符流 `Character streams`,用于大量文本。 - 二进制流 `Binary streams`,用于图像,音频或视频。 ## BLOBs and CLOBs Intersystems SQL支持将`BLOBs`(二进制大对象)和`CLOBs`(字符大对象)存储为流对象的功能。 `BLOBs`用于存储二进制信息,例如图像,而`CLOBs`用于存储字符信息。 **`BLOBs`和`CLOBs`可以存储多达4千兆字节的数据(JDBC和ODBC规范所强加的限制)。** 在各种方面,诸多方面的操作在通过ODBC或JDBC客户端访问时处理字符编码转换(例如Unicode到多字节):`BLOB`中的数据被视为二进制数据,从未转换为二进制数据另一个编码,而`CLOB`中的数据被视为字符数据并根据需要转换。 如果二进制流文件(`BLOB`)包含单个非打印字符`$CHAR(0)`,则被认为是空二进制流。它相当于`""`空二进制流程值:它存在(不是`null`),但长度为0。 ## 定义流数据字段 Intersystems SQL支持流字段的各种数据类型名称。这些Intersystems数据类型名称是与以下内容对应的同义词: - 字符流:数据类型`LONGVARCHAR`,映射到`%stream.globalcharacter`类和ODBC / JDBC数据类型`-1`。 - 字符流:数据类型`LONGVARBINARY`,映射到`%Stream.GlobalBinary`类和ODBC / JDBC数据类型`-4`。 某些Intersystems流数据类型允许指定数据精度值。此值是no-op,对流数据的允许大小没有影响。提供它以允许用户记录预期的未来数据大小。 以下示例定义包含两个流字段的表: ```sql CREATE TABLE Sample.MyTable ( Name VARCHAR(50) NOT NULL, Notes LONGVARCHAR, Photo LONGVARBINARY) ``` 分片表不能包含流数据类型字段。 ### 流字段约束 Stream字段的定义符合以下字段数据约束: 流字段可以定义为 `NOT NULL`。 流字段可以占用默认值,更新值或计算码值。 流字段不能定义为唯一,主键字段或`idkey`。试图这样做导致`SQLCode -400`致命错误,其中%MSG如下:` ERROR #5414: Invalid index attribute: Sample.MyTable::MYTABLEUNIQUE2::Notes, Stream property is not allowed in a unique/primary key/idkey index > ERROR #5030: An error occurred while compiling class 'Sample.MyTable'.` 无法使用指定的`COLLATE` 值定义流字段。试图这样做导致`SQLCode -400`致命错误,其中`%MSG`如下:` ERROR #5480: Property parameter not declared: Sample.MyTable:Photo:COLLATION > ERROR #5030: An error occurred while compiling class 'Sample.MyTable'.` ## 将数据插入流数据字段 将数据插入流字段有三种方法: - `%Stream.Globalcharacter`字段:可以直接插入字符流数据。例如, ```sql INSERT INTO Sample.MyTable (Name,Notes) VALUES ('Fred','These are extensive notes about Fred') ``` ![image](/sites/default/files/inline/images/1_31.png) ```java Class Sample.MyTable Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {yx}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = MyTable ] { Property Name As %Library.String(MAXLEN = 50) [ Required, SqlColumnNumber = 2 ]; Property Notes As %Stream.GlobalCharacter [ SqlColumnNumber = 3 ]; Property Photo As %Stream.GlobalBinary [ SqlColumnNumber = 4 ]; /// Bitmap Extent Index auto-generated by DDL CREATE TABLE statement. Do not edit the SqlName of this index. Index DDLBEIndex [ Extent, SqlName = "%%DDLBEIndex", Type = bitmap ]; Storage Default { Name Notes Photo ^Sample.MyTableD MyTableDefaultData sequence ^Sample.MyTableD ^Sample.MyTableI ^Sample.MyTableS %Library.CacheStorage } } ``` - `%stream.globalcharacter`和`%stream.globalbinary`字段:可以使用oref插入流数据。可以使用`Write()`方法将字符串附加到字符流,或者写入的方法,以将具有行终结器的字符串附加到字符流。默认情况下,行终结器是`$CHAR(13,10)`(回车返回/线路);可以通过设置`LineTerminator` 属性来更改行终结器。在以下示例中,示例的第一部分创建由两个字符串和其终端组组成的字符流,然后使用嵌入的SQL将其插入流字段。示例的第二部分返回字符流长度,并显示显示终结器的字符流数据: ```java /// d ##class(PHA.TEST.SQL).StreamField() ClassMethod StreamField() { CreateAndInsertCharacterStream SET gcoref=##class(%Stream.GlobalCharacter).%New() DO gcoref.WriteLine("First Line") DO gcoref.WriteLine("Second Line") &sql(INSERT INTO Sample.MyTable (Name,Notes) VALUES ('Fred',:gcoref)) IF SQLCODEd ##class(PHA.TEST.SQL).StreamField() 插入成功 1 ^CacheStream=1 ^CacheStream(1)=1 ^CacheStream(1,0)=25 ^CacheStream(1,1)="First Line"_$c(13,10)_"Second Line"_$c(13,10) ``` ![image](/sites/default/files/inline/images/2_19.png) - `%stream.globalcharacter`和`%stream.globalbinary`字段:可以通过从文件读取它来插入流数据。例如, ```java /// d ##class(PHA.TEST.SQL).StreamField1() ClassMethod StreamField1() { SET myf="E:\temp\game.jpg" OPEN myf:("RF"):10 USE myf:0 READ x(1):10 &sql(INSERT INTO Sample.MyTable (Name,Photo) VALUES ('George',:x(1))) IF SQLCODEd ##class(PHA.TEST.SQL).StreamField1() WRITE "插入成功",! ^ zStreamField1+11^PHA.TEST.SQL.1 DHC-APP 2d0>g WRITE "插入成功",! ^ zStreamField1+11^PHA.TEST.SQL.1 DHC-APP 2d0>g DHC-APP> ``` ![image](/sites/default/files/inline/images/3_14.png) 作为默认值或计算值插入的字符串数据以适合于流字段的格式存储。 ## 查询流字段数据 选择流字段的查询选择项返回流对象的完全形成的OID(对象ID)值,如下例所示: ```sql SELECT Name,Photo,Notes FROM Sample.MyTable WHERE Photo IS NOT NULL ``` ![image](/sites/default/files/inline/images/4_11.png) OID是一个 `%List` 格式化数据地址,如以下内容:`$lb("1","%Stream.GlobalCharacter","^EW3K.Cn9X.S")`。 - OID的第一个元素是一个连续的正整数(从1开始),它被分配给每个插入到表中的流数据值。 例如,如果第1行插入流字段`Photo`和`Notes`的值,则将它们赋值为1和2。 如果第2行插入了一个`Notes`值,则将该值赋给3。 如果用`Photo`和`Notes`的值插入第3行,则将它们赋值为4和5。 分配顺序是表定义中列出字段的顺序,而不是`INSERT`命令中指定字段的顺序。 默认情况下,使用单个整数序列,它对应于流位置全局计数器。 然而,一个表可能有多个流计数器,如下所述。 - 更新操作不会改变初始整数值。 `DELETE`操作可以在整型序列中创建空白,但不会改变这些整型值。 使用`DELETE`删除所有记录不会重置此整数计数器。 如果所有表流字段都使用默认的`StreamLocation`值,则使用`TRUNCATE TABLE`删除所有记录将重置此整数计数器。 不能使用`TRUNCATE`表为嵌入式对象(`%SerialObject`)类重置流整数计数器。 - OID的第二个元素是流数据类型,可以是`%Stream.GlobalCharacter` 或`%Stream.GlobalBinary`。 - OID的第三个元素是一个全局变量。 默认情况下,它的名称是从与表对应的包名和持久类名生成的。 一个`“S”`(用于流)被追加。 - 如果表是使用SQL `CREATE TABLE`命令创建的,这些包和持久化类名称将被散列为每个4个字符(例如,`^EW3K.Cn9X.S`)。 这个全局变量包含流数据插入计数器最近分配的值。 如果没有插入流字段数据,或者使用`TRUNCATE TABLE`删除所有表数据,那么这个全局变量是未定义的。 - 如果表是作为一个持久化类创建的,那么这些包和持久化类名不会被散列(例如`^Sample.MyTableS`)。 默认情况下,这是`StreamLocation`存储关键字`^Sample.MyTableS` 价值。 默认流位置是全局位置,如`^Sample.MyTableS`。此全局变量用于计算插入到没有自定义位置的所有流属性(字段)的次数。例如,如果`Sample.MyTable`中的所有流属性都使用默认流位置,则在`Sample.MyTable`的流属性中插入了10个流数据值时,`^Sample.MyTableS`全局变量包含值10。此全局变量包含最近分配的流数据插入计数器的值。如果没有插入流字段数据,或者使用截断表删除了所有表数据,则此全局变量未定义。 定义流字段属性时,可以定义自定义位置,如下所示:`Property Note2 As %Stream.GlobalCharacter (LOCATION="^MyCustomGlobalS")`;。在这种情况下,`^MyCustomGlobalS`全局用作指定此位置的流属性(或多个属性)的流数据插入计数器;未指定位置的流属性使用默认流位置全局(`^Sample.MyTableS`)作为流数据插入计数器。每个全局计数与该位置相关联的流属性的插入。如果没有插入流场数据,则位置`GLOBAL`是未定义的。如果一个或多个流属性定义了位置,则截断表不重置流计数器。 这些流位置全局变量的下标包含每个流字段的数据。例如,`^EW3K.Cn9X.S(3)`表示第三个插入的流数据项。`^EW3K.Cn9X.S(3,0)`是数据的长度。`^EW3K.Cn9X.S(3,1)`是实际的流数据值。 注意:流字段的`OID`与`RowID`或`Reference`字段返回的`OID`不同。`%OID`函数返回`RowID`或引用字段的`OID`;`%OID`不能与流字段一起使用。试图将流字段用作`%OID`的参数会导致`SQLCODE-37`错误。 在查询的`WHERE`子句或`HAVING`子句中使用流字段受到严格限制。不能将相等条件或其他关系运算符(`=, !=, `)或包含运算符(`]`)或跟随运算符(`[`)与流字段一起使用。尝试将这些运算符与流字段一起使用会导致`SQLCODE-313`错误。 ### Result Set Display - 从程序执行的动态SQL以`$lb("6","%Stream.GlobalCharacter","^EW3K.Cn9X.S")`.格式返回`OID`。 - SQL Shell作为动态SQL执行,并以`$lb("6","%Stream.GlobalCharacter","^EW3K.Cn9X.S")`格式返回`OID`。 - 嵌入式SQL返回相同的`OID`,但以编码`%LIST`的形式返回。可以使用`$LISTTOSTRING`函数将`OID`显示为元素以逗号分隔的字符串:`6,%Stream.GlobalBinary,^EW3K.Cn9X.S`。 从管理门户SQL执行界面运行查询时,不返回`OID`。取而代之的是: - 字符流字段返回字符流数据的前100个字符。如果字符流数据超过100个字符,则用省略号(`...`)表示。在第100个字符之后。这等效于`SUBSTRING(cstream field,1,100)`。 - 二进制流字段返回字符串``。 在表数据的管理门户SQL界面打开表显示中显示相同的值。 要从管理门户SQL执行界面显示`OID`值,请将空字符串连接到流值,如下所示:`SELECT Name, ''||Photo, ''||Notes FROM Sample.MyTable`。 ![image](/sites/default/files/inline/images/5_5.png) ## `DISTINCT`, `GROUP BY`, and `ORDER BY` 每个流数据字段的`OID`值是唯一的,即使数据本身包含重复。 这些`SELECT`子句操作的是流的`OID`值,而不是数据值。 因此,当应用到查询中的流字段时: - 不同的子句对重复的流数据值没有影响。 `DISTINCT`子句将流字段为`NULL`的记录数减少为一个`NULL`记录。 - `GROUP BY`子句对重复的流数据值没有影响。 `GROUP BY`子句将流字段为空的记录数量减少为一个空记录。 - `ORDER BY`子句根据数据流的`OID`值来排序数据,而不是数据值。 `ORDER BY`子句列出流字段为空的记录,然后列出带有流字段数据值的记录。 ## 谓词条件和流 `IS [NOT] NULL`谓词可以应用于流字段的数据值,示例如下: ```sql SELECT Name,Notes FROM Sample.MyTable WHERE Notes IS NOT NULL ``` `BETWEEN`, `EXISTS`, `IN`, `%INLIST`, `LIKE`, `%MATCHES`, and `%PATTERN` 谓词可以应用于流对象的`OID`值,示例如下: ```sql SELECT Name,Notes FROM Sample.MyTable WHERE Notes %MATCHES '*1[0-9]*GlobalChar*' ``` 尝试在流字段上使用任何其他谓词条件会导致`SQLCODE -313`错误。 ## 聚合函数和流 `COUNT`聚合函数接受一个流字段,并对该字段中包含非空值的行进行计数,示例如下: ```sql SELECT COUNT(Photo) AS PicRows,COUNT(Notes) AS NoteRows FROM Sample.MyTable ``` ![image](/sites/default/files/inline/images/6_4.png) 但是,流字段不支持`COUNT`(`DISTINCT`)。 对于流字段不支持其他聚合函数。 尝试将流字段与任何其他聚合函数一起使用会导致`SQLCODE -37`错误。 ## 标量函数和流 除了`%OBJECT`、`CHARACTER_LENGTH`(或`CHAR_LENGTH或DATALENGTH`)、`SUBSTRING`、`CONVERT`、`XMLCONCAT`、`XMLELEMENT`、`XMLFOREST`和`%INTERNAL`函数外,InterSystems SQL不能对流字段应用任何函数。 尝试使用流字段作为任何其他SQL函数的参数会导致`SQLCODE -37`错误。 尝试使用流字段作为任何其他SQL函数的参数会导致`SQLCODE -37`错误。 - `%OBJECT`函数打开一个流对象(接受一个`OID`)并返回oref(对象引用),示例如下: ```sql SELECT Name,Notes,%OBJECT(Notes) AS NotesOref FROM Sample.MyTable WHERE Notes IS NOT NULL ``` ![image](/sites/default/files/inline/images/7_1.png) - `CHARACTER_LENGTH`、`CHAR_LENGTH`和`DATALENGTH`函数接受流字段并返回实际的数据长度,如下面的示例所示: ```sql SELECT Name,DATALENGTH(Notes) AS NotesNumChars,DATALENGTH(Photo) AS PhotoNumChars FROM Sample.MyTable ``` ![image](/sites/default/files/inline/images/8_2.png) `SUBSTRING`函数接受一个流字段,并返回流字段的实际数据值的指定子字符串,如下面的示例所示: ```sql SELECT Name,SUBSTRING(Notes,1,10) AS Notes1st10Chars FROM Sample.MyTable WHERE Notes IS NOT NULL ``` ![image](/sites/default/files/inline/images/9_1.png) 当从管理门户SQL Execute接口发出时,子字符串函数返回流字段数据最多100个字符的子字符串。 如果流数据的指定子字符串大于100个字符,则在第100个字符后用省略号(`…`)表示。 - `CONVERT`函数可用于将流数据类型转换为`VARCHAR`,示例如下: ```sql SELECT Name,CONVERT(VARCHAR(100),Notes) AS NotesTextAsStr FROM Sample.MyTable WHERE Notes IS NOT NULL ``` ![image](/sites/default/files/inline/images/111.png) `CONVERT(datatype,expression)`语法支持流数据转换。 如果`VARCHAR`精度小于实际流数据的长度,则将返回值截断为`VARCHAR`精度。 如果`VARCHAR`精度大于实际流数据的长度,则返回值为实际流数据的长度。 不执行填充。 `{fn CONVERT(expression,datatype)}`语法不支持流数据转换; 它发出一个`SQLCODE -37`错误。 - `%INTERNAL`函数可以用于流字段,但不执行任何操作。 # 流字段并发锁 InterSystems IRIS通过取出流数据上的锁来保护流数据值不被另一个进程并发操作。 InterSystems IRIS在执行写操作之前取出一个排他锁。 排他锁在写操作完成后立即释放。 当第一个读操作发生时,InterSystems IRIS取出共享锁。 只有当流实际被读取时才会获取共享锁,并且在整个流从磁盘读取到内部临时输入缓冲区后立即释放共享锁。 # 在Intersystems中使用流字段IRIS方法 不能在Intersystems Iris方法中直接使用嵌入式SQL或动态SQL使用`BLOB`或`CLOB`值;相反,使用SQL来查找`Blob`或`Clob`的流标识符,然后创建`%AbstractStream`对象的实例以访问数据。 # 使用来自ODBC的流字段 ODBC规范不提供对`BLOB`和`CLOB`字段的任何识别或特殊处理。 InterSystems SQL将ODBC中的`CLOB`字段表示为具有`LONGVARCHAR(-1)`类型。 BLOB字段表示为类型为`LONGVARBINARY(-4)`。 对于流数据类型的ODBC/JDBC数据类型映射,请参考InterSystems SQL reference中的数据类型引用页中的数据类型整数代码。 ODBC驱动程序/服务器使用一种特殊协议来访问`BLOB`和`CLOB`字段。 通常,必须在ODBC应用程序中编写特殊的代码来使用`CLOB`和`BLOB`字段; 标准的报告工具通常不支持它们。 # 使用来自JDBC的流字段 在Java程序中,可以使用标准的JDBC `BLOB`和`CLOB`接口从`BLOB`或`CLOB`检索或设置数据。 例如: ```java Statement st = conn.createStatement(); ResultSet rs = st.executeQuery("SELECT MyCLOB,MyBLOB FROM MyTable"); rs.next(); // fetch the Blob/Clob java.sql.Clob clob = rs.getClob(1); java.sql.Blob blob = rs.getBlob(2); // Length System.out.println("Clob length = " + clob.length()); System.out.println("Blob length = " + blob.length()); // ... ``` 注意:当使用`BLOB`或`CLOB`结束时,必须显式调用`free()`方法来关闭Java中的对象,并向服务器发送消息以释放流资源(对象和锁)。 仅仅让Java对象超出范围并不会发送清理服务器资源的消息。
公告
Claire Zheng · 一月 10, 2023

欢迎中文社区新版主@牛宇翔

亲爱的社区开发者们, 我很高兴地向大家介绍一位我们的新版主 @牛宇翔! @牛宇翔 目前担任首都医科大学附属北京友谊医院信息中心临床组组长。 以下是@牛宇翔 的自我介绍: 本人有接近10年的医疗信息化经验,目前在我院,带领一个微型小团队,基于Ensemble数据库做医院信息系统(Hospital Information System, HIS)应用端研发,我们团队熟悉HTML、CSS、JavaScript及衍生前端语言,日常工作主要根据用户需求开发对应功能,结合临床业务难点痛点,不断优化程序功能。经过两年的学习和努力,我们团队已完成临床新增功能和优化需求共计一千余条,随着科室人力的发展,我们的开发力量会越来越强,可以更好地保证临床需求的及时响应,不断优化和完善系统BUG,提高临床工作效率。与此同时,我还担任应急小组成员,负责进行数据库运维和问题处理,保证第一时间排查故障。 InterSystems 提供了一个非常优秀的集成平台,借助该技术,给我们业务带来了非常大的便利。我也希望这么优秀的技术,能给更多的兄弟单位和合作伙伴创造价值。我也希望能够在社区与大家一起交流,分享自己的一些实践经验;同时也希望借助这个平台,向大家学习一些优秀的实践。我们一起成长,共同进步! 再次欢迎我们的新版主 @牛宇翔👏🏼👏🏼👏🏼👏🏼👏🏼 期待你在InterSystems开发者社区成长为一名优秀版主! 热烈欢迎!期待更多大作!@牛宇翔
公告
jieliang liu · 三月 30, 2022

2022年3月开发者社区更新

大家好,欢迎来到2022年3月开发者社区更新! 我们最近在InterSystems社区对开发者们的体验做了一些改进: 全新的社区内容搜索功能 综合社区数据 链接你的脸书账号 帖子页面更新:标签、作者块、草稿突出显示 下面让我们仔细看看。 社区搜 我们已经在社区网站上部署了一个全新的搜索引擎。有两个搜索选项: 快速搜索 高级搜索 通过DC快速搜索,你可以很容易地找到一个帖子/标签/用户并直接进入该网页。 在建议的选项中没有找到合适的东西? 试着通过点击🔍按钮使用DC高级搜索: 在这里,你可以轻松地为你的搜索查询添加高级参数: 按特定用户的帖子搜索 通过特定标签搜索 按特定的帖子类型或只按你的帖子搜索 你还可以按时间段和相关性对结果进行排序: 综合社区数据 现在你可以看到InterSystems开发社区的数据统计了: 链接你的脸书账号 在你的DC资料中添加Facebook链接,以认识新朋友,拉近彼此的距离。 进入你的DC用户资料-->编辑-->其他信息-->Facebook资料 帖子页面更新:标签、作者块、草稿突出显示 你问了 - 我们做到了! 现在DC标签出现在帖子的正文中。 另外,在帖子页面,你现在可以在右边的块中看到作者的联系信息: DC网站上的草稿现在是蓝色突出显示: 希望你喜欢我们的更新 在DC GitHub上提交您的改进请求和错误报告。或者在本帖的评论中发表您的建议。 请继续关注!
文章
Qiao Peng · 一月 10, 2021

iOS平台上的FHIR和IRIS医疗版

# Swift-FHIR-Iris iOS应用程序支持将HealthKit数据导入InterSystems IRIS医疗版(或任何FHIR资源仓库库) ![main](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/FHIR.png) # 目录 * [演示目的](#goal) * [如何运行此演示](#rundemo) * [先决条件](#prerequisites) * [安装Xcode](#installxcode) * [打开SwiftUi](#openswiftui) * [配置模拟器](#simulator) * [启动InterSystems FHIR服务器](#lunchfhir) * [在iOS应用程序上操作](#iosplay) * [工作原理](#howtos) * [iOS](#howtosios) * [如何检查健康数据的授权](#authorisation) * [如何连接FHIR资源仓库](#howtoFhir) * [如何将患者信息保存到FHIR资源仓库](#howtoPatientFhir) * [如何从HealthKit中提取数据](#queryHK) * [如何将HealthKit数据转换为FHIR](#HKtoFHIR) * [后端 (FHIR)](#backend) * [前端](#frontend) * [ToDos](#todo) # 演示目的 目的是创建FHIR协议的端到端演示。 这里的端到端指的是从一个信息源到另一个信息源,例如iPhone。 苹果HealthKit将收集到的健康数据转换为FHIR,再发送到InterSystems IRIS 医疗版存储库。 必须通过web接口访问这些信息。 **TL;DR**: iPhone -> InterSystems FHIR -> web界面. # 如何运行此演示 ## 先决条件 * 客户端 (iOS) * Xcode 12 * 服务器和Web应用程序 * Docker ## 安装 Xcode 这里没有太多要说的,打开AppStore,搜索Xcode,安装。 ## 打开SwiftUi project Swift是苹果在iOS、Mac、Apple TV和Apple Watch中使用的一种编程语言,是objective-C的替代品。 双击Swift-FHIR-Iris.xcodeproj 单击左上角的箭头打开模拟器。 ![xcode](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/xcode_and_simulator.gif) ## 配置模拟器 打开Health 点击“Steps” 添加数据 ![simulator](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/configuration_simulator.gif) ## 启动InterSystems FHIR服务器 在该git的根目录下,运行以下命令: ```sh docker-compose up -d ``` 构建过程结束时,你将连接到FHIR资源仓库: http://localhost:32783/fhir/portal/patientlist.html ![portal](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_default.png) 该门户网站由@diashenrique创建. 为处理Apple活动足迹,进行了一些修改。 ## 在iOS应用程序上操作 iOS应用程序首先会请求你同意分享部分信息。 点击授权 ![authorize](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/ios_authorize.gif) 然后点击“Save and test server”对FHIR服务器进行测试 默认设置指向docker配置。 操作成功后,就可以输入患者信息。 名字、姓氏、生日、性别。 将患者信息保存到Fhir。弹出窗口将显示唯一的Fhir ID。 ![savepatient](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/save_patient.gif) 可在门户网站查阅该患者信息: 访问: http://localhost:32783/fhir/portal/patientlist.html 在这里我们可以看到,增加了一个新的病人“Toto”,0个活动。 ![patient portal](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/patient_toto.png) 发送她的活动信息: 回到iOS应用程序,点击“Step count”。 这里显示的是一周的步数。在我们的案例中有2条记录。 现在可以单击发送,将这些数据发送到InterSystems IRIS FHIR。 ![ios send](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/ios_send.gif) 从门户网站上查询新的活动记录: 现在我们可以看到Toto有两条新的观察和活动消息。 ![portal activites](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_activities.gif) 你还可以单击“chart”按钮以图表格式显示。 ![portal charts](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_chart.gif) # 工作原理 ## iOS 该demo大部分是基于SwiftUI构建的。 https://developer.apple.com/xcode/swiftui/ iOS和co的最新框架。 ### 如何检查健康数据的授权 它在SwiftFhirIrisManager 类中。 该类采用单例模式,可使用@EnvironmentObject对应用程序中进行的所有操作进行注释。 更多信息请访问 : https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views 调用requestAuthorization的方法如下: ```swift // Request authorization to access HealthKit. func requestAuthorization() { // Requesting authorization. /// - Tag: RequestAuthorization let writeDataTypes: Set = dataTypesToWrite() let readDataTypes: Set = dataTypesToRead() // requset authorization healthStore.requestAuthorization(toShare: writeDataTypes, read: readDataTypes) { (success, error) in if !success { // Handle the error here. } else { DispatchQueue.main.async { self.authorizedHK = true } } } } ``` 其中healthStore是HKHealthStore()的对象。 HKHealthStore类似于iOS中的healthdata数据库。 dataTypesToWrite和dataTypesToRead是我们想要在数据库中查询的对象。 授权的目的可以通过在Info.plist xml文件中添加以下内容完成: ```xml NSHealthClinicalHealthRecordsShareUsageDescription Read data for IrisExporter NSHealthShareUsageDescription Send data to IRIS NSHealthUpdateUsageDescription Write date for IrisExporter ``` ### 如何连接FHIR资源仓库 对于这一部分,我使用了从Smart-On-FHIR网站下载的FHIR包 : https://github.com/smart-on-fhir/Swift-FHIR 使用的类是FHIROpenServer。. ```swift private func test() { progress = true let url = URL(string: self.url) swiftIrisManager.fhirServer = FHIROpenServer(baseURL : url! , auth: nil) swiftIrisManager.fhirServer.getCapabilityStatement() { FHIRError in progress = false showingPopup = true if FHIRError == nil { showingSuccess = true textSuccess = "Connected to the fhir repository" } else { textError = FHIRError?.description ?? "Unknow error" showingSuccess = false } return } } ``` 这一步将在单例swiftIrisManager中创建一个新的对象fhirServer。 接下来使用getCapabilityStatement() 如果能够检索到FHIR服务器的capabilityStatement,则意味着已成功连接到FHIR资源仓库。 这个资源仓库不在HTTPS下,默认情况下Apple会阻止这种通信。 想要获取HTTP支持,可以对Info.plist xml文件进行如下编辑: ```xml NSAppTransportSecurity NSExceptionDomains localhost NSIncludesSubdomains NSExceptionAllowsInsecureHTTPLoads ``` ### 如何将患者信息保存到FHIR资源仓库 基本操作:首先检查存储库中是否已经存在该患者的信息 ```swift Patient.search(["family": "\(self.lastName)"]).perform(fhirServer) ``` 搜索具有相同姓氏的患者。 在这里,我们可以想象一下其他场景,比如使用Oauth2和JWT令牌加入patientId及其令牌。但在这个演示中,我们简单操作即可。 如果该患者信息已经存在,可以对其进行检索;否则,则创建新的患者信息 : ```swift func createPatient(callback: @escaping (Patient?, Error?) -> Void) { // Create the new patient resource let patient = Patient.createPatient(given: firstName, family: lastName, dateOfBirth: birthDay, gender: gender) patient?.create(fhirServer, callback: { (error) in callback(patient, error) }) } ``` ### 如何从HealthKit中提取数据 通过查询healthkit商店 store(HKHealthStore())即可完成。 这里我们查询一下步数。 使用predicate做好查询准备。 ```swift //Last week let startDate = swiftFhirIrisManager.startDate //Now let endDate = swiftFhirIrisManager.endDate print("Collecting workouts between \(startDate) and \(endDate)") let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate) ``` 然后,会根据数据类型(HKQuantityType.quantityType(forIdentifier: .stepCount))和predicate内容进行查询。 ```swift func queryStepCount(){ //Last week let startDate = swiftFhirIrisManager.startDate //Now let endDate = swiftFhirIrisManager.endDate print("Collecting workouts between \(startDate) and \(endDate)") let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate) let query = HKSampleQuery(sampleType: HKQuantityType.quantityType(forIdentifier: .stepCount)!, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (query, results, error) in guard let results = results as? [HKQuantitySample] else { return } process(results, type: .stepCount) } healthStore.execute(query) } ``` ### 如何将HealthKit数据转换为FHIR 在这部分,我们使用了微软软件包HealthKitToFHIR https://github.com/microsoft/healthkit-to-fhir 这个包很有用,为开发商提供了将HKQuantitySample转换为FHIR Observation的功能。 ```swift let observation = try! ObservationFactory().observation(from: item) let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"]) observation.category = try! [CodeableConcept(json: [ "coding": [ [ "system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "activity", "display": "Activity" ] ] ])] observation.subject = patientReference observation.status = .final print(observation) observation.create(self.fhirServer,callback: { (error) in if error != nil { completion(error) } }) ``` 其中item是HKQuantitySample,在我们的例子中是stepCount类型。 这个factory完成了大部分工作,将“unit”和“type”转换为FHIR codeableConcept,并将“value”转换为FHIR valueQuantity。 对PatientId的引用是通过强制转换json fhir引用手动完成的。 ```swift let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"]) ``` 对类别进行同样的操作 : ```swift observation.category = try! [CodeableConcept(json: [ "coding": [ [ "system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "activity", "display": "Activity" ] ] ])] ``` 最后,在fhir资源仓库中创建observation : ```swift observation.create(self.fhirServer,callback: { (error) in if error != nil { completion(error) } }) ``` ## 后端 (FHIR) 没什么好说的,它基于InterSystems社区的fhir模板 : https://openexchange.intersystems.com/package/iris-fhir-template ## 前端 基于Henrique作品,Henrique是使用jquery制作的FHIR资源仓库的一个很好的前端。 https://openexchange.intersystems.com/package/iris-fhir-portal
文章
Michael Lei · 八月 12, 2021

翻译:Windows、Caché 和病毒扫描程序

我最近看到一个客户问题,是使用 Caché 数据库上运行的病毒扫描程序导致应用程序间歇性变慢和用户响应时间不佳。 出乎意料的是,这是一个常见问题,所以本帖就是提个醒,要将主要 Caché 组件排除在病毒扫描之外。 通常,病毒扫描必须排除 CACHE.DAT 数据库文件和 Caché 二进制文件。 如果防病毒软件扫描 CACHE.DAT 和 InterSystems 文件,那么系统性能_将_受到较大影响。 具体来说,防病毒软件必须排除的 Caché 文件包括: * Caché 数据库 (CACHE.DAT)。 * Ensemble/bin 或 cache/bin 目录中的 Caché 可执行文件。 * 写入映像日志 (WIJ)。 * 日志目录中的日志文件。 更多详细信息,请参见在线文档。 [更多 Caché 文档](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSA_thirdparty)
文章
姚 鑫 · 二月 22, 2021

第四十四章 Caché 变量大全 $ZTRAP 变量

# 第四十四章 Caché 变量大全 $ZTRAP 变量 包含当前错误陷阱处理程序的名称。 # 大纲 ``` $ZTRAP $ZT ``` # 描述 `$ZTRAP`包含当前错误陷阱处理程序的行标签名和/或例程名。有三种方法可以设置`$ZTRAP`: - `SET $ZTRAP=“location”` - `SET $ZTRAP=“*location”` - `SET $ZTRAP=“^%ET” or “^%ETN”` 在这里,位置可以指定为标签(当前例程中的行标签)、`^routine`(指定外部例程的开始)或`label^routine`(指定外部例程中的指定标签)。 **然而,`$ZTRAP=label^routine`不能用于程序块。过程块中的`$ZTRAP`不能用于转到过程体之外的位置;过程块中的`$ZTRAP`只能引用该过程块中的一个位置**。 ## Location 使用设置命令,可以将位置指定为带引号的字符串。 - 在例程中,可以将位置指定为标签(当前例程中的行标签)、`^routine`(指定外部例程的开始)或`label^routine`(指定外部例程中的指定标签)。不要在引用过程或过程中的标签的例程中指定位置。这是一个无效位置;当InterSystems IRIS试图执行`$ZTRAP`时,会导致运行时错误。 - 在过程中,可以将位置指定为标签;过程块中私有标签。过程块中的`$ZTRAP`不能用于转到过程体之外的位置;过程块中的`$ZTRAP`只能引用该过程块中的一个位置。因此,在过程中,不能将`$ZTRAP`设置为`^routine`或`label^routine`.尝试这样做将导致``错误。 在过程中,将`$ZTRAP`设置为私有标签名,但是`$ZTRAP`值不是私有标签名;它是从过程标签(过程的顶部)到私有标签的行位置的偏移量。例如,`+17^myproc`. 注意:`$ZTRAP`在某些情况下(而不是在过程中)为`label + offset`提供传统支持。这个可选的`+ offset`是一个整数,指定要从`label`偏移的行数。标签必须在相同的例程中。不建议使用`+offset`,它可能会导致编译警告错误。 InterSystems建议您在指定位置时避免使用行偏移量。 调用过程或IRIS `SYS`%例程时,不能指定`+`偏移量。如果尝试这样做,则InterSystems IRIS会发出错误。 `$ZTRAP`位置必须在当前名称空间中。 `$ZTRAP`不支持扩展的例程引用。 如果指定了不存在的行标签(当前例程中不存在的位置),则会发生以下情况: - 显示`$ZTRAP`:在例程中,`$ZTRAP`包含`label ^ routine`。例如,`DummyLabel^MyRou`。在一个过程中,`$TRAP`包含最大可能的偏移量:`+ 34463 ^ MyProc`。 - 调用$ZTRAP:InterSystems IRIS发出``错误消息。 每个堆栈级别可以有其自己的`$ZTRAP`值。设置`$ZTRAP`时,系统会将`$ZTRAP`的值保存为先前的堆栈级别。当前堆栈级别结束时,InterSystems IRIS会恢复该值。要在当前堆栈级别启用错误陷阱,请通过指定`$ZTRAP`的位置将其设置为错误陷阱处理程序。例如: ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP() ClassMethod ZTRAP() { IF $ZTRAP="" { WRITE !,"$ZTRAP not set" } ELSE { WRITE !,"$ZTRAP already set: ",$ZTRAP SET oldtrap=$ZTRAP } SET $ZTRAP="Etrap1^Handler" WRITE !,"$ZTRAP set to: ",$ZTRAP // program code SET $ZTRAP=oldtrap WRITE !,"$ZTRAP restored to: ",$ZTRAP } ``` 发生错误时,此格式将展开调用堆栈,并将控制权转移到指定的错误陷阱处理程序。 在SqlComputeCode中,不要设置`$ZTRAP = $ZTRAP`。这可能导致事务处理和错误报告方面的重大问题。 要禁用错误捕获,请将`$ZTRAP`设置为空字符串(`“”`)。这将清除在当前DO堆栈级别设置的所有错误陷阱。 注意:在“终端”提示符下使用$ZTRAP仅限于当前代码行。 `SET $ZTRAP`命令和生成错误的命令必须在同一行代码中。终端在每个命令行的开头将`$ZTRAP`还原为系统默认值。 ## *Location 在例程中,可以选择在发生错误后保留调用堆栈。为此,请在位置之前和双引号内放置一个星号(`*`)。该表格不适用于程序。尝试这样做会导致`` 错误。只能在不是过程的子例程中使用此示例中的: ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP() ClassMethod ZTRAP() { Main SET $ZTRAP="*OnError" WRITE !,"$ZTRAP set to: ",$ZTRAP // program code OnError // Error handling code QUIT } ``` 这种格式只会导致转到`$ZTRAP`中指定的行标签;`$STACK`和`$ESTACK`保持不变。`$ZTRAP`错误处理例程的上下文框架与发生错误的上下文框架相同。但是,InterSystems IRIS会将`$ROLES`重置为设置`$ZTRAP`的执行级别的有效值;这会阻止`$ZTRAP`错误处理程序使用在建立错误处理程序后授予例程的提升权限。完成`$ZTRAP`错误处理例程后,InterSystems IRIS将堆栈展开到上一个上下文级。这种形式的`$ZTRAP`对于分析意外错误特别有用。 请注意,星号设置`$ZTRAP`选项;它不是位置的一部分。因此,在`$ZTRAP`上执行`WRITE`或`ZZDUMP`时不会显示此星号。 ## ^%ETN 在例程中,`set $ZTRAP=“^%ETN”`将系统提供的错误例程`%ETN`建立为当前错误捕获处理程序。`%ETN`在调用它的发生错误的上下文中执行。(`%et`是`%etn`的旧名称。它们的功能相同,但`%ETN`的效率略高一些。)。`^%ETN`错误处理程序的行为总是前缀星号(`*`)。 因为过程块中的`$ZTRAP`不能用于转到过程主体之外的位置,所以不能在过程中使用`SET $ZTRAP=“^%ETN”`。尝试这样做会导致``错误。 ## TRY / CATCH 与 $ZTRAP 不能在`TRY`块内设置`$ZTRAP`。尝试这样做会生成编译错误。可以在`TRY`块之前或在`CATCH`块内设置`$ZTRAP`。 **无论之前是否设置了`$ZTRAP`,`TRY`块中发生的错误都由`CATCH`块处理。`CATCH`块内发生的错误由当前错误捕获处理程序处理。** 下面的第一个示例显示了`TRY`块中发生的错误。下面的第二个示例显示了`try`块中引发的异常。在这两种情况下,都会采用`CATCH`块,而不是`$ZTRAP`: ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP() ClassMethod ZTRAP() { SET $ZTRAP="Ztrap" TRY { WRITE 1/0 } /* divide-by-zero error */ CATCH { WRITE "Catch taken" } QUIT Ztrap WRITE "$ZTRAP taken" SET $ZTRAP="" QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP() Catch taken ``` ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP1() ClassMethod ZTRAP1() { SET $ZTRAP="Ztrap" TRY { SET myvar=##class(Sample.MyException).%New("Example Error",999,,errdatazero) WRITE !,"Throwing an exception!",! THROW myvar QUIT } CATCH { WRITE "Catch taken" } QUIT Ztrap WRITE "$ZTRAP taken" SET $ZTRAP="" QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP1() Catch taken ``` 但是,`try`块可以调用设置和使用`$ZTRAP`的代码。在下面的示例中,`$ZTRAP`而不是`CATCH`块捕获被零除错误: ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP2() ClassMethod ZTRAP2() { TRY { DO Errsub } CATCH { WRITE "Catch taken" } QUIT Errsub SET $ZTRAP="Ztrap" WRITE 1/0 /* divide-by-zero error */ QUIT Ztrap WRITE "$ZTRAP taken" SET $ZTRAP="" QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP2() $ZTRAP taken ``` CATCH块中的`Throw`命令还可以调用`$ZTRAP`错误处理程序。 # 示例 下面的示例将`$ZTRAP`设置为此程序中的`OnError`例程。然后,它调用发生错误的`Suba`(尝试将数字除以0)。当错误发生时,InterSystems IRIS调用`$ZTRAP`中指定的`OnError`例程。`OnError`在设置`$ZTRAP`的上下文级别调用。因为`OnError`与`Main`处于相同的上下文级别,所以执行不会返回`Main`。 ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP3() ClassMethod ZTRAP3() { Main NEW $ESTACK SET $ZTRAP="OnError" WRITE !,"$ZTRAP set to: ",$ZTRAP WRITE !,"Main $ESTACK= ",$ESTACK // 0 WRITE !,"Main $ECODE= ",$ECODE DO SubA WRITE !,"Returned from SubA" // not executed WRITE !,"MainReturn $ECODE= ",$ECODE QUIT SubA WRITE !,"SubA $ESTACK= ",$ESTACK // 1 WRITE !,6/0 // Error: division by zero WRITE !,"fine with me" QUIT OnError WRITE !,"OnError $ESTACK= ",$ESTACK // 0 WRITE !,"$ECODE= ",$ECODE QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP3() $ZTRAP set to: +970^PHA.TEST.SpecialVariables.1 Main $ESTACK= 0 Main $ECODE= ,ZSYNTAX,ZSYNTAX,ZSYNTAX,ZMETHOD DOES NOT EXIST,M9,M6,M9, SubA $ESTACK= 1 OnError $ESTACK= 0 $ECODE= ,ZSYNTAX,ZSYNTAX,ZSYNTAX,ZMETHOD DOES NOT EXIST,M9,M6,M9,M9, ``` 下面的示例与前面的示例相同,但有一个例外:`$ZTRAP`位置前面有一个星号(`*`)。当错误发生在`SUBA`中时,此星号会导致InterSystems IRIS在`SUBA`(发生错误的地方)的上下文级调用`OnError`例程,而不是在`Main`(设置`$ZTRAP`的地方)的上下文级调用`OnError`例程。因此,当`OnError`完成时,执行将在`do`命令之后的行返回到`Main`。 ```java /// d ##class(PHA.TEST.SpecialVariables).ZTRAP4() ClassMethod ZTRAP4() { Main NEW $ESTACK SET $ZTRAP="*OnError" WRITE !,"$ZTRAP set to: ",$ZTRAP WRITE !,"Main $ESTACK= ",$ESTACK // 0 WRITE !,"Main $ECODE= ",$ECODE DO SubA WRITE !,"Returned from SubA" // executed WRITE !,"MainReturn $ECODE= ",$ECODE QUIT SubA WRITE !,"SubA $ESTACK= ",$ESTACK // 1 WRITE !,6/0 // Error: division by zero WRITE !,"fine with me" QUIT OnError WRITE !,"OnError $ESTACK= ",$ESTACK // 1 WRITE !,"$ECODE= ",$ECODE QUIT } ```
文章
姚 鑫 · 三月 15, 2021

第十章 SQL排序(二)

# 第十章 SQL排序(二) # 查询排序 InterSystems SQL提供了排序规则功能,可用于更改字段的排序规则或显示。 # 第十章 SQL排序(二) # 查询排序 InterSystems SQL提供了排序规则功能,可用于更改字段的排序规则或显示。 ## 查询明细排序 将排序功能应用于查询选择项会更改该项目的显示。 - 字母大小写:默认情况下,查询显示带有大写和小写字母的字符串。例外情况是对排序规则类型`SQLUPPER`的字段进行`DISTINCT`或`GROUP BY`操作。这些操作以所有大写字母显示该字段。可以使用`%EXACT`排序功能来反转此字母大小写转换,并以大写和小写字母显示该字段。不应在选择项列表中使用`%SQLUPPER`排序规则函数以所有大写字母显示字段。**这是因为`%SQLUPPER`在字符串的长度上添加了一个空格字符。请改用`UPPER`函数:** ```SQL SELECT TOP 5 Name,$LENGTH(Name) AS NLen, %SQLUPPER(Name) AS UpCollN,$LENGTH(%SQLUPPER(Name)) AS UpCollLen, UPPER(Name) AS UpN,$LENGTH(UPPER(Name)) AS UpLen FROM Sample.Person ``` ![image](/sites/default/files/inline/images/1_26.png) - 字符串截断:可以使用`%TRUNCATE`排序函数来限制显示的字符串数据的长度。 `%TRUNCATE`比`%SQLUPPER`更可取,后者会在字符串的长度上添加一个空格字符。 ```SQL SELECT TOP 5 Name,$LENGTH(Name) AS NLen, %TRUNCATE(Name,8) AS TruncN,$LENGTH(%TRUNCATE(Name,8)) AS TruncLen FROM Sample.Person ``` ![image](/sites/default/files/inline/images/2_15.png) 请注意,不能嵌套排序规则函数或大小写转换函数。 - `WHERE`子句比较:大多数`WHERE`子句谓词条件比较使用字段/属性的排序规则类型。因为字符串字段默认为`SQLUPPER`,所以这些比较通常不区分大小写。可以使用`%EXACT`排序规则功能使它们区分大小写: - 下面的示例返回`Home_City`字符串匹配项,无论字母大小写如何: ```SQL SELECT Home_City FROM Sample.Person WHERE Home_City = 'albany' ``` ![image](/sites/default/files/inline/images/3_13.png) 以下示例返回区分大小写的`Home_City`字符串匹配: ```SQL SELECT Home_City FROM Sample.Person WHERE %EXACT(Home_City) = 'albany' ``` ![image](/sites/default/files/inline/images/4_9.png) `SQL Follows`运算符(`]`)使用字段/属性归类类型。 但是,无论字段/属性的排序规则类型如何,SQL `Contains`运算符(`[`)都使用EXACT排序规则: ```SQL SELECT Home_City FROM Sample.Person WHERE Home_City [ 'c' ORDER BY Home_City ``` ![image](/sites/default/files/inline/images/5_3.png) `%MATCHES`和`%PATTERN`谓词条件使用EXACT排序规则,而不管字段/属性的排序规则类型如何。 `%PATTERN`谓词提供区分大小写的通配符和不区分大小写的通配符(`'A'`)。 `ORDER BY`子句:`ORDER BY`子句使用名称空间默认排序规则对字符串值进行排序。因此,`ORDER BY`不会基于字母大小写进行排序。可以使用`%EXACT`排序规则根据字母大小写对字符串进行排序。 ## `DISTINCT`和`GROUP BY`排序规则 默认情况下,这些操作使用当前的名称空间排序。默认的名称空间排序规则是`SQLUPPER`。 - `DISTINCT`:`DISTINCT`关键字使用名称空间默认排序规则来消除重复值。因此,`DISTINCT Name`返回所有大写字母的值。可以使用`EXACT`排序规则返回大小写混合的值。 `DISTINCT`消除仅字母大小写不同的重复项。**要保留大小写不同的重复项,但要消除确切的重复项,请使用`EXACT`排序规则。** 以下示例消除了精确的重复项(但不消除字母大写的变体),并以混合的大写和小写形式返回所有值: ```SQL SELECT DISTINCT %EXACT(Name) FROM Sample.Person ``` ![image](/sites/default/files/inline/images/6_2.png) `UNION`涉及隐式`DISTINCT`操作。 - `GROUP BY`:`GROUP BY`子句使用名称空间默认排序规则来消除重复的值。因此,`GROUP BY Name`返回所有大写字母的值。**可以使用`EXACT`排序规则返回大小写混合的值。** `GROUP BY`消除仅字母大小写不同的重复项。若要保留大小写不同的重复项,但要消除完全相同的重复项,必须在`GROUP BY`子句(而不是`select-item`)上指定`%EXACT`归类函数。 下面的示例返回大小写混合的值; `GROUP BY`消除重复项,包括字母大小写不同的重复项: ```SQL SELECT %EXACT(Name) FROM Sample.Person GROUP BY Name ``` ![image](/sites/default/files/inline/images/7_0.png) 下面的示例返回大小写混合的值; `GROUP BY`消除了精确的重复项(但不消除字母大写的变体): ```SQL SELECT Name FROM Sample.Person GROUP BY %EXACT(Name) ``` ![image](/sites/default/files/inline/images/8_1.png) # 旧版排序类型 InterSystems SQL支持多种旧式排序规则类型。它们已被弃用,不建议与新代码一起使用,因为它们的目的是为遗留系统提供持续的支持。他们是: - **`%ALPHAUP` — 除去问号(`“?”`)和逗号(`“,”`)之外的所有标点符号,并将所有小写字母转换为大写字母。主要用于映射旧全局变量。由`SQLUPPER`代替。** - **`%STRING` —将逻辑值转换为大写,去除所有标点符号和空格(逗号除外),并在字符串的开头添加一个前导空格。它将所有仅包含空格(空格,制表符等)的值作为SQL空字符串进行整理。由`SQLUPPER`代替。** - **`%UPPER` —将所有小写字母转换为大写字母。主要用于映射旧全局变量。由`SQLUPPER`代替。** - `SPACE` — `SPACE`排序将单个前导空格附加到一个值,强制将其作为字符串求值。要建立`SPACE`排序规则,`CREATE TABL`E提供一个`SPACE`排序规则关键字,而ObjectScript在`%SYSTEM.Util`类的`Collation()`方法中提供一个`SPACE`选项。没有相应的SQL排序规则功能。 **注意:如果使用`EXACT`,`UPPER`或`ALPHAUP`排序定义了字符串数据类型字段,并且查询在此字段上应用了`%STARTSWITH`条件,则可能导致不一致的行为。如果指定给`%STARTSWITH`的子字符串是规范数字(尤其是负数和/或小数),则`%STARTSWITH`可能会根据字段是否被索引而给出不同的结果。如果未对列进行索引,则`%STARTSWITH`应该会按预期执行。如果该列已建立索引,则可能会发生意外的结果。** # SQL和NLS排序 上面描述的SQL排序规则不应与InterSystems IRIS NLS排序规则功能混淆,后者提供符合特定本国语言排序规则要求的下标级别编码。这是提供分页的两个独立系统,它们在产品的不同级别上工作。 InterSystems IRIS NLS排序可以具有当前过程的过程级别排序,并且可以具有特定全局变量的不同排序。 为了确保使用InterSystems SQL时的正常运行,要求进程级NLS排序规则与所涉及的所有全局变量的NLS排序规则完全匹配,包括表所使用的全局变量以及用于临时文件(例如进程专用全局变量和IRIS TEMP)的全局变量。否则,查询处理器设计的不同处理计划可能会得出不同的结果。在发生排序的情况下,例如`ORDER BY`子句或范围条件,查询处理器将选择最有效的排序策略。它可以使用索引,可以在进程专用的全局文件中使用临时文件,可以在本地数组中排序,也可以使用`“]]”`(之后排序)比较。所有这些都是下标类型的比较,遵循有效的InterSystems IRIS NLS归类,这就是为什么所有这些类型的全局变量都必须使用完全相同的NLS归类的原因。 系统使用数据库默认排序规则创建全局变量。可以使用`%Library.GlobalEdit`类的`Create()`方法来创建具有不同排序规则的全局变量。唯一的要求是指定的归类可以是内置的(例如InterSystems IRIS标准),也可以是当前语言环境中可用的国家归类之一。
文章
姚 鑫 · 五月 23, 2021

第四章 收发电子邮件

# 第四章 收发电子邮件 本主题描述如何使用InterSystems IRIS发送和接收`MIME`电子邮件消息。 注意:本主题中的示例是经过组织的,因此管理电子邮件的方法可以用于不同的电子邮件服务器,这在测试和演示期间非常有用。这不一定是最适合生产需要的代码组织。 # 支持电子邮件协议 电子邮件使用标准协议通过Internet发送消息。 InterSystems IRIS支持以下三种协议: - InterSystems IRIS提供`MIME`电子邮件的对象表示形式。它支持文本和非文本附件、单部分或多部分邮件正文,以及`ASCII`和非`ASCII`字符集的标题。 - 可以通过`SMTP`服务器发送电子邮件。`SMTP`(简单邮件传输协议)是发送电子邮件的Internet标准。 - 还可以通过`POP3`从电子邮件服务器检索电子邮件,`POP3`是从远程服务器检索电子邮件的最常用标准。 注意:InterSystems IRIS不提供邮件服务器。相反,它提供了连接到邮件服务器并与之交互的功能。 # InterSystems IRIS如何表示`MIME`电子邮件 首先,了解InterSystems IRIS如何表示`MIME`电子邮件非常有用。 通常,多部分`MIME`邮件由以下部分组成: - 一组邮件标头,每个标头都包含邮件发送到的地址等信息。这还包括整个消息的`Mime-Type`标头和`Content-Type`标头。 对于多部分消息,`Content-Type`头必须是多部分/混合或多部分的其他子类型;`MIME`标准有许多变体。 - 多个消息部分,每个消息部分由以下部分组成: - 一组内容标头,包括`Content-Type`标头和特定于此部件的其他标头。 - 一种正文,它可以是文本或二进制,并且可以使用与其它部分的正文不同的字符集。 InterSystems IRIS使用两个类来表示电子邮件:`%Net.MailMessage`和`%Net.MailMessagePart`,即`%Net.MailMessage`的超类。下图显示了这些类之间的关系: ![image](/sites/default/files/inline/images/1_47.png) - 要表示普通的、由一部分组成的消息,请使用`%Net.MailMessage` - 要表示多部分消息,请使用`%Net.MailMessage`作为父消息,并使用`%Net.MailMessagePart`的多个实例作为其部分。 # 创建由单个部分组成的电子邮件 要创建由单个部分组成的电子邮件,请使用`%Net.MailMessage`类。要创建邮件,请执行以下操作: 1. 创建`%Net.MailMessage`的实例。 提示:可以将字符集指定为`%New()`;的参数,如果这样做,则会设置消息的`CharSet`属性。 2. 设置实例的`To`、`From`和`Subject`属性。 - `To`收件人-此邮件将发送到的电子邮件地址列表。此属性是标准的InterSystems IRIS列表类;要使用它,需要使用标准列表方法:`Insert()`、`GetAt()`、`RemoveAt()`、`Count()`和`Clear()`。 - `From`发件人-此邮件的发件人电子邮件地址。 - `Subject`主题-邮件的主题(如果您使用的SMTP服务器需要该主题)。 3. 可以选择设置日期、抄送、密件抄送和其他属性。 4. 如果邮件不是纯文本,请设置以下属性以指示您要创建的邮件的类型: - 如果这是一封HTML邮件,请将`IsHTML`属性设置为1。 - 如果这是二进制消息,请将`IsBinary`属性设置为1。 5. 若要指定消息及其标头的字符集,请根据需要设置`CharSet`属性。 重要提示:在添加消息内容之前指定字符集非常重要。 6. 添加消息内容: - 对于纯文本或`HTML`,请使用`TextData`属性,该属性是`%FileCharacterStream`的实例。不需要指定此流的`TranslateTable`属性;当指定邮件的字符集时,该属性会自动发生。 - 对于二进制数据,请使用`BinaryData`属性,该属性是`%FileBinaryStream`的实例。 提示:指定流的`Filename`属性时,请确保使用用户有权写入的目录。 要使用这些属性,请使用标准流方法:`Write()`、`WriteLine()`、`Read()`、`ReadLine()`、`Rewind()`、`MoveToEnd()`和`Clear()`。还可以使用流的`Size`属性,该属性提供消息内容的大小。 注意:应该了解正在使用的`SMTP`服务器的要求。例如,某些`SMTP`服务器要求包含主题标头。同样,某些`SMTP`服务器不允许任意`FROM`标头。 类似地,一些`SMTP`服务器识别优先级报头,而其他服务器则识别`X-Priority`。 示例1:`CreateTextMessage()` 以下方法创建一条简单消息并为其指定地址: ```java ClassMethod CreateTextMessage() As %Net.MailMessage { Set msg = ##class(%Net.MailMessage).%New() set msg.From = "test@test.com" Do msg.To.Insert("xxx@xxx.com") Do msg.Cc.Insert("yyy@yyy.com") Do msg.Bcc.Insert("zzz@zzz.com") Set msg.Subject="subject line here" Set msg.IsBinary=0 Set msg.IsHTML=0 Do msg.TextData.Write("This is the message.") Quit msg } ``` 示例2:`SimpleMessage()` 在实际发送邮件时指定地。上例的以下变体生成一条没有地址的文本消息: ```java ClassMethod SimpleMessage() As %Net.MailMessage { Set msg = ##class(%Net.MailMessage).%New() Set msg.Subject="Simple message "_$h Set msg.IsBinary=0 Set msg.IsHTML=0 Do msg.TextData.Write("This is the message.") Quit msg } ``` `Samples`命名空间中还有其他示例。要查找它们,请在该命名空间中搜索`%Net.MailMessage`。 # 创建多部分电子邮件 要创建由多部分组成的电子邮件,请执行以下操作: 1. 创建`%Net.MailMessage`的实例,并将其`To`、`From`和`Subject`属性设置为。可以选择设置其他属性以指定其他邮件标头。 2. 将`IsMultiPart`属性设置为1。 3. 将`MultiPartType`属性设置为以下值之一: `"related"`, `"alternative"`, 或 `"mixed"`。这会影响整个消息的`Content-Type`标头。 4. 对于邮件应包含的每个部分,创建`%Net.MailMessagePart`的实例并指定其属性,如从步骤4开始的“创建由单个部分组成的电子邮件”中所述。 5. 对于父电子邮件,设置`Parts`属性,该属性是一个数组。将每个子消息部分插入到此数组中。 发送邮件时,`%Net.SMTP`类会根据需要自动设置邮件的`Content-Type`标头(给定`MultiPartType`属性值)。 # 指定电子邮件标题 如前所述,消息本身和消息的每个部分都有一组标头。 `%Net.MailMessage`和`%Net.MailMessagePart`类提供的属性使可以轻松访问最常用的标头,但可以添加所需的任何标头。本节提供有关所有标头以及如何创建自定义标头的信息。 给定消息部分的标头使用由该部分的`CharSet`属性指定的字符集。 注意:应该了解正在使用的`SMTP`服务器的要求。例如,某些`SMTP`服务器要求包含主题标头。同样,某些`SMTP`服务器不允许任意`FROM`标头。 类似地,一些`SMTP`服务器识别优先级报头,而其他服务器则识别`X-Priority`。 # 指定基本电子邮件标题 设置以下属性(仅在`%Net.MailMessage`中)以设置邮件本身最常用的标头: - `To`-(必填)此邮件将发送到的电子邮件地址列表。此属性是标准的InterSystems IRIS列表;要使用它,请使用标准列表方法:`Insert()`、`GetAt()`、`RemoveAt()`、`Count()`和`Clear()`。 - From-(必填)发送此邮件的电子邮件地址。 - Date-此消息的日期。 - Subject-(必选)包含此邮件主题的字符串。 - Sender-邮件的实际发件人。 - Cc-此邮件将发送到的抄送地址列表。 - Bcc-此邮件将被发送到的密件副本地址列表。 ## 内容类型标题 发送邮件时,邮件和每个邮件部分的`Content-Type`标头会自动设置如下: - 如果消息是纯文本(`IsHTML`等于0,`IsBinary`等于0),则`Content-Type`标头被设置为 `"text/plain`。 - 如果消息是`HTML`(`IsHTML`等于1,`IsBinary`等于0),则`Content-Type`标头设置为`“text/html”`。 - 如果消息是二进制的(`IsBinary`等于1),则`Content-Type`报头设置为如果消息是二进制的(`IsBinary`等于1),则`Content-Type`报头设置为`"application/octet-stream"`. - 如果邮件是多部分邮件,则会为`MultiPartType`属性的值适当设置`Content-Type`标头。 `%Net.MailMessage`和`%Net.MailMessagePart`都提供了`contentType`属性,使可以访问`Content-Type`标头。 ## 内容传输编码标头 `%Net.MailMessage`和`%Net.MailMessagePart`都提供了`ContentTransferEncoding`属性,该属性提供了一种指定消息或消息部分的`Content-Transfer-Encoding`头的简单方法。 此属性可以是以下属性之一:`"base64" "quoted-printable" "7bit" "8bit"` 默认值如下: 对于二进制消息或消息部分:`"base64"` **重要提示:请注意,如果内容为`“Base64”`编码,则不能包含任何Unicode字符。如果要发送的内容包括Unicode字符,请确保使用`$ZCONVERT`将内容转换为`UTF-8`,然后对其进行`base-64`编码。例如:** ```java set BinaryText=$ZCONVERT(UnicodeText,"O","UTF8") set Base64Encoded=$system.Encryption.Base64Encode(BinaryText) ``` 收件人必须使用相反的过程来解码文本: ```java set BinaryText=$system.Encryption.Base64Decode(Base64Encoded) set UnicodeText=$ZCONVERT(BinaryText,"I","UTF8") ``` 对于文本消息或消息部分:`"quoted-printable"` ## 自定义标题 使用`%Net.MailMessage`和`%Net.MailMessagePart`,可以通过访问`Headers`属性设置或获取自定义标题,该属性是一个具有以下结构的数组: 数组键 |数组值 ---|--- 标头的名称,如`“Priority”` | 标头的值 此属性用于包含其他标头,如`X-Priority`和其他标头。例如: ```java do msg.Headers.SetAt(1,"X-Priority") do msg.Headers.SetAt("High","X-MSMail-Priority") do msg.Headers.SetAt("High","Importance") ``` 不同的电子邮件服务器和客户端可以识别不同的标头,因此设置多个相似的标头以确保服务器或客户端接收到的邮件具有它可以识别的标头是很有用的。