清除过滤器
问题
xu hui · 六月 22, 2021
我在用.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服务
公告
Nicky Zhu · 三月 30, 2021
尊敬的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”。
问题
wei su · 九月 25, 2024
请问一下,活动量仪表盘这个界面怎么激活,实例怎么展现?我的服务器展开没有数据,但是是有消息记录的。 你好,这个界面的内容基于活动量监控,需要在production中加入BO Ens.Activity.Operation.Local,可参考https://cn.community.intersystems.com/post/%E9%9B%86%E6%88%90%E4%BA%A7%E5%93%81%E7%9A%84%E4%B8%9A%E5%8A%A1%E8%A1%8C%E4%B8%BA%E7%9B%91%E6%8E%A7
以及
https://cn.community.intersystems.com/post/intersystems-%E6%95%B0%E6%8D%AE%E5%B9%B3%E5%8F%B0%E4%BA%92%E6%93%8D%E4%BD%9C%E5%8A%9F%E8%83%BD%E8%BF%90%E8%A1%8C%E7%BB%B4%E6%8A%A4%E7%AE%A1%E7%90%86%E5%9F%BA%E7%A1%80-production%E7%AE%A1%E7%90%86%E4%B8%8E%E4%BC%98%E5%8C%96
文章
姚 鑫 · 二月 3, 2022
[toc]
# 第四十三章 SQL函数 DATEDIFF
日期/时间函数,返回两个日期之间指定日期部分的整数差。
# 大纲
```
DATEDIFF(datepart,startdate,enddate)
```
# 参数
- `datepart` - 日期或时间部分的名称(或缩写)。这个名称可以用大写或小写来指定,有或没有引号。`datepart`可以指定为文字或主机变量。
- `startdate` - 间隔的开始日期/时间。可以是各种标准格式的日期、时间或日期时间。
- `enddate` - 间隔的结束日期/时间。可以是各种标准格式的日期、时间或日期时间。从`enddate`中减去`startdate`,以确定两个日期之间的日期部分间隔。
# 描述
`DATEDIFF`函数返回两个指定日期之间指定日期部分差的整数。日期范围从开始日期开始,到结束日期结束。(如果`enddate`早于`startdate`,`DATEDIFF`将返回一个负整数值。)
`DATEDIFF`返回`startdate`和`enddate`之间指定单位的总数。例如,两个日期时间值之间的分钟数计算日期部分和时间部分,并为每一天的差异增加`1440`分钟。`DATEDIFF`返回开始日期和结束日期之间跨越的指定日期部分边界的计数。例如,指定连续年份的任意两个日期(例如`2018-09-23`和`2019-01-01`)返回的年份`DATEDIFF`为1,而不管这两个日期之间的实际持续时间是大于还是小于`365`天。同样,`12:23:59`和`12:24:05`之间的分钟数是1,尽管实际上只有`6`秒将两个值分开。
请注意,`DATEDIFF`是为Sybase和Microsoft SQL Server兼容性而提供的。使用`TIMESTAMPDIFF ODBC`标量函数可以执行类似的时间/日期比较操作。
也可以使用`DATEDIFF()`方法调用从`ObjectScript`调用此函数:
```sql
$SYSTEM.SQL.Functions.DATEDIFF(datepart,startdate,enddate)
```
为`DATEDIFF()`方法指定无效的`datepart`、`startdate`或`enddate`会生成`< ZDDIF >`错误。
# Datepart 参数
日期部分参数可以是下列日期/时间组件之一,可以是全名(日期部分列)或其缩写(缩写列)。这些`datepart`组件名称和缩写不区分大小写。
Date Part| Abbreviations
---|---
year| yyyy, yy
month |mm, m
week| wk, ww
weekday |dw
day |dd, d
dayofyear| dy
hour |hh
minute| mi, n
second| ss, s
millisecond| ms
microsecond| mcs
nanosecond| ns
`weekday`和`dayofyear datepart`值在功能上与`day datepart`值相同。
`DATEDIFF`和`TIMESTAMPDIFF`不处理季度(间隔`3`个月)。
如果指定包含分数秒的开始日期和结束日期,`DATEDIFF`将以分数秒的整数形式返回差值,如下例所示:
```sql
SELECT DATEDIFF('ms','64701,56670.10','64701,56670.27'), /* returns 170 */
DATEDIFF('ms','64701,56670.1111','64701,56670.27222') /* returns 161 */
```
`datepart`可以指定为带引号的字符串或不带引号的字符串。这些语法变体执行略有不同的操作:
- Quotes: `DATEDIFF('month','2018-02-25',$HOROLOG)`:在创建缓存查询时,`datepart`被视为文字。SQL执行文字替换。这将产生一个更容易重用的缓存查询。
- 无引号: `DATEDIFF(month,'2018-02-25',$HOROLOG)`:创建缓存查询时,`datepart`被视为关键字。没有文字替换。这将生成更具体的缓存查询。
# 日期表达式格式
`startdate`和`enddate`参数可以采用不同的数据类型格式。
`startdate`和`enddate`参数可以采用以下任何格式:
- `%Date`逻辑值(`+$H`),也称为`$HOROLOG`格式。
- `%PosixTime`(`%Library.PosixTime`。逻辑值(编码的64位有符号整数)
- `%TimeStamp`(`%Library.TimeStamp`)逻辑值(`YYYY-MM-DD HH:MM:SS。FFF`),也称为`ODBC`格式。
- `%String`(或兼容)值。
`%String`(或`compatible`)值可以是以下任何一种格式,可以包含或省略小数秒:
- `99999、99999` (`$HOROLOG`格式)。
`$HOROLOG`特殊变量不返回小数秒。
但是,可以使用`$HOROLOG`格式指定一个包含分数秒的值:`99999,99999.999`
- Sybase/SQL-Server-date Sybase/SQL-Server-time
- Sybase/SQL-Server-time Sybase/SQL-Server-date
- Sybase/SQL-Server-date (default time is 00:00:00)
- Sybase/SQL-Server-time (default date is 01/01/1900)
Sybase/SQL-Server-date是以下五种格式之一:
```sql
mm/dd/[yy]yy dd Mmm[mm][,][yy]yy dd [yy]yy Mmm[mm] yyyy Mmm[mm] dd yyyy [dd] Mmm[mm]
```
在第一种语法格式中,分隔符可以是斜杠(`/`)、连字符(`-`)或句点(`.`)。
Sybase/SQL-Server-time表示以下三种格式之一:
```sql
HH:MM[:SS[:FFF]][{AM|PM}] HH:MM[:SS[.FFF]] HH['']{AM|PM}
```
## Years
如果年份以两位数字表示,或者日期被完全省略, IRIS会检查滑动窗口来解释日期。
系统范围内滑动窗口的默认值是`1900`;
因此,在默认情况下,两位数的年份被认为是在20世纪。
如下示例所示:
```sql
SELECT DATEDIFF('year','10/11/14','02/22/2018'),
DATEDIFF('year','12:00:00','2018-02-22 12:00:00')
```
## 分数秒
`DATEDIFF`返回以毫秒(3位整数)、微秒(6位整数)或纳秒(9位整数)表示的小数秒,而不管`startdate`和`enddate`中的小数位数精度是多少。
如下示例所示:
```sql
SELECT DATEDIFF('ms','12:00:00.1','12:00:00.2'),
DATEDIFF('ms','12:00:00.10009','12:00:00.20007')
```
一些NLS区域设置将分数分隔符指定为逗号(欧洲的用法),而不是句号。
如果当前区域设置是这些区域设置之一,`DATEDIFF`接受句号或逗号作为本地日期格式的秒分隔符。
对于`$HOROLOG`格式的日期或`ODBC`格式的日期,不能使用逗号作为小数秒分隔符。
尝试这样做会生成一个`SQLCODE -8`。
无论当前的NLS语言环境是什么,这两种格式都需要一段时间。
# 时间差异与时间格式无关
`DATEDIFF`返回以秒和毫秒为单位的时间差,即使当前进程的`TimeFormat`被设置为不返回秒。
如下示例所示:
```java
ClassMethod DateDiff()
{
s tfmt = ##class(%SYS.NLS.Format).GetFormatItem("TimeFormat")
d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",1)
w "datetime values (with seconds) are: ",!,
$ZDATETIME("64701,56670.10",1,-1)," ",$ZDATETIME("64701,56673.27",1,-1),!
&sql(SELECT DATEDIFF('ss','64701,56670.10','62871,56673.27') INTO :x)
w "DATEDIFF number of seconds is: ",x,!!
d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",2)
w "datetime values (without seconds) are: ",!,
$ZDATETIME("64701,56670.10",1,-1)," ",$ZDATETIME("64701,56673.27",1,-1),!
&sql(SELECT DATEDIFF('ss','64701,56670.10','64701,56673.27') INTO :x)
w "DATEDIFF number of seconds is: ",x,!
d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",tfmt)
}
```
```java
DHC-APP>d ##class(PHA.TEST.SQLCommand).DateDiff()
datetime values (with seconds) are:
02/22/2018 15:44:30 02/22/2018 15:44:33
DATEDIFF number of seconds is: -158111996.83
datetime values (without seconds) are:
02/22/2018 15:44 02/22/2018 15:44
DATEDIFF number of seconds is: 3.17
```
# 范围和值检查
`DATEDIFF`对输入值执行以下检查:
- 在执行任何`DATEDIFF`操作之前,开始日期和结束日期的所有指定部分必须是有效的。
- 日期字符串必须完整,格式正确,包含适当数量的元素和每个元素的数字,以及适当的分隔符。
年必须指定为四位数字。
如果省略输入值的日期部分,`DATEDIFF`默认为`' 1900-01-01 '`。
无效的日期值将导致`SQLCODE -8`错误。
- 日期和时间值必须在有效范围内。
年龄:`0001`到`9999`。
月份:`1 - 12`个月。
天数:`1 - 31`天。
营业时间:`00`至`23`。
分钟:`0`到`59`分钟。
秒:`0 ~ 59`。
一个月中的天数必须与月和年相匹配。
例如,日期`“02-29”`仅在指定的年份为闰年时有效。
无效的日期值将导致`SQLCODE -8`错误。
- 小于`10`(月和日)的日期值可以包括或省略前导零。
不允许使用其他非规范整数值。
因此,`Day`值为`“07”`或`“7”`是有效的,但`“007”`、`“7.0”`或`“7a”`无效。
- 时间值可以全部或部分省略。
如果`startdate`或`enddate`指定了一个不完整的时间,则为未指定的部分提供`0`。
- 小于`10`的小时值必须包含前导零。
省略前导零将导致`SQLCODE -8`错误。
# 错误处理
- 在`Embedded SQL`中,如果指定无效的`datepart`作为输入变量,则会发出`SQLCODE -8`错误码。
如果将无效的日期部分指定为文字,则会发生``错误。
如果将无效的开始日期或结束日期指定为输入变量或文字,则会发出`SQLCODE -8`错误码。
- 在动态SQL中,如果您提供了无效的日期部分、开始日期或结束日期,则`DATEDIFF`函数将返回一个`NULL`值。
没有发出`SQLCODE`错误。
# 示例
下面的例子返回`353`,因为两个时间戳之间有`353`天(D):
```sql
SELECT DATEDIFF(D,'2018-01-01 00:00:00','2018-12-20 12:00:00')
353
```
在下面的示例中,每个`DATEDIFF`返回`1`,因为日期的年份部分相差1。
日期之间的实际持续时间不被考虑:
```sql
SELECT DATEDIFF('yyyy','1910-08-21','1911-08-21') AS ExactYear,
DATEDIFF('yyyy','1910-06-30','1911-01-01') AS HalfYear,
DATEDIFF('yyyy','1910-01-01','1911-12-31') AS Nearly2Years,
DATEDIFF('yyyy','1910-12-31 11:59:59','1911-01-01 00:00:00') AS NewYearSecond
1 1 1 1
```
注意,上面的例子使用了日期部分的缩写。
但是,你可以指定全名,如下例所示:
```sql
SELECT DATEDIFF('year','2017-09-10 13:19:00','2018-12-20 00:00:00')
1
```
下面的嵌入式SQL示例使用主机变量执行与前面示例相同的`DATEDIFF`操作:
```sql
ClassMethod DateDiff1()
{
s x="year"
s date1="2017-09-10 13:19:00"
s date2="2018-12-20 00:00:00"
&sql(SELECT DATEDIFF(:x,:date1,:date2)
INTO :diff)
w diff
}
```
```
1
```
下面的例子使用`WHERE`子句中的`DATEDIFF`来选择上周入院的患者:
```sql
SELECT Name,DateOfAdmission FROM Sample.Patients WHERE DATEDIFF(D,DateOfAdmission,$HOROLOG)
文章
姚 鑫 · 四月 7, 2021
# 第十九章 存储和使用流数据(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')
```

```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)
```

- `%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>
```

作为默认值或计算值插入的字符串数据以适合于流字段的格式存储。
## 查询流字段数据
选择流字段的查询选择项返回流对象的完全形成的OID(对象ID)值,如下例所示:
```sql
SELECT Name,Photo,Notes
FROM Sample.MyTable WHERE Photo IS NOT NULL
```

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`。

## `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
```

但是,流字段不支持`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
```

- `CHARACTER_LENGTH`、`CHAR_LENGTH`和`DATALENGTH`函数接受流字段并返回实际的数据长度,如下面的示例所示:
```sql
SELECT Name,DATALENGTH(Notes) AS NotesNumChars,DATALENGTH(Photo) AS PhotoNumChars
FROM Sample.MyTable
```

`SUBSTRING`函数接受一个流字段,并返回流字段的实际数据值的指定子字符串,如下面的示例所示:
```sql
SELECT Name,SUBSTRING(Notes,1,10) AS Notes1st10Chars
FROM Sample.MyTable WHERE Notes IS NOT NULL
```

当从管理门户SQL Execute接口发出时,子字符串函数返回流字段数据最多100个字符的子字符串。
如果流数据的指定子字符串大于100个字符,则在第100个字符后用省略号(`…`)表示。
- `CONVERT`函数可用于将流数据类型转换为`VARCHAR`,示例如下:
```sql
SELECT Name,CONVERT(VARCHAR(100),Notes) AS NotesTextAsStr
FROM Sample.MyTable WHERE Notes IS NOT NULL
```

`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对象超出范围并不会发送清理服务器资源的消息。
文章
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 年的经验。
点击查看原文
文章
姚 鑫 · 一月 5, 2024
# 第十六章 调用Callout Library函数
`Callout` 库是一个共享库(`DLL` 或 `SO` 文件),其中包含 `$ZF Callout` 接口的挂钩,允许各种 $ZF 函数在运行时加载它并调用其函数。 `$ZF Callout` 接口提供了四种不同的接口,可用于在运行时加载 `Callout` 库并从该库调用函数。这些接口的主要区别在于如何识别库并将其加载到内存中:
- 使用 `$ZF()` 访问 `iriszf` 标注库描述了如何使用名为 `iriszf` 的特殊共享库。当该库可用时,可以通过 `$ZF("funcname",args)` 形式的调用来访问其函数,而无需事先加载该库或指定库名称。
- 使用 `$ZF(-3)` 进行简单库函数调用描述了如何通过指定库文件路径和函数名来加载库并调用函数。它使用简单,但虚拟内存中一次只能有一个库。与其他接口不同,它在调用库函数之前不需要任何初始化。
- 使用 `$ZF(-5)` 通过系统 `ID` 访问库描述了一种可用于一次有效维护和访问多个库的接口。可以同时加载和使用多个库,每个库所需的处理开销比 `$ZF(-3)` 少得多。内存中的库由加载库时生成的系统定义的 `ID` 来标识。
- 使用 `$ZF(-6)` 按用户索引访问库描述了处理大量标注库的最有效接口。该接口通过`Global`定义的索引表提供对库的访问。该索引可供 `IRIS` 实例中的所有进程使用,并且多个库可以同时位于内存中。每个索引库都被赋予一个唯一的、用户定义的索引号,并且可以在运行时定义和修改索引表。当库文件被重命名或重新定位时,与给定库 `ID` 关联的文件名可以更改,并且此更改对于按索引号加载库的应用程序来说是透明的。
# 使用 `$ZF()` 访问 `iriszf` 标注库
当名为 `iriszf` 的 `Callout` 库在实例的 `/bin` 目录中可用时,可以通过仅指定函数名称和参数的 `$ZF` 调用来调用其函数(例如,`$ZF("functionName",arg1, arg2))`.。无需事先加载库即可调用 `iriszf` 函数,并且实例中的所有进程都可以使用 `iriszf` 函数。
自定义 `iriszf` 库是通过创建标准 `Callout` 库、将其移动到实例的 `/bin` 目录并将其重命名为 `iriszf`(具体为 `iriszf.dll` 或 `iriszf.so`,具体取决于平台)来定义的。
以下是编译 `simplecallout.c` 示例(请参阅“创建 `Callout` 库”)并将其设置为 `iriszf` 库的步骤。这些示例假设实例在 `Linux` 下运行,安装在名为 `/intersystems/iris` 的目录中,但所有平台上的过程基本相同:
1. 编写并保存 `simplecallout.c`:
```java
#define ZF_DLL
#include "iris-cdzf.h"
int AddTwoIntegers(int a, int b, int *outsum) {
*outsum = a+b; /* set value to be returned by $ZF function call */
return IRIS_SUCCESS; /* set the exit status code */
}
ZFBEGIN
ZFENTRY("AddInt","iiP",AddTwoIntegers)
ZFEND
```
2. 生成`Callout`库文件(`simplecallout.so`):
```java
gcc -c -fPIC simplecallout.c -I /intersystems/iris/dev/iris-callin/include/ -o simplecallout.o
gcc simplecallout.o -shared -o simplecallout.so
```
3. 从 `IRIS` 终端会话中使用 `$ZF(-3)` 测试库:
```java
USER>write $ZF(-3,"/mytest/simplecallout.so","AddInt",1,4)
5
```
4. 现在安装该库以与 `$ZF()` 一起使用。将 `simplecallout.so` 复制到 `/bin`中,并将其重命名为 `iriszf.so`:
```java
cp simplecallout.so /intersystems/iris/bin/iriszf.so
```
5. 确认可以从 `IRIS` 会话中使用 `$ZF()` 调用代码:
```java
USER>write $zf("AddInt",1,4)
5
```
`iriszf` 库在首次使用时加载一次,并且永远不会卸载。它完全独立于本章前面描述的其他 `$ZF` 加载和卸载操作。
注意:静态链接库 `$ZF Callout Interface` 的早期版本允许将代码静态链接到 `InterSystems` 内核并使用 `$ZF()` 进行调用。不再支持静态链接,但 `irisz` 库提供相同的功能,无需重新链接内核。
文章
Qiao Peng · 一月 10, 2021
# Swift-FHIR-Iris
iOS应用程序支持将HealthKit数据导入InterSystems IRIS医疗版(或任何FHIR资源仓库库)

# 目录
* [演示目的](#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
单击左上角的箭头打开模拟器。

## 配置模拟器
打开Health
点击“Steps”
添加数据

## 启动InterSystems FHIR服务器
在该git的根目录下,运行以下命令:
```sh
docker-compose up -d
```
构建过程结束时,你将连接到FHIR资源仓库:
http://localhost:32783/fhir/portal/patientlist.html

该门户网站由@diashenrique创建.
为处理Apple活动足迹,进行了一些修改。
## 在iOS应用程序上操作
iOS应用程序首先会请求你同意分享部分信息。
点击授权

然后点击“Save and test server”对FHIR服务器进行测试
默认设置指向docker配置。
操作成功后,就可以输入患者信息。
名字、姓氏、生日、性别。
将患者信息保存到Fhir。弹出窗口将显示唯一的Fhir ID。

可在门户网站查阅该患者信息:
访问: http://localhost:32783/fhir/portal/patientlist.html
在这里我们可以看到,增加了一个新的病人“Toto”,0个活动。

发送她的活动信息:
回到iOS应用程序,点击“Step count”。
这里显示的是一周的步数。在我们的案例中有2条记录。
现在可以单击发送,将这些数据发送到InterSystems IRIS FHIR。

从门户网站上查询新的活动记录:
现在我们可以看到Toto有两条新的观察和活动消息。

你还可以单击“chart”按钮以图表格式显示。

# 工作原理
## 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
公告
Claire Zheng · 一月 10, 2023
亲爱的社区开发者们,
我很高兴地向大家介绍一位我们的新版主 @牛宇翔!
@牛宇翔 目前担任首都医科大学附属北京友谊医院信息中心临床组组长。
以下是@牛宇翔 的自我介绍:
本人有接近10年的医疗信息化经验,目前在我院,带领一个微型小团队,基于Ensemble数据库做医院信息系统(Hospital Information System, HIS)应用端研发,我们团队熟悉HTML、CSS、JavaScript及衍生前端语言,日常工作主要根据用户需求开发对应功能,结合临床业务难点痛点,不断优化程序功能。经过两年的学习和努力,我们团队已完成临床新增功能和优化需求共计一千余条,随着科室人力的发展,我们的开发力量会越来越强,可以更好地保证临床需求的及时响应,不断优化和完善系统BUG,提高临床工作效率。与此同时,我还担任应急小组成员,负责进行数据库运维和问题处理,保证第一时间排查故障。
InterSystems 提供了一个非常优秀的集成平台,借助该技术,给我们业务带来了非常大的便利。我也希望这么优秀的技术,能给更多的兄弟单位和合作伙伴创造价值。我也希望能够在社区与大家一起交流,分享自己的一些实践经验;同时也希望借助这个平台,向大家学习一些优秀的实践。我们一起成长,共同进步!
再次欢迎我们的新版主 @牛宇翔👏🏼👏🏼👏🏼👏🏼👏🏼
期待你在InterSystems开发者社区成长为一名优秀版主! 热烈欢迎!期待更多大作!@牛宇翔
公告
Jeff Liu · 三月 30, 2022
大家好,欢迎来到2022年3月开发者社区更新!
我们最近在InterSystems社区对开发者们的体验做了一些改进:
全新的社区内容搜索功能
综合社区数据
链接你的脸书账号
帖子页面更新:标签、作者块、草稿突出显示
下面让我们仔细看看。
社区搜
我们已经在社区网站上部署了一个全新的搜索引擎。有两个搜索选项:
快速搜索
高级搜索
通过DC快速搜索,你可以很容易地找到一个帖子/标签/用户并直接进入该网页。
在建议的选项中没有找到合适的东西?
试着通过点击🔍按钮使用DC高级搜索:
在这里,你可以轻松地为你的搜索查询添加高级参数:
按特定用户的帖子搜索
通过特定标签搜索
按特定的帖子类型或只按你的帖子搜索
你还可以按时间段和相关性对结果进行排序:
综合社区数据
现在你可以看到InterSystems开发社区的数据统计了:
链接你的脸书账号
在你的DC资料中添加Facebook链接,以认识新朋友,拉近彼此的距离。
进入你的DC用户资料-->编辑-->其他信息-->Facebook资料
帖子页面更新:标签、作者块、草稿突出显示
你问了 - 我们做到了! 现在DC标签出现在帖子的正文中。
另外,在帖子页面,你现在可以在右边的块中看到作者的联系信息:
DC网站上的草稿现在是蓝色突出显示:
希望你喜欢我们的更新
在DC GitHub上提交您的改进请求和错误报告。或者在本帖的评论中发表您的建议。
请继续关注!
文章
姚 鑫 · 二月 22, 2021
# 第四十四章 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排序(二)
# 查询排序
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
```

- 字符串截断:可以使用`%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
```

请注意,不能嵌套排序规则函数或大小写转换函数。
- `WHERE`子句比较:大多数`WHERE`子句谓词条件比较使用字段/属性的排序规则类型。因为字符串字段默认为`SQLUPPER`,所以这些比较通常不区分大小写。可以使用`%EXACT`排序规则功能使它们区分大小写:
-
下面的示例返回`Home_City`字符串匹配项,无论字母大小写如何:
```SQL
SELECT Home_City FROM Sample.Person WHERE Home_City = 'albany'
```

以下示例返回区分大小写的`Home_City`字符串匹配:
```SQL
SELECT Home_City FROM Sample.Person WHERE %EXACT(Home_City) = 'albany'
```

`SQL Follows`运算符(`]`)使用字段/属性归类类型。
但是,无论字段/属性的排序规则类型如何,SQL `Contains`运算符(`[`)都使用EXACT排序规则:
```SQL
SELECT Home_City FROM Sample.Person WHERE Home_City [ 'c'
ORDER BY Home_City
```

`%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
```

`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
```

下面的示例返回大小写混合的值; `GROUP BY`消除了精确的重复项(但不消除字母大写的变体):
```SQL
SELECT Name FROM Sample.Person GROUP BY %EXACT(Name)
```

# 旧版排序类型
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`的超类。下图显示了这些类之间的关系:

- 要表示普通的、由一部分组成的消息,请使用`%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")
```
不同的电子邮件服务器和客户端可以识别不同的标头,因此设置多个相似的标头以确保服务器或客户端接收到的邮件具有它可以识别的标头是很有用的。
文章
姚 鑫 · 五月 3, 2021
# 第二章 全局变量结构(一)
本章描述全局变量的逻辑视图,并概述全局变量是如何在磁盘上物理存储的。
# 全局变量的逻辑结构
全局变量是存储在物理InterSystems IRIS®数据库中的命名多维数组。
在应用程序中,全局变量到物理数据库的映射基于当前名称空间——名称空间提供一个或多个物理数据库的逻辑统一视图。
## 全局命名约定和限制
全局名称指定其目标和用途。有两种类型的全局变量和一组单独的变量,称为“进程私有全局变量”:
- 全局变量 - 这就是所谓的标准全局变量;通常,这些变量被简称为全局变量。它是驻留在当前命名空间中的永久性多维数组。
- **扩展全局引用-这是位于当前命名空间以外的命名空间中的全局引用。**
- **进程私有全局变量-这是一个数组变量,只有创建它的进程才能访问。**
全局变量的命名约定如下:
- 全局变量名称以脱字符(`^`)前缀开头。这个插入符号区分全局变量和局部变量。
- 全局变量名称中脱字符(`^`)前缀后的第一个字符可以是:
- 字母或百分号字符(%)-仅适用于标准全局变量。对于全局变量名称,字母被定义为`ASCII 65`到`ASCII 255`范围内的字母字符。如果全局名称以`“%”`开头(但不是`“%Z”`或`“%z”`),则此全局名称供InterSystems IRIS系统使用。`%GLOBAL`通常存储在IRISSYS或IRISLIB数据库中。
- 竖线(`|`)或左方括号(`[`)-表示扩展全局引用或进程专用全局变量。使用取决于后续字符。
- 全局变量名称的其他字符可以是字母、数字或句号(`.`)字符。
百分比(`%`)字符不能使用,除非作为全局名称的第一个字符。
`“.”`字符不能作为全局名称的最后一个字符。
- **全局名称最长可达31个字符(不包括脱字符前缀)。可以指定更长的全局名称,但InterSystems IRIS只将前31个字符视为重要字符。**
- 全局名称区分大小写。
- InterSystems IRIS对全局引用的总长度施加限制,而该限制又对任何下标值的长度施加限制。
**在IRISSYS数据库中,InterSystems将除以`“z”`、`“Z”`、`“%z”`和`“%Z”`开头的所有全局变量名称保留给自己。在所有其他数据库中,InterSystems保留所有以`“ISC”`开头的全局名称。和`“%isc.”`。**
## 示例全局名称及其用法
以下是各种全局名称的示例以及每种名称的用法:
- `^globalname` - 标准全局变量
- `^|"environment"|globalname` - 扩展全局变量引用的环境语法
- `^||globalname` - 进程私有全局变量
- `^|"^"|` - 进程私有全局变量
- `^[namespace]globalname` - 扩展全局变量引用中显式命名空间的括号语法
- `^[directory,system]globalname` - 扩展全局变量引用中隐含命名空间的括号语法
- `^["^"]globalname` - 进程私有全局变量
- `^["^",""]globalname` - 进程私有全局变量
注意:全局名称只能包含有效的标识符字符;默认情况下,这些字符如上所述。但是,NLS(国家语言支持)定义了一组不同的有效标识符字符集。全局名称不能包含`Unicode`字符。
因此,以下都是有效的全局名称:
```java
SET ^a="The quick "
SET ^A="brown fox "
SET ^A7="jumped over "
SET ^A.7="the lazy "
SET ^A1B2C3="dog's back."
WRITE ^a,^A,^A7,!,^A.7,^A1B2C3
KILL ^a,^A,^A7,^A.7,^A1B2C3 // keeps the database clean
```
## 全局节点和下标简介
全局通常有多个节点,通常由一个下标或一组下标标识。下面是一个基本示例:
```java
set ^Demo(1)="Cleopatra"
```
此语句引用全局节点`^Demo(1)`,它是`^Demo`全局节点中的一个节点。此节点由一个下标标识。
再举一个例子:
```java
set ^Demo("subscript1","subscript2","subscript3")=12
```
该语句指的是全局节点`^Demo("subscript1","subscript2","subscript3")`,它是同一全局中的另一个节点。此节点由三个下标标识。
再举一个例子:
```java
set ^Demo="hello world"
```
该语句引用不使用任何下标的全局节点`^Demo`。
全局的节点形成分层结构。ObjectScript提供了利用此结构的命令。例如,可以删除节点或删除节点及其所有子节点。
## 全局变量下标
下标有以下规则:
- 下标数值区分大小写。
- **下标值可以是任何ObjectScript表达式,前提是该表达式的计算结果不是空字符串(`""`)。**
**该值可以包括所有类型的字符,包括空格、非打印字符和Unicode字符。(请注意,非打印字符在下标数值中不太实用。)**
- 在解析全局引用之前,InterSystems IRIS计算每个下标的方式与计算任何其他表达式的方式相同。在下面的示例中,我们设置了`^Demo`全局的一个节点,然后以几种等效的方式引用该节点:
```java
DHC-APP>s ^Demo(1+2+3)="a value"
DHC-APP>w ^Demo(3+3)
a value
DHC-APP>w ^Demo(03+03)
a value
DHC-APP>w ^Demo(03.0+03.0)
a value
DHC-APP>set x=6
DHC-APP>w ^Demo(x)
a value
```
- InterSystems IRIS对全局引用的总长度施加限制,而该限制又对任何下标值的长度施加限制。
**注意:上述规则适用于IRIS支持的所有排序规则。对于出于兼容性原因仍在使用的旧归类,如`“pre-ISM-6.1”`,下标的规则有更多限制。例如,字符下标不能以控制字符作为其初始字符;整数下标中可以使用的位数也有限制。**
## 全局变量节点
在应用程序中,节点通常包含以下类型的结构:
1. 字符串或数字数据,包括本机`Unicode`字符。
2. 具有由特殊字符分隔的多个字段的字符串:
```java
SET ^Data(10) = "Smith^John^Boston"
```
可以使用ObjectScript `$PIECE` 函数来拆分这些数据。
3. InterSystems IRIS `$LIST` 结构中包含多个字段。`$LIST`结构是包含多个长度编码值的字符串。它不需要特殊的分隔符。
4. 空字符串 (`""`)。在下标本身用作数据的情况下,实际节点中不存储任何数据。
5. 一个位串。如果全局变量用于存储位图索引的一部分,那么存储在节点中的值就是位字符串。位串是包含`1`和`0`值的逻辑压缩集的字符串。可以使用`$BIT`函数构造位串。
6. 更大的数据集的一部分。例如,对象和SQL引擎将流(`BLOB`)存储为全局中连续的`32K`节点系列。通过流接口,流的用户不知道流是以这种方式存储的。
请注意,任何全局节点都不能包含长度超过字符串长度限制的字符串,字符串长度限制非常长。
## 全局变量排序规则
在全局中,节点按排序(排序)顺序存储。
**应用程序通常通过将转换应用于用作下标的值来控制节点的排序顺序。例如,SQL引擎在为字符串值创建索引时,会将所有字符串值转换为大写字母,并在前面加上一个空格字符,以确保索引不区分大小写并且以文本形式排序(即使数值存储为字符串)。**
# 全局变量引用的最大长度
**全局变量引用(即对特定全局节点或子树的引用)的总长度限制为`511`个编码字符(少于`511`个键入字符)。**
要保守地确定给定全局变量引用的大小,请使用以下准则:
1. 全局变量名称:每个字符加`1`。
2. 对于纯数字下标:每个数字、符号或小数点加`1`。
3. 对于包含非数字字符的下标:为每个字符添加`3`。
如果下标不是纯数字的,则根据用于编码字符串的字符集的不同,下标的实际长度会有所不同。一个多字节字符最多可以占用`3`个字节。
请注意,ASCII字符可能占用`1`或`2`字节。
如果排序规则进行大小写折叠,那么`ASCII`字符可以使用`1`个字节表示字符,`1`个字节表示消除歧义字节。
如果排序不执行大小写折叠,`ASCII`字符占用`1`字节。
4. 每个下标加`1`。
如果这些数字的总和大于`511`,则引用太长。
由于确定限制的方式,如果必须使用长下标或全局名称,这有助于避免使用大量下标级别。
相反,如果使用多个下标级别,则应避免长全局名称和长下标。
因为无法控制正在使用的字符集,所以保持全局名称和下标更短是很有用的。
当对特定引用有疑问时,创建与最长预期全局变量引用长度相等(甚至稍长一点)的全局变量引用的测试版本是有用的。
这些测试的数据为构建应用程序之前可能修订的命名约定提供了指导。
文章
Michael Lei · 八月 26, 2021
# SAM - 设置和添加非 IRIS 目标指标的技巧和提示
SAM(系统警报和监视)以“功能齐全”的 docker-compose 容器集的形式提供,只要启动就可以开始以默认的仪表板监视 IRIS 实例。 使用初始配置就可以很好地了解 SAM 功能并开始对 IRIS 系统进行基本监视。 但是,当开始监视多个系统并收集大量指标数据时,需要更改一些默认设置。 为了从 SAM 获取更多价值,您还会想要添加来自其他数据源(目标)的指标。 以下技巧将帮助您在生产环境中部署 SAM,从多个目标收集指标并将这些指标组合到您自己的仪表板和图表中。 此外,您还将看到一些可能有助于探索 SAM 容器和应用程序的命令。
> *注意:*我应该指出,其中一些技巧和提示可能不是最佳做法;这更像是一个日志,记录了我第一次如何配置 SAM 来监视相同系统上的多个服务器和非 IRIS 目标的基准。 如果您有建议,请在评论中指教 ;) 所以,记住本帖可能会随着时间的推移而有所变化,让我们开始吧;
---
在下面的技巧中,有重启 docker 以及启动和停止 SAM 的操作。 请通读这些技巧,确定哪些适合您,然后按照下面的相同顺序执行。
## 1. 确保有足够的空间用于 SAM 数据库
默认情况下,docker 容器将文件存储在根 (/) 文件系统。 SAM 不需要很多 CPU 或内存资源;但是,指标收集将占用空间。
> 指标需要的存储容量“视情况而定”。 虽然在开始监视之前可能无法明确数据库大小,但大致上,在抓取周期为 15 秒的情况下,监视 10 个 IRIS 虚拟机以及操作系统指标大约消耗 50GB 存储。
策略包括:增加监视实例的根存储,或更改数据库的卷位置。 我使用了以下命令来更改运行 docker 的虚拟机上的 docker 目录。 也许是杀鸡用了牛刀,但很管用。
- 停止 docker 并将 docker 文件复制到空间充足的文件系统(本例中为 /data/docker/data)。 见下面的示例:
```other
[root@mysamserver lib]# sudo systemctl stop docker
[root@mysamserver lib]# pwd
/var/lib
[root@mysamserver lib]# cp -rp docker /data/docker/data
[root@mysamserver lib]#
[root@mysamserver lib]# rm -rf docker
```
- 在 docker 配置文件中更新卷路径。 注意此文件还有一个网络设置“bip”(请参见注释:...)
```swift
cat /etc/docker/daemon.json
{
"data-root": "/data/docker/data",
"bip": "192.168.0.1/24"
}
```
- 重启 docker
```swift
sudo systemctl daemon-reload
sudo systemctl restart docker
systemctl status docker.service
```
## 2. 设置 SAM
我假定您已在测试系统上设置 SAM,并熟悉它的基本操作:添加集群和实例,以及查看系统指标。 建议您花 20 分钟时间查看我在虚拟全球峰会 2020 上的展示,以了解安装步骤的概述,以及添加多个目标的运行指标时 SAM 的外观。 要观看此会议,请使用以下链接(您需要使用您的电子邮件注册):
[DEV007 系统警报和监视](https://intersystems.6connex.com/event/virtual-summit/en-us/contents/434680/share?rid=Lobby&nid=804450)
登录到 SAM 门户并配置一些 IRIS 实例。 这会填充配置文件并提供向导。
`http://mysamserver:8080/api/sam/app/index.csp#/`
> 注意:如果要添加多个实例,或者希望用脚本执行此步骤,可以通过 API 添加实例。 请参见文档。
## 3. 升级到生产许可证
SAM 随附了一个 IRIS 社区版许可证。 有几个限制,包括 IRIS.DAT 限制为 10GB。 10GB 不足以长时间从多个目标收集数据。 请联系您的 InterSystems 联系人以获取生产许可证。 在没有编辑器的情况下,在精简的容器中更新许可证可能很棘手,我只是在 IRIS 容器上登录一个交互式会话,然后使用以下命令更新许可证密钥:
- 打开 shell,切换目录至 mgr 文件夹(iris.key 文件的默认位置)
```swift
docker exec -it sam_iris_1 bash
cd /dur/iconfig/mgr
```
- 使用 unix“here 文档”更新密钥。 在“>”后面粘贴密钥文本。 在密钥文本后面,输入“>EOF”以提交命令。 然后输入“exit”退出 shell。
```other
cat
[ConfigFile]
FileType=InterSystems License Rev-A.1
LicenseID=999999
[License]
LicenseCapacity=InterSystems IRIS 2020.2 Server for SAM:etc etc, the key you were sent by your InterSystems contact.
>EOF
exit
```
- 然后使用提供的 docker-compose shell 脚本停止再启动 SAM:
```swift
./stop.sh
./start.sh
```
- 可以通过访问系统管理门户或登录到 iris 实例并检查 messages.log 来检查许可证是否一切正常。
```shell
docker exec -it sam_iris_1 bash
cd /dur/iconfig/mgr
cat messages.log
```
## 4. 在目标上安装其他 prometheus 导出程序
例如,prometheus 节点导出程序可显示各种硬件和内核相关的指标。
[节点导出程序文档](https://prometheus.io/docs/guides/node-exporter/)
通过请求(抓取)实例端点的指标,测试节点导出程序是否正常工作:
```swift
curl my_target_server_name:9100/metrics
```
您应该看到类似下面的信息:
```swift
mylaptop:~ mo$ my_target_server_name:9100/metrics | more
HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 4.8862e-05
go_gc_duration_seconds{quantile="0.25"} 7.5898e-05
go_gc_duration_seconds{quantile="0.5"} 9.2974e-05
go_gc_duration_seconds{quantile="0.75"} 0.000130664
go_gc_duration_seconds{quantile="1"} 0.000358762
go_gc_duration_seconds_sum 303.291715258
go_gc_duration_seconds_count 2.572586e+06
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 9
:
: many many metrics will be displayed
```
注意您可以对您的 IRIS 实例执行同样操作:
```swift
mylaptop:~ mo$ curl my_target_server_name:52776/api/monitor/metrics | more
iris_cpu_pct{id="AUXWD"} 0
iris_cpu_pct{id="CSPDMN"} 0
iris_cpu_pct{id="CSPSRV"} 0
iris_cpu_pct{id="ECPCliR"} 0
iris_cpu_pct{id="ECPCliW"} 0
iris_cpu_pct{id="ECPSrvR"} 0
iris_cpu_pct{id="ECPSrvW"} 0
:
: many many metrics will be displayed
```
## 5. 编辑配置文件以添加对新目标的抓取
例如,前一个技巧中的 node-exporter 实例。 配置文件将位于 SAM 的安装位置。 如下所示,可以看到 grafana 和 prometheus `yml` 配置文件。
```plaintext
[root@mysamserver sam-1.0.0.115-unix]# ls
config docker-compose.yml readme.txt start.sh stop.sh
[root@mysamserver sam-1.0.0.115-unix]# tree -x config
config
├── alertmanager
│ └── isc_alertmanager.yml
├── grafana
│ ├── dashboard.json
│ ├── dashboard-provider.yml
│ ├── datasource.yml
│ └── grafana.ini
├── nginx
│ └── nginx.conf
└── prometheus
├── isc_alert_rules.yml
└── isc_prometheus.yml
4 directories, 8 files
```
## 5.1 添加目标到 prometheus
以下示例是使用 SAM 中的配置 GUI 屏幕创建的 `isc_prometheus.yml` 文件。 该文件包含两个集群。 一个集群监视 sam 实例本身,另一个集群监视五个 IRIS 实例。
```yaml
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
global:
evaluation_interval: 15s
scrape_interval: 15s
remote_read:
- url: http://iris:52773/api/sam/private/db/read
remote_write:
- url: http://iris:52773/api/sam/private/db/write
rule_files:
- ./isc_alert_rules.yml
scrape_configs:
- job_name: SAM
metrics_path: /api/monitor/metrics
scheme: http
static_configs:
- labels:
cluster: "1"
targets:
- mysaminstance.mycompany.com:8080
- labels:
cluster: "2"
targets:
- myiristarget1:52776
- myiristarget2:52776
- myiristarget3:52776
- myiristarget4:52776
- myiristarget5:52776
```
- 要添加对其他运行 node-exporter 的目标的抓取,请将以下内容添加到 `isc_prometheus.yml` 文件的底部。 注意 API `metrics_path` 与 IRIS 不同。
```yaml
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
global:
evaluation_interval: 15s
scrape_interval: 15s
remote_read:
- url: http://iris:52773/api/sam/private/db/read
remote_write:
- url: http://iris:52773/api/sam/private/db/write
rule_files:
- ./isc_alert_rules.yml
scrape_configs:
- job_name: SAM
metrics_path: /api/monitor/metrics
scheme: http
static_configs:
- labels:
cluster: "1"
targets:
- iscsydsam.iscinternal.com:8080
- labels:
cluster: "2"
targets:
- myiristarget1:52776
- myiristarget2:52776
- myiristarget3:52776
- myiristarget4:52776
- myiristarget5:52776
- job_name: node_shard1
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget1:9100
- job_name: node_shard2
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget2:9100
- job_name: node_shard3
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget3:9100
- job_name: node_shard4
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget4:9100
- job_name: node_shard5
metrics_path: /metrics
scheme: http
static_configs:
- labels:
cluster: "2"
group: node
targets:
- myiristarget5:9100
```
- 然后使用提供的 docker-compose shell 脚本停止再启动 SAM:
```swift
./stop.sh
./start.sh
```
SAM 现在从您通过 GUI 添加的 IRIS 实例以及相同实例上的 node-exporter 中收集指标。
# 6. 增加 Prometheus 收集指标的天数
在 SAM 的第一版中,您可以在 GUI 中更改收集指标的天数。 但是,我在显示所有指标时遇到一个问题。 在我弄清楚发生了什么之前,我更改了 Prometheus 中的保留天数,否则 SAM 将收集数据,但是您在 Grafana 的 Prometheus 查询中看不到指标。
在文件 `docker-compose.yml` 中用来安装 SAM 的层,更改 Prometheus 启动时设置的保留天数,例如在 `prometheus` 部分中,更新 `storage.tsdb.retention.time` 参数以匹配所需的保留天数:
```swift
prometheus:
command:
- --web.enable-lifecycle
- --config.file=/config/isc_prometheus.yml
- --storage.tsdb.retention.time=30d
```
> 注意:在 SAM 的第一版中,最长保留天数为 30 天。 然后使用提供的 docker-compose shell 脚本停止再启动 SAM:
```swift
./stop.sh
./start.sh
```
## 7. 创建您自己的仪表板
您可以向现有仪表板添加面板,也可以创建新的仪表板以满足您的监视需求。 这是一个很大的主题,所以留到下一个帖子再说。 不过,这里先帮助您上手。
在 SAM 屏幕上使用 `View in Grafana`(在 Grafana 中查看)按钮切换到 Grafana。

打开 Grafana 后,可以创建或编辑仪表板;

网上有许多查询导出程序(如 node-exporter)的示例。
> 当可以显示 IRIS 系统指标(SAM 中的默认设置)、IRIS 应用程序指标(您需要将这些指标构建到应用程序中)以及其他指标(如 node-exporter 或由供应商创建的任何数量的指标)时,真正强大的功能才体现出来。 例如,[使用 SAM 和 cAdvisor 监视 Docker 容器](https://community.intersystems.com/post/monitor-docker-containers-using-sam-and-cadvisor)