清除过滤器
文章
Frank Ma · 三月 2, 2022
如何检查密码是否足够强大,使其不会很快被破解? 又如何制作一个强大的密码?
我开发了一个工具,可能对这个问题有帮助。你可以在OpenExchange上找到它。用zpm安装。
zpm "install passwords-tool"
这个模块将只安装一个类 caretdev.Passwords中,其中包含一些有用的方法。
安全密码
要获得一个安全的密码,通常只需使用大写和小写的字母、数字和特殊符号,而且至少要有8个符号的长度。
Generate方法使用的参数:
Length - 只是一个生成密码的长度,默认值为12。
IncludeUpperLetter - 包括大写的ASCII字母,如果需要的话是2,默认是1。
IncludeLowerLetter - 包括小写ASCII字母,如果需要的话,默认为2。
IncludeNumber - 包括数字,如果需要的话,2个,默认为1个。
IncludeSymbol - 包括特殊符号,如果需要的话,2个,默认为1个。
USER>w ##class(caretdev.Passwords).Generate(12,1,0,0,0)
FMXRQEQPOVBC
USER>w ##class(caretdev.Passwords).Generate(12,1,1,0,0)
rgbPyWApcUjp
USER>w ##class(caretdev.Passwords).Generate(12,1,1,1,0)
cDuLf8FqEDx7
USER>w ##class(caretdev.Passwords).Generate(12,1,1,1,1)
0J/ lLbW|T$
USER>w ##class(caretdev.Passwords).Generate()
w3}{OQA|T{h^
这个方法使用$System.Encryption.GenCryptRand(),而不是普通的$random,后者对于密码来说可能不是那么安全。除了获得最佳密码外,它还在一个循环中生成一些密码,检查密码熵的值,并返回一个最高分。
密码熵 Entropy
密码熵预测了一个给定的密码通过猜测、暴力破解、字典攻击或其他常见方法破解的难度。熵本质上是衡量攻击者需要进行多少次猜测才能猜出你的密码。有几种方法来计算它。
USER>write ##class(caretdev.Passwords).Entropy("Pas$W0rD")
52.56
熵值公式L = 密码长度;密码中的符号数S = 独特的可能符号库的大小(字符集)。
比如:
数字(0-9): 10小写拉丁字母(a-z): 26小写和大写拉丁字母(a-z,A-Z):52ASCII可打印字符集(a-z、A-Z、符号、空格):95
可能的组合数=S**L密码熵值 = log2(可能的组合数)
香农熵 Shannon Entropy
USER>write ##class(caretdev.Passwords).ShannonScore("Pas$W0rD")
24
这种方式是基于使用字符的频率,以及密码的整个长度。详情见 Wiki.
NIST得分
USER>write ##class(caretdev.Passwords).NISTScore("Pas$W0rD")
24
计算
第一个字符的熵是4比特;
接下来的七个字符的熵是每个字符2比特;
第九个到第二十个字符的熵为每字符1.5比特;
第21个及以上的字符,每个字符有1比特的熵;
如果同时使用大写字母和非字母字符,将增加6位的 "奖励";
对于长度为1到19个字符的密码,在进行广泛的字典检查后,会增加6位的 "奖励",以确保密码不包含在一个大的字典中。20个字符以上的密码不会得到这个奖励,因为它被认为是由多个字典词组成的密码。
强度 Strength
write ##class(caretdev.Passwords).DetermineStrength("Pas$W0rD")
REASONABLE
生成的密码
USER>write ##class(caretdev.Passwords).DetermineStrength(##class(caretdev.Passwords).Generate())
STRONG
非常弱 VERY_WEAK - 熵值Entropy <= 32
弱WEAK - 熵值Entropy <= 48
正常 REASONABLE - 熵值Entropy <= 64
强 STRONG - 熵值Entropy <= 80
非常强 VERY_STRONG - 熵值Entropy > 80
如果你喜欢这篇文章,请投票 。
文章
姚 鑫 · 七月 28, 2021
# 第三十三章 类关键字 - SoapBodyUse
指定此类中定义的任何`web method`的编码。此关键字仅适用于`web服务`和`web客户端`类。
# 用法
要指定此类的`web method`的输入和输出所使用的编码,请使用以下语法:
```java
Class MyApp.MyClass [ SoapBodyUse = soapbodyuse ] { //class members }
```
其中`soapbodyuse`是下列之一:
- `literal` 文字(默认)—默认情况下,此类中的`web method`使用文字数据。也就是说,`SOAP`消息的``中的`XML`与`WSDL`中给出的模式完全匹配。
- `encoded` 编码—默认情况下,此类中的`web method`使用`SOAP`编码的数据。也就是说,`SOAP`消息的``中的`XML`使用了适合所使用的`SOAP`版本的`SOAP`编码,如以下规范所要求的:
- `SOAP 1.1` (https://www.w3.org/TR/2000/NOTE-SOAP-20000508/Opens in a new window)
- `SOAP 1.2` (https://www.w3.org/TR/soap12-part2/Opens in a new window)
重要提示:对于手动创建的`web服务`,该关键字的默认值通常是合适的。当使用`SOAP`向导从WSDL生成`web`客户端或服务时,InterSystems IRIS会将此关键字设置为适合该`WSDL`;如果修改该值,web客户端或服务可能不再工作。
# 详解
此关键字指定此类中定义的任何`web method`使用的默认编码。它还控制这个类的`ELEMENTQUALIFIED`和`XMLELEMENT`参数的默认值,这将在本主题的一个小节中讨论。
可以通过使用`SoapBodyUse`方法关键字或`SoapBodyUse`查询关键字,为单个方法重写此关键字。
# 对子类的影响
此关键字不是继承的。
# 默认
默认值为文字。(`SOAP`标准V1.1指定`web method`应该使用`SOAP`编码。但是,大多数`SOAP`客户端(包括`.NET`)都使用文字样式。)
# WSDL的关系
`SoapBodyUse`关键字指定了`WSDL`的``部分中``元素的`Use`属性的值。例如,如果`SoapBodyUse`是字面意思,则`WSDL`可能如下所示:
```xml
...
文章
Louis Lu · 四月 9, 2022
此文章也是对问题 在不重建的情况下插入索引Inserting an index without reconstruction 的一种解释
在使用SQL语言对 InterSystems IRIS 中的表进行查询时,有时候会发现返回的结果与实际有出入,特别是使用count() 函数,或者select 查询时,返回的结果少于实际应返回的值。这种情况往往是由于数据表格的索引值出了问题。
索引出问题的主要原因可能是:
表中先有数据,后创建的索引定义,并且定义之后没有重新生成索引。
对保存数据的global直接操作。如果是使用对象或者sql的方式操作数据,相应的索引都会自动更新,但是如果直接对global操作,则不会自动更新索引。
对保存索引的global直接操作。
要解决或者要检查是不是索引引发的问题,可以使用%ValidateIndices()函数,它有两种方式使用
$SYSTEM.OBJ.ValidateIndices(classname,idxList,autoCorrect,lockOption,multiProcess)
或者
##class(classname).%ValidateIndices(idxList,autoCorrect,lockOption,multiProcess)
两种使用方法最大的差别是:$SYSTEM.OBJ.ValidateIndices()方法会同时检查继承于该表的子表的索引,而##class(classname).%ValidateIndices()不检查子表的索引。
函数参数: idxList, ""代表检查所有索引,或者设定检查的索引项。默认为检查所有索引。 autoCorrect, 是否自动纠正错误。默认为0,不自动纠正。 lockOption, 执行过程中执行的锁的操作,0 - 完全不进行锁定 1 - 在检查每一行时进行共享锁定 2 - 对整个表进行独占锁定。默认=1 multiProcess, 在允许的情况下使用多进程执行。$SYSTEM.OBJ.ValidateIndices() 默认为 0,##class(classname).%ValidateIndices() 默认为 1.
例子:
Do $SYSTEM.OBJ.ValidateIndices("Sample.Company",$lb("NameIdx"),1,1)
Do ##class(Sample.Company).%ValidateIndices()
公告
Claire Zheng · 八月 26, 2022
欢迎了解2022年7月社区的最新动态!
最近我们进行了很多有趣的提升,以优化你在InterSystems开发者社区的体验:
📌 社交网络通知功能
📌 改进了订阅设置
📌 全新的“关于我们”页面
📌 更友好的“会员”页面
我们来详细看看这些改进!
通知
从现在开始,你会在你页面右上角(靠近头像照片)看到新的通知,点击小铃铛,你就可以看到所有最新的通知,点击即可获得更详细的信息:
点击“查看全部”即可抵达“通知”页面,在那里你可以看到所有通知信息。
在此页面中,您可以“将所有内容标记为已读(Mark all as read)”或通过链接进入生成通知的页面。并管理订阅设置。
订阅
我们改进了订阅页面,希望你们会觉得这个页面变得更加友好
您可以选择从开发者社区接收哪些通知,无论您是通过电子邮件还是通过网站接收。你可以在你账户的“订阅”部分找到它。
关于我们
我们 已经提到 过,我们创建了一些全新的“关于我们”页面。但是这些按钮太可爱了,值得我再提一次🥰
你可以在顶部菜单的About部分找到它——> 关于我们:
会员
另一个我们已经调整的是“会员”页,希望可以让你感到更便利。我们添加了一个新的“最新活动”列。您可以通过单击任何列的名称对其进行排序。
暂时就这些吧!希望您赞成我们所有的改进!
下次见!
文章
Chang Liu · 九月 22, 2022
1,准备
本次安装环境:Kylin-Server-10-SP2-Release-Build09-20210524-x86_64.iso
安装系统适配的对应版本:HealthConnect-2021.1.2.338.0-lnxubuntux64.tar.gz;ISCAgent-2021.1.2.338.0-lnxubuntux64.tar.gz
系统语言选择:English(必要)
2,安装HealthConnect+webgateway
2.1 新建所需用户组
groupadd iscagent
2.2 解压文件
2.3 安装
本次安装,使用root用户及root用户组安装,超级端口改为51773
3,安装ISCAgent
3.1安装说明
ISCAgent是healthconnect的镜像服务,若是单机使用,则不需要安装。
3.2 解压文件
3.3 安装
3.3 加入服务
3.3.1 新建文件
在/etc/systemd/system 下创建文件,ISCAgent.service,内容如下:
[Unit]
Description=InterSystems Agent
After=syslog.target network-online.target
[Service]
Environment=LD_LIBRARY_PATH=/usr/local/etc/irissys
Environment=COMLIB=/usr/local/etc/irissys
ExecStart=/usr/local/etc/irissys/ISCAgent
Type=forking PIDFile=/var/run/ISCAgent.pid KillMode=process
[Install]
WantedBy=multi-user.target
其中,/usr/local/etc/irissys为ISCAgent服务安装默认目录。
3.3.2 修改文件属性
chmod 755 ISCAgent.service3.3.3 重新启动systemctl
systemctl daemon-reload
3.3.4 启动服务
systemctl start ISCAgent.service
3.3.5 查看服务状态
systemctl status ISCAgent.service
如下:
4, 防火墙配置
firewall-cmd --zone=public --add-port=51773/tcp --permanent
firewall-cmd --zone=public --add-port=52773/tcp --permanent
firewall-cmd --zone=public --add-port=2188/tcp --permanent (--permanent永久生效,没有此参数重启后失效) 重载生效: firewall-cmd --reload
5,镜像配置
5.1 主机配置
创建镜像
5.2 备机配置
加入故障转移
hc为HealthConnect的安装实例名称
6 安装过程中出现的问题
6.1 描述
添加虚拟ip失败:
6.2 问题解决
发现virtualIP.sh中部分代码在中文系统中执行时有问题,则将系统换成英文系统则可以解决这个问题。
The End
可以,很实用 找了好久,国产系统适配先行者 很棒的分享! 友友写的真好 优秀 非常不错,总结到位 真的很不错 加精了!
文章
Michael Lei · 六月 8, 2023
嗨社区!
我们已经到了#GlobalSummit23 的尾声——最后一天!这是我们的一天——程序员的一天。今天的主题演讲都致力于开发人员、他们的成长、抱负和创新。
更有趣的是,在主题演讲中,@Dean.Andrews2971谈到了开发者社区等话题。你现在可以在Youtube上观看这部分,或者晚些有更新的版本:
午餐后,出席全球峰会的所有主持人齐聚一堂,参加名为“如何充分利用 InterSystems 开发人员生态系统”的会议。今年参加的人比去年多了很多!
@Dean.Andrews2971 谈到了社区、全球大师、开放交流、创意门户的新闻和功能,以及人们如何从中受益。
然后是任何想说几句话的人的开放季节😊
@Dmitry.Maslennikov 英文社区
@José.Pereira 葡语社区
@Muhammad.Waseem 英文社区
西语社区的@Francisco.López1549
法文社区的@Lorenzo Scalese
DC 英文社区的@Scott Roth
这是所有在场主持人的照片(从左到右):@José.Pereira、@Muhammad.Waseem、@Djeniffer.Greffin7753、@Scott.Roth、@Dean.Andrews2971、@John.Murray、@Irène.Mykhailova ,@Lorenzo.Scalese,@Francisco.López1549。
多么好的一群人!
我希望在场的每个人都喜欢这 45 分钟。
会议结束后,几乎是最后的冰淇淋和咖啡时间了!但在我看见@Guillaume.Rongier7183完成他关于他最喜欢的主题 Python 的演讲之前。
我们联系了@Dmitry.Maslennikov、@Murray.Oldfield 以及在上述会议期间加入的我们的新社区成员 - @Vladimir.Babarykin。
在最后的告别之后,我真的从 Caelestinus 抓住了@Vita.Tsareva
以上就是全部内容,希望您喜欢我的全球峰会进展情况的故事。
在评论中分享您对全球峰会的看法。您认为 2024 年全球峰会的举办地点是什么?这是一个有趣的话题😀到时候见!
文章
Jingwei Wang · 七月 7, 2023
本篇文章主要介绍互联互通套件的一些基础问题:
基于互联互通套件通过互联互通成熟的测评的实施工作量
电子病历共享文档部分:需要客户将业务系统数据灌入CCH套件SQL模型中
服务部分:在平台做消息改造,或者直接做业务系统接口改造
基于互联互通套件通过电子病例五级+互联互通成熟度测评四级需要的最低人员配备和项目总耗时
需要了医院现有业务系统和人员配备,做进一步评估及分析
目标只是通过互联互通成熟度测评需不需要FHIR
不需要,如果只是过测评,只需要互联互通套件基础版就够了
BI相关功能如何实现
可以使用DeepSee,基于Cubes做数据分析及钻取
如何使用Java进行快速开发
可以使用PEX,支持Java开发,但是如果使用Production,推荐使用内置开发语言ObjectScript,学习成本更低,未来开发新特性能力更强大
有没有自带的ETL工具
InterSystems 互联互通套件中没有ETL工具,但是支持所有ETL工具的连接
发送失败消息是否有记录
所有错误消息都能够在平台监控到,且可以进行转发或者重发
有没有按照单个服务流程进行整个业务流程的修改和查看
平台内所有服务都可以按照类别区分,也可以按照服务查看业务流程,但是没有按照单个服务修改整个业务流程的界面
文章
姚 鑫 · 六月 30, 2021
# 第二十三章 执行XSLT转换概述
XSLT(Extensible StyleSheet Language Transformations,可扩展样式表语言转换)是一种基于XML的语言,用于描述如何将给定的XML文档转换为另一个XML或其他“人类可读”的文档。可以使用`%XML.XSLT`和`%XML.XSLT2`包中的类来执行`XSLT 1.0`和`2.0`转换。
注意:使用的任何XML文档的XML声明都应该指明该文档的字符编码,并且文档应该按照声明的方式进行编码。如果未声明字符编码, IRIS将使用本书前面的“输入和输出的字符编码”中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。
# 在IRIS中执行XSLT转换概述
IRIS提供两个XSLT处理器,每个处理器都有自己的API:
- `Xalan`处理器支持`XSLT 1.0`。`XML.XSLT`包为该处理器提供API。
- `Saxon`处理器支持`XSLT 2.0`。`%XML.XSLT2`程序包为该处理器提供API。
`XML.XSLT2` API通过到`XSLT 2.0`网关的连接向`Saxon`发送请求。网关允许多个连接。这意味着,例如,可以将两个独立的 IRIS进程连接到网关,每个进程都有自己的一组编译样式表,同时发送转换请求。
使用Saxon处理器,编译的样式表和`isc:Evaluate`缓存是特定于连接的;必须管理自己的连接才能利用这两个特性。如果打开连接并创建编译样式表或计算填充`isc:Evaluate`缓存的转换,则在该连接上计算的所有其他转换都将访问编译样式表和`isc:Evaluate`缓存条目。如果打开新连接,其他连接(及其编译的样式表和缓存)将被忽略。
这两个处理器的API相似,不同之处在于`%XML.XSLT2`中的方法使用另一个参数来指定要使用的网关连接。
要执行`XSLT`转换,请执行以下操作:
1. 如果使用的是`Saxon`处理器,请按照下一节所述配置`XSLT`网关服务器。或使用默认配置。
如果使用的是`Xalan`处理器,则不需要网关。
系统会在需要时自动启动网关。或者也可以手动启动它。
2. 如果使用的是`Saxon`处理器,则可以选择创建`%Net.Remote.Gateway`的实例,表示到`XSLT`网关的单个连接。
请注意,当使用`Saxon`处理器时,要利用已编译的样式表和`isc:Evaluate`缓存,这一步是必需的。
3. 可以选择创建已编译的样式表并将其加载到内存中。请参阅本章后面的“创建编译样式表”。如果使用的是`Saxon`处理器,请确保在创建编译后的样式表时指定网关参数。
如果打算重复使用同一样式表,则此步骤非常有用。然而,此步骤也会消耗内存。当不再需要编译的样式表时,请务必将其删除。
4. 调用适用API的转换方法之一。如果使用的是`Saxon`处理器,则在调用`Transform`方法时可以选择指定网关参数。
5. 可以选择调用其他转换方法。如果使用的是`Saxon`处理器,则在调用`Transform`方法时可以选择指定网关参数;这使能够使用相同的连接计算另一个转换。此转换将访问与此连接相关联的所有编译样式表和`isc:Evaluate`缓存条目。如果打开新连接,其他连接(及其编译的样式表和缓存)将被忽略。
Studio还提供了一个向导,可以使用该向导测试XSLT转换;本章稍后将对此进行介绍。
# 配置、启动和停止XSLT 2.0网关
当使用`Saxon`处理器(执行`XSLT 2.0`转换)时, IRIS使用`XSLT 2.0`网关(后者使用Java)。要配置此网关,请执行以下操作:
1. 在管理门户中,选择 System Administration > Configuration > Connectivity > XSLT 2.0 Gateway Server.
2. 选择Go。

系统将显示XSLT网关服务器页面。
左侧区域显示配置详细信息,右侧区域显示最近的活动。

3. 在左侧区域中,可以选择指定以下设置:
- Port Number -`XSLT 2.0`网关独占使用的TCP端口号。此端口号不得与服务器上的任何其他本地TCP端口冲突。
默认值为 IRIS SuperServer端口号加`3000`。如果此数字大于`65535`,则系统使用`54773`。
- Java Version - 使用的Java版本。
- Log File - 日志文件的路径名。如果忽略此设置,则不执行日志记录。如果指定了文件名但忽略了目录,则将日志文件写入系统管理器的目录。
- Java Home Directory -包含Java bin目录的目录路径。如果服务器上没有默认Java,或者如果想使用不同的Java,请指定此选项。
要查看默认Java,请在服务器上的Shell中执行以下命令:
```
java -version
```
- JVM Arguments - Java虚拟机要使用的任何其他参数。
此区域还显示`JAVA_HOME`环境变量的当前值。
请注意,在网关运行时,不能编辑这些值中的任何一个。
4. 如果已进行更改,请选择保存以保存更改。或选择重置以。
5. (可选)选择测试以测试更改。
在此页面上,还可以执行以下操作:
- 启动网关。要执行此操作,请选择右侧区域中的Start。
请注意, IRIS会在需要时自动启动网关。不需要手动启动网关。
- 关闭网关。要执行此操作,请选择右侧区域中的Stop(停止)。
# 重用XSLT网关服务器连接(XSLT 2.0)
如果使用的是`Saxon`处理器,InterSystems IRIS将使用之前配置的`XSLT 2.0`网关。为了与此网关通信,InterSystems IRIS在内部创建一个`XSLT`网关连接(`%Net.Remote.Gateway`的实例)。默认情况下,系统创建一个连接,将其用于转换,然后丢弃该连接。打开新连接会产生开销,因此为多个转换维护一个连接可提供最佳性能。此外,必须维护自己的连接,以便利用已编译的样式表和`isc:Evaluate`缓存。
要重用XSLT网关连接,请执行以下操作:
1. 调用`%XML.XSLT2.Transformer`的`StartGateway()`方法:
```
set status=##class(%XML.XSLT2.Transformer).StartGateway(.gateway)
```
此方法启动XSLT 2.0网关(如果它尚未运行),并返回`%Net.Remote.Gateway`的实例作为输出。请注意,该方法还返回状态。
在`%Net.Remote.Gateway`实例表示与网关的连接。
`StartGateway()`有一个可选的第二个参数`useSharedMemory`。如果此参数为真(缺省值),则与`localhost`或`127.0.0.1`的连接将使用共享内存(如果可能)。要强制连接仅使用`TCP/IP`,请将此参数设置为False。
2. 检查上一步返回的状态:
```java
if $$$ISERR(status) {
quit
}
```
3. 创建任何已编译的样式表。执行此操作时,请将网关参数指定为`%Net.Remote.GatewayInstance`的实例在步骤1中创建。
4. 根据需要调用`%XML.XSLT2.Transformer`的`Transform`方法(`TransformFile()`、`TransformFileWithCompiledXSL()`、`TransformStream()`和`TransformStreamWithCompiledXSL()`)。执行此操作时,请将网关参数指定为在步骤1中创建的`%Net.Remote.Gateway`的实例。
5. 如果不再需要给定的编译样式表,请在调用`%XML.XSLT2.CompiledStyleSheet`的`ReleaseFromServer()`方法:
```java
Set status=##class(%XML.XSLT2.CompiledStyleSheet).ReleaseFromServer(compiledStyleSheet,,gateway)
```
重要提示:当不再需要已编译的样式表时,请务必使用此方法。
6. 当不再需要XSLT网关连接时,调用`%XML.XSLT2.Transformer`的`StopGateway()`方法,并将网关连接作为参数传递:
```java
set status=##class(%XML.XSLT2.Transformer).StopGateway(gateway)
```
此方法丢弃连接并重置当前设备。它不会停止`XSLT 2.0`网关。
重要提示:当不再需要连接时,请务必使用此方法。
有关示例,请参见XSLT2中的`Example10()`方法。`Samples`命名空间中的`Examples`。
# 排除XSLT 2.0网关服务器连接故障
当XSLT 2.0网关打开时,InterSystems IRIS和网关服务器之间的连接可能会变得无效。例如,如果出现网络错误或在InterSystems IRIS连接到网关服务器后重新启动网关服务器,则连接可能无法正常关闭。因此,可能会遇到错误。
可以通过连续调用XSLT网关连接对象的`%LostConnectionCleanup()`方法和`%reconnect`方法,尝试将InterSystems IRIS重新连接到网关服务器。
如果希望在断开连接时自动重新连接到网关服务器,请将网关连接对象的`AttemptReconnect`属性设置为true。
# 创建编译的样式表
如果打算重复使用同一样式表,则可能需要编译该样式表以提高速度。请注意,此步骤会消耗内存。当不再需要编译的样式表时,请务必将其删除。
要创建编译的样式表,请执行以下操作:
- 如果使用的是`Xalan`处理器(对于`XSLT 1.0`),请使用`%XML.XSLT.CompiledStyleSheet`的以下类方法之一:
- `CreateFromFile()`
- `CreateFromStream()`
- 如果使用的是`Saxon`处理器(用于`XSLT 2.0`),请在使用`%XML.XSLT2.CompiledStyleSheet`的以下类方法之一:
- `CreateFromFile()`
- `CreateFromStream()`
另请注意,将需要创建一个XSLT网关连接;请参阅“重用XSLT网关服务器连接(`XSLT 2.0`)”。
对于所有这些方法,完整的参数列表按顺序如下:
1. source - 样式表。
对于`CreateFromFile()`,此参数是文件名。对于`CreateFromStream()`,此参数是一个流。
2. compiledStyleSheet - 编译后的样式表,作为输出参数返回。
这是样式表类(`%XML.XSLT.CompiledStyleSheet`或`%XL.XSLT2.CompiledStyleSheet`,视情况而定)的实例。
3. errorHandler - 编译样式表时使用的可选自定义错误处理程序。
对于这两个类中的方法,这是`%XML.XSLT.ErrorHandler`实例。
4. (仅适用于`%XML.XSLT2.CompiledStyleSheet`)网关-`%Net.Remote.Gateway`的实例
```
//将tXSL设置为等于适当流的OREF
Set tSC=##class(%XML.XSLT.CompiledStyleSheet).CreateFromStream(tXSL,.tCompiledStyleSheet)
If $$$ISERR(tSC) Quit
```
文章
姚 鑫 · 十月 20, 2021
# 第五十一章 SQL命令 HAVING(二)
## In和%INLIST谓词
`IN`谓词用于将值与一系列非结构化的项进行匹配。
`%INLIST`谓词是 IRIS扩展,用于将值与列表结构的元素进行匹配。
使用任一谓词,都可以执行相等比较和子查询比较。
在中有两种格式。第一个用作使用与`OR运`算符链接在一起的多个相等比较的速记。例如:
```sql
SELECT Name, Home_State FROM Sample.Person
GROUP BY Home_State
HAVING Home_State IN ('ME','NH','VT','MA','RI','CT')
```
如果`Home_State`等于括号列表中的任意值,则计算为`TRUE`。列表元素可以是常量或表达式。排序规则适用于IN比较,因为它适用于相等性测试。默认情况下,`IN`比较使用字段定义的排序规则类型;默认情况下,字符串字段定义为`SQLUPPER`,不区分大小写。
当日期或时间用于IN谓词相等比较时,会自动执行适当的数据类型转换。如果`HAVING`子句字段是`TIMESTAMP`类型,则`DATE`或`TIME`类型的值将转换为`TIMESTAMP`。如果`HAVING`子句字段为`DATE`类型,则`TIMESTAMP`或`STRING`类型的值将转换为`DATE`。如果`HAVING`子句字段为TIME类型,则`TIMESTAMP`或`STRING`类型的值将转换为`TIME`。
下面的示例都执行相同的相等比较并返回相同的数据。
`groupby`字段指定对于每个成功的相等比较只返回一条记录。
`DOB`字段的数据类型为`Date`:
```sql
SELECT Name,DOB FROM Sample.Person
GROUP BY DOB
HAVING DOB IN ({d '2014-01-02'},{d '1990-04-25'})
```
```sql
SELECT Name,DOB FROM Sample.Person
GROUP BY DOB
HAVING DOB IN ({ts '2014-01-02 00:00:00'},{ts '1990-04-25 00:00:00'})
```
`%INLIST`谓词可用于对列表结构的元素执行相等比较。
`%INLIST`使用`EXACT`排序。
因此,默认情况下,`%INLIST`字符串比较是区分大小写的。
下面的例子使用`%INLIST`来匹配一个字符串值到`FavoriteColors`列表字段的元素:
```sql
SELECT Name,FavoriteColors FROM Sample.Person
HAVING 'Red' %INLIST FavoriteColors
```
它返回`FavoriteColors`中包含元素`“Red”`的所有记录。
下面的嵌入式SQL示例将`Home_State`列值与`northne`(新英格兰北部各州)列表中的元素匹配:
```java
ClassMethod Having()
{
s northne = $lb("VT","NH","ME")
&sql(
DECLARE StateCursor CURSOR FOR
SELECT Name,Home_State
INTO :name,:state FROM Sample.Person
HAVING Home_State %INLIST :northne
)
&sql(OPEN StateCursor)
q:(SQLCODE'=0)
n %ROWCOUNT,%ROWID
for {
&sql(FETCH StateCursor)
q:SQLCODE
w !,"#",%ROWCOUNT," Name=",name," State=",state,!
}
w !,"Final Fetch SQLCODE: ",SQLCODE
&sql(CLOSE StateCursor)
}
```
```java
DHC-APP>d ##class(PHA.TEST.SQLCommand).Having()
#1 Name=Lepon,Jeff Z. State=NH
#2 Name=Ingleman,Terry A. State=NH
#3 Name=Jung,Keith W. State=NH
#4 Name=Xiang,Kirsten U. State=ME
#5 Name=Jackson,Ralph V. State=VT
#6 Name=Tesla,Geoffrey O. State=NH
```
还可以在子查询中使用`IN`或`%INLIST`来测试列值(或任何其他表达式)是否等于任何子查询行值。
例如:
```sql
SELECT Name,Home_State FROM Sample.Person
HAVING Name IN
(SELECT Name FROM Sample.Employee
HAVING Salary < 50000)
```
注意,子查询在`SELECT`列表中必须只有一个项。
## %STARTSWITH谓词
IRIS `%STARTSWITH`比较操作符允许对字符串或数字的初始字符执行部分匹配。
下面的示例使用`%STARTSWITH`。
它根据年龄进行选择,然后为每个以“S”开头的Name返回一条记录:
```sql
SELECT Name,Age FROM Sample.Person
WHERE Age > 30
HAVING Name %STARTSWITH 'S'
ORDER BY Name
```
与其他字符串字段比较一样,`%STARTSWITH`比较不区分大小写。
## Contains Operator ([)
`Contains`操作符是左括号符号:`[`。
它允许将子字符串(字符串或数字)匹配到字段值的任何部分。
比较总是区分大小写的。
下面的例子在`HAVING`子句中使用`Contains`操作符选择那些`Home_State`值包含`“K”`的记录,然后对这些状态执行`%AFTERHAVING`计数:
```sql
SELECT Home_State,COUNT(Home_State) AS States,
COUNT(Home_State %AFTERHAVING) AS KStates
FROM Sample.Person
HAVING Home_State [ 'K'
```
## FOR SOME谓词
`HAVING`子句的`FOR SOME`谓词决定是否根据一个或多个字段值的条件测试返回结果集。
该谓词的语法如下:
```
FOR SOME (table[AS t-alias]) (fieldcondition)
```
`FOR SOME`指定字段`condition`的值必须为`true`;
至少有一个字段值必须匹配指定的条件。
`Table`可以是单个表,也可以是逗号分隔的表列表,也可以是表别名。
`Fieldcondition`为指定表中的一个或多个字段指定一个或多个条件。
`table`参数和字段`condition`参数都必须用括号分隔。
下面的例子展示了`FOR SOME`谓词的用法:
```sql
SELECT Name,Age
FROM Sample.Person
HAVING FOR SOME (Sample.Person)(Age>20)
ORDER BY Age
```
在上面的示例中,如果至少有一个字段包含大于`20`的`Age`值,则返回所有记录。
否则,不返回任何记录。
## NULL 谓词
这将检测未定义的值。
你可以检测所有空值,或所有非空值:
```sql
SELECT Name, FavoriteColors FROM Sample.Person
HAVING FavoriteColors IS NULL
```
```sql
SELECT Name, FavoriteColors FROM Sample.Person
HAVING FavoriteColors IS NOT NULL
ORDER BY FavoriteColors
```
使用`GROUP BY`子句,可以为指定字段的每个非空值返回一条记录:
```sql
SELECT Name, FavoriteColors FROM Sample.Person
GROUP BY FavoriteColors
HAVING FavoriteColors IS NOT NULL
ORDER BY FavoriteColors
```
## EXISTS 谓词
它使用子查询来测试子查询是否计算为空集。
```sql
SELECT t1.disease FROM illness_tab t1 WHERE EXISTS
(SELECT t2.disease FROM disease_registry t2
WHERE t1.disease = t2.disease
HAVING COUNT(t2.disease) > 100)
```
## LIKE、%MATCHES和%PATTERN谓词
这三个谓词允许执行模式匹配。
- `LIKE`允许使用文字和通配符进行模式匹配。
当希望返回包含已知字面值子字符串的数据值,或在已知序列中包含多个已知子字符串时,请使用`LIKE`。
`LIKE`使用目标的排序规则进行字母大小写比较。
- `%MATCHES`允许使用文字、通配符、列表和范围进行模式匹配。
当希望返回包含已知字面值子字符串的数据值,或包含一个或多个位于可能字符列表或范围内的字面值字符,或在已知序列中包含多个这样的子字符串时,请使用`%MATCHES`。
`%MATCHES`使用`EXACT`排序法进行字母大小写比较。
- 允许指定字符类型的模式。
例如,`'1U4L1",".A'`(`1`个大写字母,`4`个小写字母,一个逗号,后面跟着任意数量的字母字符)。
如果希望返回包含已知字符类型序列的数据值,请使用`%PATTERN`。
当数据值不重要,但这些值的字符类型格式很重要时,`%PATTERN`特别有用。
`PATTERN`还可以指定已知的文字字符。
它使用`EXACT`排序法进行文字比较,这总是区分大小写的。
要与字符串的第一个字符进行比较,请使用`%STARTSWITH`谓词。
# 示例
下面的示例为每个至少有一个`21`岁以下的人的州返回一行。
对于每一行,它返回该州所有人的平均、最小和最大年龄。
```sql
SELECT Home_State, MIN(Age) AS Youngest,
AVG(Age) AS AvgAge, MAX(Age) AS Oldest
FROM Sample.Person
GROUP BY Home_State
HAVING Age < 21
ORDER BY Youngest
```
下面的示例为每个至少有一个`21`岁以下的人的州返回一行。
对于每一行,它返回该州所有人的平均、最小和最大年龄。
使用`%AFTERHAVING`关键字,它还返回该州`21`岁以下的人的平均年龄(`AvgYouth`),以及该州`21`岁以下最年长的人的年龄(`OldestYouth`)。
```sql
SELECT Home_State,AVG(Age) AS AvgAge,
AVG(Age %AFTERHAVING) AS AvgYouth,
MIN(Age) AS Youngest, MAX(Age) AS Oldest,
MAX(Age %AFTERHAVING) AS OldestYouth
FROM Sample.Person
GROUP BY Home_State
HAVING Age < 21
ORDER BY AvgAge
```
文章
姚 鑫 · 八月 24, 2022
# 第十一章 配置数据库(三)
## 编辑本地数据库的属性
显示的信息取决于数据库是否被镜像。本节确定以下字段:
### 部分编辑非镜像本地数据库属性
单击非镜像数据库的名称可查看以下数据库属性并更改其中一些属性。 (“创建本地数据库”部分描述了其中的许多字段。)
- `Name `- `Directory` 目录(此设置必须始终反映 `IRIS.DAT` 数据库文件的位置)- `Encrypted`加密(无法更改)- `Mirrored` 已镜像 — 单击添加到 `Mirrormirror_name` 链接以将数据库添加到其中 `IRIS` 实例是主要故障转移成员的镜像。 (仅当实例是镜像中的主实例时,此选项才可用。)- `Block Size (Bytes)`块大小(字节)(无法更改)- `Size` 大小 (MB) — 共有三种大小设置,如下所示: - `Change Current` 修改数据库的当前大小。 - `Expansion` 扩展设置在需要时扩展数据库的数量;默认(和推荐)设置为零 (`0`) 表示当前大小的 `12%` 或 `10` MB,以较大者为准。使用当前大小的 `12%` 时,扩展大小不会大于 1GB。 - `Maximum` 最大值指定数据库可以增长到的最大大小,以兆字节为单位;默认设置为零 (`0`) 表示没有最大值。要修改此设置,可以输入新的 `MB` 数,也可以在数字前加上 `+` 或 `-`,例如 `+10` 或 `-20`,将最大值放大或缩小指定的量。当小数据库的最大大小时,会收到警告并且必须确认操作。
**注意:不能创建或编辑数据库,使其大小大于可用的总磁盘空间。如果指定的大小在磁盘可用空间的 `90%` 以内,会收到警告并且必须确认操作。**
- `Resource Name` 资源名称 — 选择与数据库关联的资源。单击下拉列表旁边的资源图标以显示“资源”页面,以便可以创建资源。- `New Global` 新全局 - 为新`globals`指定属性。- `Global Journal State` 全局日志状态 — 选择启用日志,清除禁用。- `Preserve global attributes on delete` 删除时保留global属性——指定删除时是否应保留global的目录条目和属性;属性包括排序规则、日志状态和增长指针。当global被完全删除时,选择保留global的目录条目和属性; `clear` 删除目录条目和属性。- `Mount Read-Only` — 选择以指定数据库以只读方式安装; `clear` 指定它以读写方式挂载。- `Mount Required at Startup` — 选择以指示在 `IRIS` 启动时必须安装数据库;如果无法安装数据库, `IRIS` 不会启动。这使可以确保在崩溃后启动之前可以在数据库上执行日志恢复和事务回滚(如数据完整性指南的“日志”一章中所述)。清除让 `IRIS` 无需先安装数据库即可启动。
**注意:默认情况下,为所需的 `IRIS` 数据库(例如,`IRISLIB` 和 `IRISAUDIT`)选择此设置并且无法更改。默认值已清除,但可以为创建的数据库以及 `USER` 和 `ENSLIB` 数据库选择)。**
- `Stream Location`流位置 — 单击“浏览”按钮选择与该数据库关联的流的存储目录。默认情况下,本地数据库的流位置是数据库目录中名为 `stream` 的子目录,它是上述字段之一(例如 `install-dir\mgr\DB1\stream`)。
**注意: 建议使用默认位置。**
### 编辑镜像本地数据库属性
单击镜像数据库的名称可以查看和更改以下一些数据库属性;请参阅上一节中的定义。
**注意:镜像数据库需要日记功能,因此不会出现`Global Journal State`全局日记状态设置。**
- `Name`- `Mirror Name` 镜像名称——在镜像中识别数据库的名称;无法更改。- `Directory` 目录(此设置必须始终反映 `IRIS.DAT` 数据库文件的位置)- `Encrypted` 加密(无法更改)- `Stream Location` 流位置 — 单击“浏览”按钮选择与该数据库关联的流的存储目录。默认情况下,本地数据库的流位置是数据库目录中名为 `stream` 的子目录,它是上述字段之一(例如 `install-dir\mgr\DB1\stream`)。
**注意:与不包含在数据库本身中的其他数据库相关数据一样,镜像数据库的文件流不会被镜像。 建议使用默认位置。**
- `Resource Name` 资源名称 — 选择与数据库关联的资源。单击下拉列表旁边的资源图标以显示“资源”页面,以便可以创建资源。- `Block Size (Bytes)`块大小(字节)(无法更改)- `Collation` 排序规则 - 在全局属性中,只有排序规则属性可以更改,仅适用于新的全局变量。- `Preserve global attributes on delete`删除时保留`global`属性——指定删除时是否应保留global的目录条目和属性;属性包括排序规则、日志状态和增长指针。当global被完全删除时,选择保留global的目录条目和属性; clear 删除目录条目和属性。- `Mount Read-Only` — 选择以指定数据库以只读方式安装; `clear` 指定它以读写方式挂载。- `Mount Required at Startup` — 选择以指示在 `IRIS` 启动或成为镜像主数据库时必须安装数据库;如果无法安装数据库, `IRIS` 不会启动或成为主数据库。这使可以确保在崩溃后启动之前可以在数据库上执行日志恢复和事务回滚,并且前主数据库上的打开事务已作为一部分回滚的故障转移。清除让 IRIS 无需先安装数据库即可启动。- `Local Properties` 本地属性 — 此区域包含三个大小设置,如下所示: - `Change Size` 修改数据库的当前大小。
- 扩展设置在需要时扩展数据库的数量(并假设可用空间);默认(和推荐)设置为零 (`0`) 表示当前大小的 `12%` 或 `10 MB`,以较大者为准。 - 最大值指定数据库可以增长到的最大大小,以兆字节为单位;默认设置为零 (`0`) 表示没有最大值。要修改此设置,您可以输入新的 MB 数,也可以在数字前加上 `+` 或 `-`,例如 `+10` 或 `-20`,将最大值放大或缩小指定的量。当减小数据库的最大大小时,您会收到警告并且必须确认操作。
该区域还包含其他系统的当前、扩展和最大大小设置 — 如果当前实例是故障转移成员,则这是另一个故障转移成员;如果当前实例是异步成员,则这是异步可以从中获取信息的第一个故障转移成员。 **注意:不能创建或编辑数据库,使其大小大于可用的总磁盘空间。如果指定的大小在磁盘可用空间的 `90%` 以内,会收到警告并且必须确认操作。**
文章
Hao Ma · 五月 4, 2023
当系统发生严重危机,一般错误,以及其他需要管理员关注的其他事件发生时, 管理员必须及时的收到系统发出的警告信息。
上篇文章中介绍了控制台日志。这是个文本文件,包含几乎所有的系统级别的错误信息,并且有严重级别的标识,那么使用工具来监控控制台日志文件,并给管理员发送通知是可行的方案吗?
当然。实际上,有些用户正是这样来管理Caceh'/IRIS的。他们有自己熟悉的监控工具,实时读取控制台日志,分析内容,并完成警告通知的发送。
这篇文章我来介绍的是Cache'/IRIS内置的处理警告的机制和配置方法。 通过把严重的错误和事件写入另一个文本文件alert.log,并配置邮件,SNMP, API接口发送通知,可以基本的实现caceh'/IRIS系统的警告通知工作。
### Alerts.log
控制台日志中最严重的两个级别(级别2和3), 的记录会被写入另一个文本文件,名字是Alert.log。 默认存储于\installDir\mgr\路径。
-
在操作门户中“系统>系统日志>控制台日志” ,你会发现 Alerts.log的内容会以红色的字体显示在最上方。比如下图中有2个严重级别的Alert。
另外, 告警的条目数量会显示在系统仪表板的“错误和告警”模块中的‘严重告警’(Serious Alerts)栏。
注意,**这里的数值只显示30分钟内非启动过程中的Alert条目数**。比如上面例子中产生了一条“Failed to allocate…”的告警,因为是启动过程中的记录,因此仪表板中的严重告警数值为1。而如果30分钟内不再发生 “Winter is coming”的告警,此数值会减为0.
**关于alerts.log, 您还需要知道:**
- 每次系统重启该文件也会清除重置。
- 对alerts.log的内容,用户可以使用系统工具^MONMGR配置发送告警邮件
- 除了来自控制台日志,Alerts.log的记录还可以是来自其他来源
是的。底层的系统内核以及开发工具可以直接写告警信息到Alert.log, 而不通过控制台日志,应用监视器%Monitor.Adaptor就是这么一个开发工具,有些开发者使用它来向alert.log直接写入记录。
细心的读者可能注意到上面图中有个告警内容是*“Winter is coming”*,它是为了测试用以下命令产生的。
`do ##class(%SYS.System).WriteToConsoleLog("winter is coming",,2)`
这也是为什么要单独保留一个Alert日志文件,在设计者的想法里, alert.log不是只从控制台日志拿记录,它还可以有多个可能的来源。
**可以把控制台日志中的“警示性错误(Warning)”写入Alert.log吗?**
可以,但管理员必须清楚的知道这样会收到很多不严重的警示信息。通常这样做的理由是用户有自己的监控手段监控Alert.log这个文件,那么先把Warning写入Alert.log,随后用自己的方式去过滤,这是个合理的解决方案。
读取控制台日志到Alert.log的工具在早期版本中被称为Caché Monitor,这是个非常恼人的名字,好在新版本里改称为“Log Monitor”。默认的配置中,Log Monitor每10秒扫描一下控制台日志,将级别2,3的记录写入Alert.log。配置和修改log monitor使用终端工具^MONMGR,它可以修改写入错误的级别选择和采样的间隔(Monitor Interval)。
```
%SYS>do ^MONMGR
1) Start/Stop/Update MONITOR
2) Manage MONITOR Options
3) Exit
Option? 2
1) Set Monitor Interval
2) Set Alert Level
3) Manage Email Options
4) Exit
Option? 2
Alert on Severity (1=warning,2=severe,3=fatal)? 2 =>
1) Set Monitor Interval
2) Set Alert Level
3) Manage Email Options
4) Exit
Option? 4
```
### Alert.log内容的发送
系统内嵌的发送通知的方式有以下几种:
#### 发送告警邮件
这是系统默认的Alert的通知方式。使用^MONMGR配置配置您的邮件地址和服务器。
```
SYS>do ^MONMGR
1) Start/Stop/Update MONITOR
2) Manage MONITOR Options
3) Exit
Option? 2
1) Set Monitor Interval
2) Set Alert Level
3) Manage Email Options
4) Exit
Option? 3
1) Enable/Disable Email
2) Set Sender
3) Set Server
4) Manage Recipients
5) Set Authentication
6) Test Email
7) Exit
Option?
```
#### SNMP Trap
通过SNMP Trap发送通知/警告也是非常常用的方案。无论是Cache'还是IRIS, 您都可以在SNMP客户端使用SNMP收集采样指标,接收alert消息。具体的操作内容,我会在单独的文章介绍。这里只是简单的描述下步骤:
- 确认操作系统的SNMP服务已启动
- 在Cache'/IRIS管理门户“System>Security Management >Services”启动%Service_Monitor服务.
- 到“Monitor Setting"页面确认“the monitor service is Enabled"
- 重启实例。
以下是使用snmptrapd命令接收的alert的例子:
```
Received 113 byte packet from UDP: [172.16.58.200]:60620->[0.0.0.0]:0
0000: 30 6F 02 01 00 04 06 70 75 62 6C 69 63 A4 62 06 0o.....public�b.
0016: 0A 2B 06 01 04 01 81 81 33 01 02 40 04 AC 10 3A .+......3..@.�.:
0032: C8 02 01 06 02 01 0F 43 02 5D 33 30 44 30 1A 06 �......C.]30D0..
0048: 12 2B 06 01 04 01 81 81 33 01 01 01 01 01 04 48 .+......3......H
0064: 53 41 50 04 04 48 53 41 50 30 26 06 12 2B 06 01 SAP..HSAP0&..+..
0080: 04 01 81 81 33 01 01 01 01 08 04 48 53 41 50 04 ....3......HSAP.
0096: 10 77 69 6E 74 65 72 20 69 73 20 63 6F 6D 69 6E .winter is comin
0112: 67
```
注意: snmp trap的发送发生在alerts.log的写入时。重复消息写入Alert的时限是30分钟。切换执行的进程,比如重新打开另一个terminal进程会重新计数。
#### REST API
通过REST接口查看alert内容是IRIS的新特性。下面的查看结果中有4个alert记录。原始输出的json是给机器读的,堆在一起很难看,我做了格式化,更方便人读。
注意的一点: 通过REST读取alert的内容每次只能读到新的alerts。也就是说,当再次GET的时候, 如果和上次查看的间隔中没有新alert记录出现,GET的结果是空,虽然这时候alert.log的文件里还是有很多记录。
```json
hma@CNMBPHMA ~ % curl http://localhost:52773/api/monitor/alerts
[
{
"time": "2023-05-04T02:12:05.647Z",
"severity": "2",
"message": "Preserving journal files /usr/irissys/mgr/journal/20230421.002 and later for journal recovery and transaction rollback"
},
{
"time": "2023-05-04T02:13:35.671Z",
"severity": "2",
"message": "[SYSTEM MONITOR] DiskPercentFull(/external/demo/) Alert: DiskPercentFull = 91.34, 91.34, 91.34 (Max value is 90)."
},
{
"time": "2023-05-04T02:13:35.671Z",
"severity": "2",
"message": "[SYSTEM MONITOR] DiskPercentFull(/external/oeesp/) Alert: DiskPercentFull = 91.34, 91.34, 91.34 (Max value is 90)."
},
{
"time": "2023-05-04T02:13:35.672Z",
"severity": "2",
"message": "[SYSTEM MONITOR] DiskPercentFull(/external/smart/) Alert: DiskPercentFull = 91.34, 91.34, 91.34 (Max value is 90)."
}
]
```
#### Monitoring Web Service
Caché Monitoring Web Service是一个提供系统采样值的Web服务,简单的说,您在用户界面上看到的所有指标,都可以从这个Web服务得到。
它的其中一个服务是EventSubscribe,用户调用这个服务,订阅Caché Event, 提供用户自己的Web服务调用地址,服务规范拷贝Monitoring Web Service中的EventSink服务,这是服务就是专门提供给客户的一个WSDL模板。当Caché产生Warning或者Alert时,Caché会调用用户的Web服务发送通知。这是一个不太常用的方案,感兴趣的用户可以查看产品手册中“Monitoing Caché Using Web Services”部分。
文章
Claire Zheng · 三月 22, 2022
最在第一期“极客聊吧”中,InterSystems销售工程师们聊了聊这些话题:为什么有些医院和某些商保之间可以直接结算,有些又不能?医院和保险之间的结算难在哪儿?在InterSystems 2021全球线上峰会中提到的医保结算案例对国内实践有哪些借鉴意义?FHIR又能起到什么关键作用?医疗数据实现互联互通的关键是什么?以下是文字版。
点击查看视频。
#从商保结算谈起#
菁伟 (@Jingwei.Wang ):大家好,我是InterSystems的销售工程师王菁伟,这是我的同事祝麟和刘皆良(Jeff)。今天我们一块来聊聊HIT行业里的数据交互那点事。去医院就诊的话,我们会发现有些医院可以和某些商业保险直接结算,有的医院或者某些保险产品又不能。为什么直结这个流程没有全面开通呢?
祝麟 ( @Lin.Zhu ):我们虽然平时看病都基本实现了医保直连, 但实际上背后医院的信息科和供应商付出了大量的努力,比如供应商就需要要适应各地医保结算流程和政策的差异,这个过程的数字化还是有很大难度的,也没法一蹴而就。
Jeff ( @Jieliang.Liu ):到商保这一侧,可以观察到很多商保产品的直结清单是逐年递增。那么保险公司的产品是一家一家和医院对接的,难度恐怕更大。
菁伟 (@Jingwei.Wang ):医院和保险之间的结算过程到底为什么落地困难呢?
祝麟 ( @Lin.Zhu ):原因很多,既有政策层面的,也有技术层面的。比如医院和院外机构间通信的安全性保障就是问题,如果没有安全的公共平台进行数据交换,哪家医院也不能独立承担数据流出医院的安全风险,这在政策的制定和技术的实现方面都有挑战。
Jeff ( @Jieliang.Liu ):医院和保险之间的接口也是问题,不同的医院会采用不同厂家提供的系统,不同保险公司采用的数据接口肯定也不一样,是个典型的多对多集成的问题,工作量会比较大,实施周期也很长。
#借鉴国际成功案例#
菁伟 (@Jingwei.Wang ):去年InterSystems的全球峰会上HealthShare的分论坛里是不是就谈到了医保结算的场景?这个案例对实现直接结算有没有借鉴意义呢?
祝麟 ( @Lin.Zhu ):是的。本身医保结算这个事是个全球性的挑战。除了我们国家以外,即使是商保比较发达的欧美国家,在打通流程方面也是处于进行中的状态。这次峰会上HealthShare发布解决方案,实现了CMS,也就是美国医保局所定义的医疗服务提供方和支付方的交互规范。这个方案覆盖的正是医疗机构、支付方以及患者三者之间结算和信息交互流程。
菁伟 (@Jingwei.Wang ):也就是说满足了政策要求?
Jeff ( @Jieliang.Liu ):也包含技术要求。CMS定义的交互流程和数据模型是以FHIR为载体的。
祝麟 ( @Lin.Zhu ):是的。CMS定义的交互规约既包含流程规范,也包含接口和数据规范,目前是以FHIR R4规定的,所以必须以FHIR API的形式实现。
#如何准确理解FHIR能力#
菁伟 (@Jingwei.Wang ):那么,现在有没有实际的案例使用FHIR来完成业务功能呢?
Jeff ( @Jieliang.Liu ):有的。我们在国际上已经看到不少基于FHIR的业务出现。比如我们和UC Davis Health以及Centene合作进行了医保预授权的自动化项目,就是基于FHIR的。在这个项目里,UC Davis Health的角色是医疗机构,Centene是保险的支付方,采用HealthShare作为平台来支撑不同角色间的实时交互。
祝麟 ( @Lin.Zhu ):UC Davis Health的医生在Epic的电子病历系统里下达医嘱,系统把患者和医嘱信息按自定义接口发到HealthShare;HealthShare将请求转为FHIR标准再通过FHIR接口与Centene的系统交互,检查这些医嘱能不能被Centene的保险产品覆盖,再把结果通过HealthShare转回到医生那儿。这样就可以在下达医嘱时实时地通过预授权的检验,杜绝医保拒付的情况。先不说杜绝拒付问题能节省的开支,光是将预授权自动化这一项,和人工处理相比,就能把每一单预授权的处理成本从3.68美金降到0.04美金,那每处理一百万次预授权就能省下几百万美金了。
菁伟 (@Jingwei.Wang ):那么,假设我们有一个集成平台,通过平台实现FHIR API接口,不同的系统通过FHIR API与集成平台对接,是不是就能解决数据交互问题呢?
祝麟 ( @Lin.Zhu ):这是个非常好的问题。FHIR在设计之初就声明采用了剃刀原理,它大概只能覆盖80%常见的交互需求。因此,对于差异化的需求或者是新技术引入的新的数据交互需求,FHIR要借助除了API之外的额外机制来解决这个问题。在医疗行业,我们现在经常遇到医疗文档共享或者跨机构流程这样的业务场景,除了API。Jeff,你认为平台这个层面还需要什么样的一些能力来支撑这些场景呢?
Jeff ( @Jieliang.Liu ):Profile。针对患者健康档案共享和支付方之间的数据交换两个不同的场景,需要分别遵循USCore profile和PDex Profile的规约。也就是说在可预见的未来,对于一家医院或者一个区域级的数据交换中心来说,需要能够支持不同的Profile以应对不同的场景。
菁伟 (@Jingwei.Wang ):这些不同的Profile之间有什么差别吗?
Jeff ( @Jieliang.Liu ):首先我们需要明白Profile立意于使用FHIR支持差异化的用例或场景。因此,一个合法的Profile就只覆盖这个场景所需要使用的模型而不会涉及到其他用例的内容。
US Core和PDex 这两个Profile首先在定位上不太一样。US Core面向患者就诊过程的信息交换,对就诊中的涉及例如治疗计划、体征和检验结果这样的临床信息进行了定义;而PDex是面向医保结算的用例,就会包含报销范围,支付方的组织机构信息这样一些和医保报销相关的信息,由CPCDS这个数据集定义。当然PDex也会引用US Core中定义的内容,比如患者的身份、病史、体征、检验结果,在PDex里这些临床信息是直接引用US Core里的定义的。
祝麟 ( @Lin.Zhu ):没错,正如同我们在医院信息互联互通标准化成熟度测评过程中可以体会到文档交换和服务调用是面向不同用例的交互手段,两者的信息构造有差异。那么使用FHIR进行交互时,面对不同的应用场景时完全可能需要套用不同的Profile,甚至是借助Profile套用特定的术语。因此,Profile之间会有很多差异。
如果FHIR在中国落地,可以想象到,由于医疗技术上我们包含中医,医疗福利上我们有医保和商保,还有很多其他差异,我们也需要有中国自己定义的多个Profile去投入使用。
因此,对FHIR的支持不能仅仅体现在支持HL7官网发布的协议结构上。支持多Profile,能够根据地区、应用场景的不同导入并套用Profile对于医疗行业的集成引擎、数据平台这样的产品是一项至关重要的FHIR能力。
Jeff ( @Jieliang.Liu ):除了遵循协议之外,还有数据架构。在HealthShare的解决方案里包含了一个整合好的数据存储。
祝麟 ( @Lin.Zhu ):是的,有一份在各业务系统之上,经过整合与泛化统一存储的数据能够极大简化应用标准协议的成本。大家可以想象一下,对于使用FHIR来说,在多Profile模式下运行的一个体系,如果没有一份整合的数据,那么每次要支持一个新的Profile,特别是和上一次应用的Profile所需的资源不一样,术语可能也不一样的时候,实施方需要再一次挨个把和各个业务系统的映射再做一遍,这个代价和周期可想而知。
菁伟 (@Jingwei.Wang ):梳理和整合数据存储的话,这样一套方案就不是单纯的集成平台方案了。
祝麟 ( @Lin.Zhu ):没错,这是因为采用集成平台,和采用集成加数据整合的医院信息平台,要解决的问题是不一样的。
当单纯应用集成平台整合流程时,要解决是打破烟囱的问题,但还谈不上整合数据与数据利用。对于这样的场景,即使点对点地两两集成,也能解决问题,坦率说除非每个应用系统都能支持某个标准协议通信,否则采不采用协议进行集成并不关键。但如果要上线统一患者档案这样的业务,就需要整合和泛化数据并进行存储,如何利用这份数据就是协议可以发挥作用的地方了。
Jeff ( @Jieliang.Liu ):日本群马大学医学部附属医院就用我们的产品作为信息平台使用。应用InterSystems IRIS作为信息交换引擎从HIS、检验这样的系统里通过实时和批量数据同步接口获取数据,转换为FHIR并存储在InterSystems IRIS的FHIR存储库里。这个FHIR存储库所承担的就是临床数据中心的角色。它们的科研系统REDCap则通过FHIR对这个存储库进行查询并获得患者档案。现在这个项目也还在扩展,通过和Apple的技术融合实现患者端对自己的临床档案的访问。
祝麟 ( @Lin.Zhu ):是的,FHIR API本身就能支持数据利用和数据共享。院里要做科研的话也可以通过FHIR API查询符合条件的患者集合,比如查2021年11月到12月间就诊的低密度脂蛋白低于100的II型糖尿病患者,这是个典型的数据利用问题。如果不借助一份整合好的数据,只凭借单纯的集成平台,那就需要把这样的请求解析并分解到不同的业务系统,再把结果整合起来,才能获得结果。实施难度大,业务压力大不说,效率还没有保障。直接从支持FHIR的存储库里获取数据要高效得多。
Jeff ( @Jieliang.Liu ):使用FHIR资源仓库还有一大好处是,FHIR资源仓库并不意味着中心化的存储,而是由一系列物理上分布的资源仓库组成。这些离散的仓库各自保存特定的数据,通过资源间的相互引用形成逻辑上的统一。由于这种引用本质上松耦合,因此能够形成一个逻辑上整合的数据中心。也因为物理离散而逻辑统一,FHIR存储库非常适合用在微服务架构中。当然无论如何,物理上分布的数据也仍然需要通过FHIR统一逻辑概念和语意,以便在异构的系统间和组织机构间进行共享。
因此在应用FHIR相关的技术方面,FHIR接口是个基本的合规要求,多Profile的支持和FHIR存储库则更加关键,这是两个会直接影响FHIR是否能落地的重要特性。
#小谈互联互通#
菁伟 (@Jingwei.Wang ):标准接口和整合数据存储,这个概念听着很耳熟。
Jeff ( @Jieliang.Liu ):当然。一是互联互通的推荐架构里,是包含临床数据中心的,也是对整合应用数据提出了要求。另外,InterSystems在介绍方案时,通常也是把集成平台、数据中心看作是一个解决方案中的两个组成部分来看的。
祝麟 ( @Lin.Zhu ):没错,随着互联互通这项工作的逐渐推广,相信各家医院和区域数据中心都会收到越来越多数据开放和应用的需求。基于FHIR的数据交换和数据利用会经历越来越多的讨论,我们也会见到大量的交互场景通过FHIR实现的案例,以及基于FHIR特性的智能应用的出现。
菁伟 (@Jingwei.Wang ):感谢两位工程师与大家分享FHIR的案例和FHIR协议落地时所需要的平台能力。FHIR除了资源和接口的定义之外,还有许多特性能够帮助医疗机构打通数据流程。作为一个面向互操作性的协议,相信未来我们还会见到更多通过FHIR支撑的业务场景。
文章
姚 鑫 · 三月 9, 2021
# 第六章 SQL定义和使用视图
视图是一种虚拟表,由执行时通过`SELECT`语句或几个`SELECT`语句的`UNION`从一个或多个物理表中检索到的数据组成。 `SELECT`可以通过指定表或其他视图的任意组合来访问数据。因此,存储了视图的视图提供了物理表的所有灵活性和安全性特权。
InterSystemsIRIS®数据平台上的InterSystems SQL支持在视图上定义和执行查询的功能。
注意:不能对以只读方式安装的数据库中存储的数据创建视图。
无法在通过ODBC或JDBC网关连接链接的`Informix`表中存储的数据上创建视图。这是因为InterSystems IRIS查询转换对这种类型的查询使用FROM子句中的子查询。 `Informix`不支持`FROM`子句子查询。
# 创建一个视图
可以通过几种方式定义视图:
- 使用SQL `CREATE VIEW`命令(在DDL脚本中或通过JDBC或ODBC)。
- 使用管理门户的“创建视图”界面。
视图名称:不合格的视图名称是一个简单的标识符:`MyView`。合格的视图名称由两个简单的标识符组成,即模式名称和视图名称,以句点分隔:`MySchema.MyView`。视图名称和表名称遵循相同的命名约定,并对不合格的名称执行相同的架构名称解析。同一模式中的视图和表不能具有相同的名称。
可以使用`$SYSTEM.SQL.ViewExists()`方法确定视图名称是否已存在。此方法还返回投影视图的类名称。可以使用`$SYSTEM.SQL.TableExists()`方法确定表名是否已存在。
视图可用于创建表的受限子集。以下嵌入式SQL示例创建一个视图,该视图限制了可以通过该视图访问的原始表的行(通过`WHERE`子句)和列(假设`Sample.Person`包含两个以上的列):
```java
/// d ##class(PHA.TEST.SQL).View()
ClassMethod View()
{
&sql(CREATE VIEW Sample.VSrStaff
AS SELECT Name AS Vname,Age AS Vage
FROM Sample.Person WHERE Age>75)
IF SQLCODE=0 {
WRITE "创建一个视图",!
} ELSEIF SQLCODE=-201 {
WRITE "视图已经存在",!
} ELSE {
WRITE "SQL报错: ",SQLCODE," ",%msg,!
}
}
```
```java
DHC-APP>d ##class(PHA.TEST.SQL).View()
创建一个视图
```
以下嵌入式SQL示例基于`SalesPeople`表创建一个视图,并创建一个新的计算值列`TotalPay`:
```java
/// d ##class(PHA.TEST.SQL).View1()
ClassMethod View1()
{
&sql(CREATE VIEW Sample.VSalesPay AS
SELECT Name,(Salary + Commission) AS TotalPay
FROM Sample.SalesPeople)
IF SQLCODE=0 {
WRITE "创建一个视图",!
} ELSEIF SQLCODE=-201 {
WRITE "视图已经存在",!
} ELSE {
WRITE "SQL报错: ",SQLCODE," ",%msg,!
}
}
```
## 管理门户创建视图界面
可以从管理门户创建视图。转到InterSystems IRIS管理门户。在系统资源管理器中,选择SQL。使用页面顶部的Switch选项选择一个名称空间;这将显示可用名称空间的列表。选择名称空间后,单击“操作”下拉列表,然后选择“创建视图”。
这将显示“创建视图”窗口,其中包含以下字段:
- 模式:可以决定将视图包含在现有模式中,也可以创建一个新模式。如果选择选择现有模式,则会提供一个现有模式的下拉列表。如果选择创建新架构,请输入架构名称。在这两种情况下,如果省略模式,则InterSystems IRIS都会使用系统范围内的默认模式名称。
- 视图名称:有效的视图名称。不能对同一模式中的表和视图使用相同的名称。
- 使用`Check Option`:选项为`READONLY`,`LOCAL`,`CASCADED`。
- 将视图的所有特权授予`_PUBLIC`:如果选中,则此选项为该视图授予所有用户执行特权。默认设置是不授予所有用户访问该视图的权限。
- 查看文字:可以通过以下三种方式中的任意一种来指定查看文字:
- 在“查看文本”区域中键入SELECT语句。
- 使用查询生成器创建`SELECT`语句,然后按OK将此查询提供给“查看文本”区域。
- 如果在Management Portal SQL界面的左侧选择了一个缓存查询名称(例如`%sqlcq.USER.cls4`),然后调用`Create View`,则该缓存查询将提供给“视图文本”区域。请注意,在保存视图文本之前,必须在“视图文本”区域中用实际值替换主机变量引用。
## 视图和相应的类
定义视图时,InterSystems IRIS会生成一个相应的类。按照名称转换规则,SQL视图名称用于生成相应的唯一类名称。 Management Portal SQL界面显示现有视图的“目录详细信息”,包括此类名称。
# 修改视图
在Management Portal SQL界面中,可以选择一个现有视图以显示该视图的“目录详细信息”。 “目录详细信息视图信息”选项显示“编辑视图”链接,该链接提供了用于编辑视图文本(视图的`SELECT`语句)的界面。它还提供了一个下拉列表,以将“带检查选项”选择为无,`READONLY`,`LOCAL`或`CASCADED`。
# 可更新的视图
可更新的视图是可以在其上执行`INSERT`,`UPDATE`和`DELETE`操作的视图。仅当满足以下条件时,才认为视图是可更新的:
- 视图查询的`FROM`子句仅包含一个表引用。该表引用必须标识可更新的基表或可更新的视图。
- 视图查询的`SELECT`列表中的值表达式必须全部是列引用。
- 视图的查询中不得指定`GROUP BY`,`HAVING`或`SELECT DISTINCT`。
- 该视图不是投影为视图的类查询。
- 视图的类不包含类参数`READONLY = 1`(如果视图定义包含`WITH READ ONLY`子句,则为`true`)。
## WITH CHECK选项
为了防止在视图上执行`INSERT`或`UPDATE`操作,而该操作会导致基础基表中的行不属于派生视图表的一部分,InterSystems SQL在视图定义中支持`WITH CHECK OPTION`子句。此子句只能与可更新视图一起使用。
`WITH CHECK OPTION`子句指定可更新视图上的任何`INSERT`或`UPDATE`操作必须对照视图定义的WHERE子句验证结果行,以确保插入或修改的行将成为派生视图表的一部分。
例如,以下DDL语句定义了一个可更新的`GoodStudent`视图,其中包含所有具有高`GPA`(平均绩点)的学生:
```java
CREATE VIEW GoodStudent AS
SELECT Name, GPA
FROM Student
WHERE GPA > 3.0
WITH CHECK OPTION
```
由于视图包含`WITH CHECK OPTION`,因此任何尝试在`GPA`值小于或等于3.0的`GoodStudent`视图中插入或更新行都将失败(此类行将不表示“好学生”)。
有两种类型的`WITH CHECK`选项:
- `WITH LOCAL CHECK`选项意味着只检查`INSERT`或`UPDATE`语句中指定的视图的`WHERE`子句。
- 与级联检查选项(和级联检查选项)意味着视图的`WHERE`子句中指定的`INSERT`或`UPDATE`语句以及所有视图检查基于这一观点,无论外表或与当地检查没有其他选项在这些视图定义条款。
如果指定了`just WITH CHECK`选项,默认值是级联的。
在更新或插入期间,在为基础表的字段计算了所有默认值和触发的计算字段之后,并在常规表验证(必需字段、数据类型验证、约束等)之前,检查`WITH CHECK`选项条件。
在`WITH CHECK`选项验证通过后,插入或更新操作继续进行,就像在基表本身上执行插入或更新一样。
检查所有约束,拉出触发器,等等。
如果在`INSERT`或`UPDATE`语句中指定了`%NOCHECK`选项,则不检查`WITH CHECK`选项的有效性。
有两个与`WITH CHECK`选项验证相关的`SQLCODE`值(插入/更新会导致派生视图表中不存在一行):
- `SQLCODE -136`-`INSERT`中视图的`WITH CHECK OPTION`验证失败。
- `SQLCODE -137`-视图的`WITH CHECK OPTION`验证在`UPDATE`中失败。
# 只读视图
只读视图是不能在其上执行`INSERT`,`UPDATE`和`DELETE`操作的视图。任何不符合可更新视图标准的视图都是只读视图。
视图定义可以指定`WITH READ ONLY`子句,以强制其成为只读视图。
如果尝试针对只读视图编译/准备`INSERT`,`UPDATE`或`DELETE`语句,则会生成`SQLCODE -35`错误。
# 查看ID:%VID
InterSystems IRIS为视图或`FROM`子句子查询返回的每一行分配一个整数视图`ID`(`%VID`)。与表行`ID`号一样,这些视图行`ID`号是系统分配的,唯一的,非空的,非零的和不可修改的。该`%VID`通常对用户不可见,并且仅在明确指定时返回。它以数据类型`INTEGER`返回。因为`%VID`值是顺序整数,所以如果视图返回有序数据,它们将更有意义。视图与TOP子句配对时,只能使用`ORDER BY`子句。以下嵌入式SQL示例创建一个名为`VSrStaff`的视图:
```java
/// d ##class(PHA.TEST.SQL).View()
ClassMethod View()
{
&sql(CREATE VIEW Sample.VSrStaff
AS SELECT Name AS Vname,Age AS Vage
FROM Sample.Person WHERE Age>75)
IF SQLCODE=0 {
WRITE "创建一个视图",!
} ELSEIF SQLCODE=-201 {
WRITE "视图已经存在",!
} ELSE {
WRITE "SQL报错: ",SQLCODE," ",%msg,!
}
}
```
下面的示例返回`VSrStaff`视图定义的所有数据(使用`SELECT *`),并且还指定应返回每一行的视图`ID`。与表行`ID`不同,使用星号语法时不显示视图行`ID`。仅当在`SELECT`中明确指定时才显示:
```java
SELECT *,%VID AS ViewID FROM Sample.VSrStaff
```
`%VID`可用于进一步限制`SELECT`从视图返回的行数,如以下示例所示:
```java
SELECT *,%VID AS ViewID FROM Sample.VSrStaff WHERE %VID BETWEEN 5 AND 10
```
**因此,可以使用`%VID`代替`TOP`(或除`TOP`之外)来限制查询返回的行数。通常,`TOP`子句用于返回数据记录的一小部分。 `%VID`用于返回大多数或所有数据记录,以小的子集返回记录。此功能可能很有用,尤其是对于移植Oracle查询(`%VID`轻松映射到Oracle ROWNUM)而言。但是,与`TOP`相比,用户应了解使用`%VID`时的一些性能限制:**
- `%VID`不执行第一行时间优化。 `TOP`优化为尽快返回第一行数据。 `%VID`优化以尽快返回完整的数据集。
- 如果查询指定排序的结果,则`%VID`不会执行有限的排序(这是`TOP`进行的特殊优化)。该查询首先对完整的数据集进行排序,然后使用`%VID`限制返回数据集。 `TOP`是在排序之前应用的,因此`SELECT`只能执行有限的排序,仅涉及有限的行子集。
为了节省第一行优化和有限排序优化的时间,可以将`FROM`子句子查询与`TOP`和`%VID`结合使用。在`FROM`子查询中指定上限(在本例中为10)作为`TOP`的值,而不是使用`TOP ALL`。使用`%VID`在`WHERE`子句中指定下限(在这种情况下,`> 4`)。以下示例使用此策略返回与上一个视图查询相同的结果:
```sql
SELECT *,%VID AS SubQueryID
FROM (SELECT TOP 10 Name,Age
FROM Sample.Person
WHERE Age > 75
ORDER BY Name)
WHERE %VID > 4
```
即使显式指定了`%PARALLEL`关键字,也无法对指定`%VID`的查询执行并行执行。
# List视图属性
`INFORMATION.SCHEMA.VIEWS`持久类显示有关当前名称空间中所有视图的信息。它提供了许多属性,包括视图定义,视图的所有者以及创建和最后修改视图时的时间戳。这些属性还包括视图是否可更新,如果可更新,是否使用检查选项定义。
在嵌入式SQL中指定时,`INFORMATION.SCHEMA.VIEWS`需要`#include%occInclude`宏预处理程序指令。 `Dynamic SQL`不需要此伪指令。
`VIEWDEFINITION`属性(`SqlFieldName = VIEW_DEFINITION`)以字符串形式返回当前名称空间中所有视图的视图字段名称和视图查询表达式。例如,
```sql
SELECT View_Definition FROM INFORMATION_SCHEMA.VIEWS
```
返回诸如`“(vName,vAge)SELECT Name,Age FROM Sample.Person WHERE Age> 21”`的字符串。当从Management Portal SQL执行查询界面发出时,此字符串的显示仅限于前100个字符,其中不包括空格和换行符,并且(如有必要)附加表示省略号的省略号(`...`)。否则,发出此查询将为每个视图返回最多`1048576`个字符的字符串,在视图字段列表和查询文本之间有一个换行符,并保留了视图查询表达式中指定的空格,并(如有必要)附加了省略号(`...`)表示内容被截断。
以下示例返回当前名称空间中所有视图的视图名称(Table_Name字段)和所有者名称:
```sql
SELECT Table_Name,Owner FROM INFORMATION_SCHEMA.VIEWS
```
以下示例返回当前名称空间中所有非系统视图的所有信息:
```sql
SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE Owner != '_SYSTEM'
```
`INFORMATION.SCHEMA.VIEWCOLUMNUSAGE`持久性类显示当前名称空间中每个视图的源表字段的名称:
```sql
SELECT * FROM INFORMATION_SCHEMA.VIEW_COLUMN_USAGE WHERE View_Name='VSrStaff'
```
可以使用管理门户网站SQL界面中的“目录详细信息”选项卡为单个视图显示与`INFORMATION.SCHEMA.VIEWS`相同的信息。视图的“目录详细信息”包括每个视图字段的定义(数据类型,最大长度,最小值/最大值等),以及`INFORMATION.SCHEMA`视图类未提供的详细信息。 “目录详细信息”视图信息显示还提供了用于编辑视图定义的选项。
# 列出视图依赖
`INFORMATION.SCHEMA.VIEWTABLEUSAGE`持久类显示当前名称空间中的所有视图及其依赖的表。在下面的示例中显示:
```sql
SELECT View_Schema,View_Name,Table_Schema,Table_Name FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE
```
可以调用`%Library.SQLCatalog.SQLViewDependsOn`类查询以列出指定视图所依赖的表。可以为此类查询指定`schema.viewname`。如果仅指定视图名称,则它将使用系统范围的默认架构名称。调用者必须具有指定视图的特权才能执行此类查询。在下面的示例中显示:
```java
/// d ##class(PHA.TEST.SQL).View3()
ClassMethod View3()
{
SET statemt=##class(%SQL.Statement).%New()
SET cqStatus=statemt.%PrepareClassQuery("%Library.SQLCatalog","SQLViewDependsOn")
IF cqStatus'=1 {
WRITE "%PrepareClassQuery failed:" DO $System.Status.DisplayError(cqStatus) QUIT
}
SET rset=statemt.%Execute("vschema.vname")
DO rset.%Display()
}
```
```sql
DHC-APP>d ##class(PHA.TEST.SQL).View3()
Dumping result #1
SCHEMA TABLE_NAME
0 Rows(s) Affected
```
此`SQLViewDependsOn`查询列出了视图所依赖的表,并列出了表架构和表名。如果调用者没有该视图所依赖的表的特权,则该表及其模式将列为``。这允许没有表特权的调用者确定视图所依赖的表数量,而不是表的名称。
文章
姚 鑫 · 八月 7, 2021
# 第七十三章 方法关键字 - Requires
指定用户或进程调用此方法必须拥有的权限列表。
# 用法
要指定此方法应限于具有指定权限的用户或进程,请使用以下语法:
```java
Method name(formal_spec) As returnclass [ Requires = privilegelist ]
{ //implementation }
```
其中,`privilegelist` 要么是单个特权,要么是用引号括起来的以逗号分隔的特权列表。
每个权限都采用`resource:permission`的形式,其中`permission`是`Use`、`Read`或`Write`(或单字母缩写`U`、`R`或`W`)。
若要为一个资源`resource`指定多个权限,请使用单字母缩写。
# 详情
用户或进程必须拥有权限列表中的所有权限才能调用该方法。
调用没有指定权限的方法会导致``错误。
如果方法从超类继承了`Requires`关键字,则可以通过设置关键字的新值将其添加到所需特权的列表中。
不能以这种方式删除所需的特权。
# 默认
如果忽略此关键字,则调用此方法不需要特殊权限。
# 示例
下面的方法需要对`Sales`数据库的读权限和对`Marketing`数据库的写权限。
(注意,如果一个数据库有写权限,它会自动有读权限。)
```java
ClassMethod UpdateTotalSales() [ Requires = "%DB_SALES: Read, %DB_MARKETING: Write" ]
{
set newSales = ^["SALES"]Orders
set totalSales = ^["MARKETING"]Orders
set totalSales = totalSales + newSales
set ^["MARKETING"]Orders = totalSales
}
```
若要为一个资源指定多个权限,请使用单字母缩写。
以下两种方法在功能上是等价的:
```java
ClassMethod TestMethod() [ Requires = "MyResource: RW" ]
{
write "You have permission to run this method"
}
ClassMethod TestMethodTwo() [ Requires = "MyResource: Read, MyResource: Write" ]
{
write "You have permission to run this method"
}
```
# 第七十四章 方法关键字 - ReturnResultsets
指定此方法是否返回结果集(以便`ODBC`和`JDBC`客户机能够检索它们)。
# 用法
要指定该方法返回至少一个结果集,请使用以下语法:
```java
ClassMethod name(formal_spec) As returnclass [ ReturnResultsets, SqlName = CustomSets, SqlProc ]
{ //implementation }
```
否则,忽略此关键字或将单词`Not`紧接在关键字之前。
# 详解
此关键字指定该方法至少返回一个结果集。如果方法可能返回一个或多个结果集,则将此关键字设置为`true`。如果没有,`xDBC`客户端将无法检索结果集。
# 默认
如果省略此关键字,`xDBC`客户端将无法检索结果集。
# 第七十五章 方法关键字 - ServerOnly
指定此方法是否将被投影到Java客户端。
# 用法
将方法投影到`Java`客户端,请使用以下语法:
```java
Method name(formal_spec) As returnclass [ ServerOnly=n ]
{ //implementation }
```
其中`n`为下列其中之一:
- `0`表示该方法可以映射。
- `1`表示该方法不会被映射。
# 详解
该关键字指定方法不会被投影到`Java`客户机。
# 提示
要查看类的哪些方法是`server-only`的,请在终端中使用以下实用程序:
```java
do dumpMethods^%occLGUtil("Sample.Person")
```
参数是完全限定类名。
该实用程序生成一个报告,该报告指出关于每个方法的基本信息:该方法是否为存根,该方法是否仅为服务器,以及(如果该方法是从某个属性派生的)派生该方法的属性。
# 默认
如果忽略这个关键字,这个方法如果是存根方法就不会被投影(但是如果不是存根方法就会被投影)。
```java
DHC-APP>do dumpMethods^%occLGUtil("Sample.Person")
Method=%%OIDGet UseStub=0 serveronly=1
Method=%%OIDIsValid UseStub=1 serveronly=0 PropName=%%OID MethodName=IsValid
Method=%%OIDSet UseStub=1 serveronly=1 PropName=%%OID MethodName=Set
Method=%1Check UseStub=0 serveronly=1
Method=%AcquireLock UseStub=0 serveronly=1
Method=%AddJrnObjToSyncSet UseStub=0 serveronly=1
Method=%AddToSaveSet UseStub=0 serveronly=1
```
# 第七十六章 方法关键字 - SoapAction
指定当通过HTTP将此方法作为`web方法`调用时,要在`HTTP`头中使用的`SOAP`操作。仅适用于定义为`web服务`或`web客户端`的类。
# 用法
要指定将此方法用作`web方法`时在HTTP头中使用的`SOAP`操作,请使用以下语法:
```java
Method name(formal_spec) As returnclass [ WebMethod, SoapAction = soapaction ]
{ //implementation }
```
其中`soapaction`是下列之一:
- `“[default]”—SOAP`操作的默认值,即`NAMESPACE/Package.Class.Method`
- `"customValue"` -使用`customValue`作为`SOAP`操作。
该值应该是标识`SOAP`请求意图的`URI`。
如果指定了一个自定义的值,它必须在`web服务`的每个`web方法`中是唯一的,或者你必须为每个`web方法`指定`SoapRequestMessage`关键字(并且为该关键字使用唯一的值)。
- "" -使用空值作为`SOAP`操作。这种情况很少见。
# 详情
`web方法`的`SOAP`动作通常用于路由请求`SOAP消息`。
例如,防火墙可以使用它来适当地过滤`SOAP请求消息`。
InterSystems IRIS `web服务`使用`SOAP操作`(与消息本身结合)来确定如何处理请求消息。
该关键字允许指定在作为`web方法`调用此方法时使用的HTTP `SOAP`动作。
对于`SOAP 1.1`, `SOAP`动作包含在`SOAPAction HTTP`报头中。
对于`SOAP 1.2`,它包含在`Content-Type` HTTP报头中。
# 默认
如果忽略`SoapAction`关键字,`SOAP`动作的形式如下:
```java
NAMESPACE/Package.Class.Method
```
其中`NAMESPACE`是`web服务`的`NAMESPACE`参数的值,`Package.Class`是`web服务`类的名称,`Method`是`web方法`的名称。
# WSDL的关系
`SoapAction`关键字影响`web服务`的`WSDL`中`的`部分。
例如,以下web方法:
```java
Method Add(a as %Numeric,b as %Numeric) As %Numeric [ SoapAction = MySoapAction,WebMethod ]
{
Quit a + b
}
```
对于这个`web服务`,`WSDL`的``部分如下所示:
```xml
```
默认情况下,如果方法没有指定`SoapAction`关键字,``元素可能会像下面这样:
```xml
```
如果使用`SOAP`向导从`WSDL`生成 `web服务`服务或客户端,将此关键字设置为适合于该`WSDL`的关键字。
# 对消息的影响
对于前面显示的`web方法`,`web服务`期望收到以下形式的请求消息(对于SOAP 1.1):
```xml
POST /csp/gsop/ROBJDemo.BasicWS.cls HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; InterSystems IRIS;)
Host: localhost:8080
Connection: Close
Accept-Encoding: gzip
SOAPAction: MySoapAction
Content-Length: 379
Content-Type: text/xml; charset=UTF-8
...
```
默认情况下,如果方法没有指定`SoapAction`关键字,`SoapAction`行可能会像下面这样:
```xml
SOAPAction: http://www.mynamespace.org/ROBJDemo.BasicWS.Add
```
注意,对于`SOAP 1.2`,细节略有不同。
在这种情况下,`web服务`期望收到如下形式的请求消息:
```xml
POST /csp/gsop/ROBJDemo.BasicWS.cls HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; InterSystems IRIS;)
Host: localhost:8080
Connection: Close
Accept-Encoding: gzip
Content-Length: 377
Content-Type: application/soap+xml; charset=UTF-8; action="MySoapAction"
...
```