#InterSystems IRIS for Health

0 关注者 · 862 帖子

InterSystems IRIS for Health™ 是全球第一个也是唯一一个专门为医疗应用程序的快速开发而设计的数据平台,用于管理全世界最重要的数据。它包括强大的开箱即用的功能:事务处理和分析、可扩展的医疗保健数据模型、基于 FHIR 的解决方案开发、对医疗保健互操作性标准的支持等等。所有这些将使开发者能够快速实现价值并构建具有突破性的应用程序。了解更多信息

文章 姚 鑫 · 三月 7, 2021 17m read

第五章 SQL定义表(二)

主键

InterSystems IRIS提供了两种方法来唯一标识表中的行:RowID和主键。

可选的主键是一个有意义的值,应用程序可以使用该值唯一地标识表中的行(例如,联接中的行)。主键可以是用户指定的数据字段,也可以是多个数据字段的组合。主键值必须是唯一的,但不必是整数值。 RowID是一个内部用于标识表中行的整数值。通常,主键是由应用程序生成的值,而RowID是由InterSystems IRIS生成的唯一整数值。

系统会自动创建一个主map,以使用RowID字段访问数据行。如果定义主键字段,系统将自动创建并维护主键索引。

显然,具有两个不同的字段和索引来标识行的双重性不一定是一件好事。可以通过以下两种方式之一解析为单个行标识符和索引:

  • 使用应用程序生成的主键值作为IDKEY。 可以通过使用关键字PrimaryKeyIdKey在类定义中标识主键索引来实现这一点(如果为此目的设置了PKey is IdKey标志,也可以在DDL中实现这一点)。 这使得主键索引成为表的主映射。 因此,主键将被用作行的主要内部地址。 如果主键包含多个字段,或者主键值不是整数,那么这种方法的效率会较低。
  • 不要使用应用程序生成的主键值,而应在应用程序中使用系统生成的RowID整数作为应用程序使用的主键(例如,在joins中)。这样做的好处是,整数RowID有助于进行更有效的处理,包括使用位图索引。

根据应用程序的性质,可能希望解析为单个行标识符和索引,或者为应用程序生成的主键和系统生成的RowID具有单独的索引。

RowVersion,AutoIncrement和串行计数器字段

InterSystems SQL支持三种专用数据类型,用于自动增加计数器值。这三种数据类型都是扩展%Library.BigInt数据类型类的子类。

  • %Library.RowVersion:计算在命名空间范围内所有RowVersion表的插入和更新。只有在包含ROWVERSION字段的表中进行插入和更新时,此计数器才会递增。 ROWVERSION值是唯一的且不可修改。此名称空间范围的计数器永远不会重置。
  • %Library.Counter(也称为SERIAL计数器字段):对表中的插入进行计数。默认情况下,此字段接收一个自动递增的整数。但是,用户可以为此字段指定一个非零的整数值。用户可以指定重复值。如果用户提供的值大于系统提供的最高值,则将自动递增计数器设置为从用户指定的值开始递增。
  • %Library.AutoIncrement:计数插入到表中的次数。默认情况下,此字段接收一个自动递增的整数。但是,用户可以为此字段指定一个非零的整数值。用户可以指定重复值。指定用户值对自动增量计数器无效。

这三个字段以及IDENTITY字段均返回AUTO_INCREMENT = YES,如以下示例所示:

SELECT COLUMN_NAME,AUTO_INCREMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'MyTable'

RowVersion Field

RowVersion字段是一个可选的用户定义字段,它提供行级版本控制,使可以确定对每个命名空间范围内的行中的数据进行更改的顺序。 InterSystems IRIS维护一个整个命名空间范围的计数器,并在每次修改行数据(插入,更新或%Save)时向该字段分配一个唯一的增量正整数。因为此计数器是整个名称空间范围的,所以对具有ROWVERSION字段的一个表进行的操作将设置ROWVERSION计数器的增量点,该值将用于同一名称空间中具有ROWVERSION字段的所有其他表。

通过指定数据类型为ROWVERSION(%Library.RowVersion)的字段来创建RowVersion字段。每个表只能指定一个ROWVERSION数据类型字段。尝试创建具有多个ROWVERSION字段的表会导致5320编译错误。

该字段可以具有任何名称,并且可以出现在任何列位置。 ROWVERSION(%Library.RowVersion)数据类型映射到BIGINT(%Library.BigInt)

此字段从自动递增计数器接收一个从1开始的正整数。只要通过插入,更新或%Save操作修改了任何启用ROWVERSION的表中的数据,此计数器就会递增。递增的值记录在已插入或更新的行的ROWVERSION字段中。

名称空间可以包含具有RowVersion字段的表和不具有该字段的表。仅对具有RowVersion字段的表的数据更改会增加整个命名空间范围的计数器。

当用数据填充表时,InterSystems IRIS会为每个插入的行将此字段分配连续的整数。如果使用ALTER TABLEROWVERSION字段添加到已经包含数据的表中,则该字段将被创建为NULL以用于预先存在的字段。对该表的任何后续插入或更新都会为该行的RowVersion字段分配一个顺序整数。该字段是只读的;尝试修改RowVersion值会生成SQLCODE -138错误:无法为只读字段插入/更新值。因此,RowVersion字段被定义为唯一且不可修改,但不是必需字段或非null

RowVersion值始终递增。它们不被重用。因此,插入和更新按时间顺序分配唯一的RowVersion值。删除操作从该序列中删除数字。因此,RowVersion值可能在数字上不连续。

此计数器永远不会重置。删除所有表数据不会重置RowVersion计数器。即使删除名称空间中包含ROWVERSION字段的所有表,也不会重置此计数器。

RowVersion字段不应包含在唯一键或主键中。 RowVersion字段不能是IDKey索引的一部分。

分片表不能包含RowVersion字段。

RowVersion字段未隐藏(通过SELECT *显示)。

在同一名称空间中的三个表的以下示例中显示了这一点。

  1. 创建表1表3,每个都有一个ROWVERSION字段,并创建表2没有一个ROWVERSION字段。
  2. Table1中插入十行。这些行的ROWVERSION值是接下来的十个计数器增量。由于以前未使用过计数器,因此它们是1到10。
  3. Table2中插入十行。由于Table2没有ROWVERSION字段,因此计数器不会增加。
  4. 更新表1的行。该行的ROWVERSION值将更改为下一个计数器增量(在这种情况下为11)。
  5. Table3中插入十行。这些行的ROWVERSION值是接下来的十个计数器增量(12到21)。
  6. 更新表1的行。该行的ROWVERSION值更改为下一个计数器增量(在这种情况下为22)。
  7. 删除表1的行。 ROWVERSION计数器不变。
  8. 更新Table3的一行。该行的ROWVERSION值将更改为下一个计数器增量(在这种情况下为23)。

Serial Counter Field

可以使用SERIAL数据类型(在持久性类表定义中为%Library.Counter)来指定一个或多个可选的整数计数器字段,以记录在表中插入记录的顺序。每个串行计数器字段都维护自己的独立计数器。

每当将一行插入表中时,串行计数器字段都会从其自动增量计数器接收一个正整数,该行没有提供任何值(NULL)或值为0。但是,用户可以指定非零整数值插入期间针对此字段的值,将覆盖表计数器的默认值。

  • 如果INSERT没有为计数器字段指定非零整数值,则计数器字段将自动接收正整数计数器值。计数从1开始。每个连续值都是从为此字段分配的最高计数器值开始的1增量。
  • 如果INSERTcounter字段指定了一个非零的整数值,则该字段将接收该值。它可以是正整数或负整数,可以低于或高于当前计数器值,并且可以是已经分配给该字段的整数。如果该值大于任何分配的计数器值,它将自动增量计数器的增量起始点设置为该值。

尝试更新计数器字段值会导致SQLCODE -105错误。

TRUNCATE TABLE命令将该计数器重置为1。即使使用DELETE命令删除表中的所有行,也不会通过DELETE命令将其重置。

分片表不能包含串行计数器字段。

AutoIncrement Field

可以使用%Library.AutoIncrement数据类型(或BIGINT AUTO_INCREMENT)来指定一个整数计数器字段,以记录在表中插入记录的顺序。每个表只能指定一个%AutoIncrement数据类型字段。每当将一行插入表中时,此字段都会从自动增量计数器接收一个正整数,该行没有提供任何值(NULL)或值为0。但是,用户可以为此指定非零整数值插入过程中的字段,将覆盖表计数器的默认值。

  • 如果INSERT没有为计数器字段指定非零整数值,则计数器字段将自动接收正整数计数器值。计数从1开始。每个连续值都是从为此字段分配的最高计数器值开始的1增量。
  • 如果INSERTcounter字段指定了一个非零的整数值,则该字段将接收该值。它可以是正整数或负整数,可以低于或高于当前计数器值,并且可以是已经分配给该字段的整数。用户分配的值对自动增量计数器无效。

尝试更新计数器字段值会导致SQLCODE -105错误。

TRUNCATE TABLE命令将该计数器重置为1。即使使用DELETE命令删除表中的所有行,也不会通过DELETE命令将其重置。

分片表可以包含一个AutoIncrement字段。

通过创建持久性类来定义表

在InterSystems IRIS中定义表的主要方法是使用Studio创建持久性类定义。当这些类在InterSystems IRIS数据库中保存并编译时,它们会自动投影到与类定义相对应的关系表中:每个类代表一个表;每个类代表一个表。每个属性代表一列,依此类推。可为一个类(表)定义的属性(列)的最大数量为1000

例如,以下定义了持久类MyApp.Person

Class MyApp.Person Extends %Persistent 
{
Property Name As %String(MAXLEN=50) [Required];
Property SSN As %String(MAXLEN=15) [InitialExpression = "Unknown"];
Property DateOfBirth As %Date;
Property Sex As %String(MAXLEN=1);
}

编译后,这将在MyApp模式中创建MyApp.Person持久类和相应的SQL表Person

在此示例中,指定了程序包名称MyApp。定义持久类时,未指定的程序包名称默认为User。这对应于默认的SQL模式名称SQLUser。例如,将名为“Students”的表定义为持久类将创建类User.Students,以及相应的SQL schema.table名称SQLUser.Students

在此示例中,持久类名称Person是默认的SQL表名称。可以使用SqlTableName类关键字来提供其他SQL表名称。

可以使用DDL CREATE TABLE语句(指定SQL schema.table名称)定义相同的MyApp.Person表。成功执行此SQL语句会生成一个相应的持久性类,其包名称为MyApp,类名称为Person:

CREATE TABLE MyApp.Person (
    Name VARCHAR(50) NOT NULL,
    SSN VARCHAR(15) DEFAULT 'Unknown',
    DateOfBirth DATE,
    Sex VARCHAR(1)
)

CREATE TABLE在相应的类定义中未指定显式的StorageStrategy。相反,它将采用已定义的默认存储策略。

默认情况下,CREATE TABLE在相应的类定义中指定Final class关键字,指示它不能具有子类。

请注意,诸如上图所示的持久性类定义在编译时会创建相应的表,但是无法使用SQL DDL命令(或通过使用Management Portal Drop操作)来修改或删除此表定义,这会向显示消息“未为类'schema.name'启用DDL ...”)。必须在表类定义中指定[DdlAllowed]才能进行以下操作:

Class MyApp.Person Extends %Persistent [DdlAllowed]

可以在类定义中指定%Populate以启用使用测试数据自动填充表。

Class MyApp.Person Extends (%Persistent,%Populate) [DdlAllowed]

这为该类提供了Populate()方法。运行此方法将在表中填充十行测试数据。

定义数据值参数

每个属性(字段)定义都必须指定一个数据类型类,该类指定该属性所基于的类。指定的数据类型将字段的允许数据值限制为该数据类型。定义投影到表的持久类时,必须使用%Library包中的类指定此数据类型。可以将此类指定为%Library.Datatype%Datatype

许多数据类型类提供的参数使可以进一步定义允许的数据值。这些参数特定于单个数据类型。以下是一些较常见的数据定义参数:

  • 数据值物理限制
  • 允许的数据值:枚举或模式匹配
  • 通过定义唯一索引来唯一数据值
  • 通过定义SqlComputeCode计算数据值

数据值限制

对于数字数据类型,可以指定MAXVALMINVAL参数以限制允许值的范围。根据定义,数字数据类型具有最大支持值(正数和负数)。可以使用MAXVALMINVAL进一步限制允许的范围。

对于字符串数据类型,可以指定MAXLENMINLEN参数以限制允许的长度(以字符为单位)。根据定义,字符串数据类型具有最大支持的长度。可以使用MAXLENMINLEN进一步限制允许的范围。默认情况下,超过MAXLEN的数据值会生成字段验证错误:INSERTSQLCODE -104UPDATESQLCODE -105。可以指定TRUNCATE = 1以允许超过MAXLEN的字符串数据值。指定的字符串将被截断为MAXLEN长度。

允许的数据值

可以通过两种方式限制实际数据值:

  • 允许值的列表(带有VALUELISTDISPLAYLIST的枚举值)。
  • 允许值的匹配模式(PATTERN)。

枚举值

通过将表定义为持久类,可以定义仅包含某些指定值的属性(字段)。这是通过指定VALUELIST参数来完成的。 VALUELIST(指定逻辑存储值的列表)通常与DISPLAYLIST(指定相应的显示值的列表)一起使用。这两个列表都以列表定界符开头。几种数据类型可以指定VALUELISTDISPLAYLIST。下面的示例定义两个带有枚举值的属性:

Class Sample.Students Extends %Persistent 
{
Property Name As %String(MAXLEN=50) [Required];
Property DateOfBirth As %Date;
Property ChoiceStr As %String(VALUELIST=",0,1,2",DISPLAYLIST=",NO,YES,MAYBE");
Property ChoiceODBCStr As %EnumString(VALUELIST=",0,1,2",DISPLAYLIST=",NO,YES,MAYBE");
}

如果指定了VALUELIST,则INSERTUPDATE只能指定VALUELIST中列出的值之一,或者不提供值(NULL)。 VALUELIST有效值区分大小写。指定与VALUELIST值不匹配的数据值会导致字段值验证失败:INSERTSQLCODE -104UPDATESQLCODE -105

在ODBC模式下显示时,%String%EnumString数据类型的行为不同。使用上面的示例,当以逻辑模式显示时,ChoiceStrChoiceODBCStr都显示其VALUELIST值。在“显示”模式下显示时,ChoiceStrChoiceODBCStr均显示其DISPLAYLIST值。当以ODBC模式显示时,ChoiceStr显示VALUELIST值;否则显示VALUELIST值。 ChoiceODBCStr显示DISPLAYLIST值。

值的模式匹配

几种数据类型可以指定PATTERN参数。 PATTERN将允许的数据值限制为与指定的ObjectScript模式匹配的数据值,指定为带引号的字符串,省略前导问号。以下示例使用模式定义属性:

Class Sample.Students Extends %Persistent 
{
Property Name As %String(MAXLEN=50) [Required];
Property DateOfBirth As %Date;
Property Telephone As %String(PATTERN = "3N1""-""3N1""-""4N");
}

由于将模式指定为带引号的字符串,因此模式中指定的文字必须将其双引号引起来。请注意,模式匹配是在MAXLENTRUNCATE之前应用的。因此,如果为可能超过MAXLEN并被截断的字符串指定了一个模式,则可能希望以“ .E”(任何类型的尾随字符数不限)结束该模式。

PATTERN不匹配的数据值会生成字段验证错误:INSERTSQLCODE -104UPDATESQLCODE -105

唯一值

CREATE TABLE允许将字段定义为UNIQUE。这意味着每个字段值都是唯一(非重复)值。

将表定义为持久类不支持相应的uniqueness属性关键字。相反,必须同时定义属性和该属性的唯一索引。下面的示例为每个记录提供唯一的Num值:

  Class Sample.CaveDwellers Extends %Persistent [ DdlAllowed ]
  { 
  Property Num As %Integer;
  Property Troglodyte As %String(MAXLEN=50);
  Index UniqueNumIdx On Num [ Type=index,Unique ];
  }

索引名称遵循属性的命名约定。可选的Type关键字指定索引类型。 Unique关键字将属性(字段)定义为唯一。

使用INSERTUPDATE语句时,必须具有唯一的值字段。

计算值

下面的类定义示例定义一个表,该表包含一个字段(生日),该字段在最初设置DateOfBirth字段值时使用SqlComputed来计算其值,而在更新DateOfBirth字段值时使用SqlComputeOnChange来重新计算其值。 Birthday字段值包括当前时间戳,以记录该字段值的计算/重新计算时间:

Class Sample.MyStudents Extends %Persistent [DdlAllowed]
{
  Property Name As %String(MAXLEN=50) [Required];
  Property DateOfBirth As %Date;
  Property Birthday As %String 
          [ SqlComputeCode = {SET {Birthday}=$PIECE($ZDATE({DateOfBirth},9),",")_
                              " changed: "_$ZTIMESTAMP},
                              SqlComputed, SqlComputeOnChange = DateOfBirth ];
}
```java

请注意,对`DateOfBirth`的`UPDATE`指定现有的`DateOfBirth`值不会重新计算`Birthday`字段值。

## 嵌入式对象(%SerialObject)

可以通过引用定义属性的嵌入式串行对象类来简化持久表的结构。例如,希望`MyData.Person`包含地址信息,包括街道,城市,州和邮政编码。可以定义一个定义这些属性的串行对象(`%SerialObject`)类,而不是在`MyData.Person`中指定这些属性,然后在`MyData.Person`中指定一个引用该嵌入式对象的`Home`属性。在以下类定义中显示了这一点:

```java
Class MyData.Person Extends (%Persistent) [ DdlAllowed ]
{  Property Name As %String(MAXLEN=50);
   Property Home As MyData.Address;
   Property Age As %Integer;
} 
Class MyData.Address Extends (%SerialObject)
{  Property Street As %String;
   Property City As %String;
   Property State As %String;
   Property PostalCode As %String;
 }

不能直接访问串行对象属性中的数据,必须通过引用它的持久类/表访问它们:

  • 要从持久性表中引用单个串行对象属性,请使用下划线。例如,SELECT名称Home_State FROM MyData.Person返回状态串行对象属性值作为字符串。串行对象属性值以查询中指定的顺序返回。
  • 要引用持久性表中的所有串行对象属性,请指定引用字段。例如,SELECT Home FROM MyData.Person%List结构形式返回所有MyData.Address属性的值。串行对象属性值以串行对象中指定的顺序返回:Home_Street,Home_City,Home_State,Home_PostalCode。在Management Portal SQL界面“目录详细信息”中,此引用字段称为“容器”字段。这是一个Hidden字段,因此SELECT *语法不返回。
  • 持久类的SELECT *单独返回所有串行对象属性,包括嵌套的串行对象。例如,SELECT * FROM MyData.Person返回Age,Name,Home_City,Home_PostalCode,Home_State和Home_Street值(按此顺序);它不返回Home%List结构值。串行对象属性值以排序顺序返回。 SELECT *首先按排序顺序(通常按字母顺序)列出持久性类中的所有字段,然后按排序顺序列出嵌套的串行对象属性。

请注意,嵌入式串行对象不必与引用它的持久性表位于同一程序包中。

定义嵌入式对象可以简化持久性表定义:

  • 持久表可以包含多个属性,这些属性引用同一嵌入式对象中的不同记录。例如,MyData.Person表可以包含HomeOffice属性,这两个属性均引用MyData.Address串行对象类。
  • 多个持久表可以引用同一嵌入式对象的实例。例如,MyData.Person表的Home属性和MyData.Employee WorkPlace属性都可以引用MyData.Address串行对象类。
  • 一个嵌入式对象可以引用另一个嵌入式对象。例如,MyData.Address嵌入式对象包含引用MyData.Telephone嵌入式对象的Phone属性,其中包含CountryCodeAreaCodePhoneNum属性。在持久类中,使用多个下划线来引用嵌套的串行对象属性,例如Home_Phone_AreaCode

编译串行对象类会在存储定义中生成数据规范。编译器通过在串行对象类名称后附加单词“State”来为该规范分配数据名称。因此,为MyData.Address分配了<Data name =“ AddressState”>。如果此名称(在此示例中为AddressState)已经用作属性名称,则编译器将附加一个整数以创建唯一的数据名称:<Data name =“ AddressState1”>

类方法

可以将类方法指定为表定义的一部分,如以下示例所示:

Class MyApp.Person Extends %Persistent 
{
Property Name As %String(MAXLEN=50) [Required];
Property SSN As %String(MAXLEN=15) [InitialExpression = "Unknown"];
Property DateOfBirth As %Date;
Property Sex As %String(MAXLEN=1);
ClassMethod Numbers() As %Integer [ SqlName = Numbers, SqlProc ]
  {
   QUIT 123
  }
}

在SELECT查询中,可以按以下方式调用此方法:

SELECT Name,SSN,Sample.Numbers() FROM Sample.Person

image

通过创建持久性类来定义分片表

必须先建立分片环境,然后才能定义作为分片表投影的持久性类。

要将持久性类定义为分片,请指定类关键字Sharded = 1。 (类关键字Sharded = 2保留供生成的类内部使用。)

注意:请勿尝试设置或更改现有类定义的与分片相关的类属性。仅应为不包含数据的新表指定这些属性。这包括设置Sharded类关键字和与分片相关的索引关键字。尝试编辑现有类的任何与分片相关的属性都可能导致数据无法访问。

下例显示了Sharded = 1持久类的类定义:

Class Sample.MyShardT Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Sharded = 1]
{
...
}

如果将一个类定义为分片,则它必须是持久性的ClassType。如果未将分片类定义为ClassType持久类,则在类编译期间将返回错误,例如:ERROR#5599:分片类'Sample.Address'必须为ClassType'persistent',而不是ClassType'serial'。分片类使用的存储类必须为%Storage.Persistent或其子类%Storage.Shard。如果分片类的存储类不是%Storage.Persistent,则在类编译期间将返回以下错误:错误#5598:分片类'Sample.Vendor'必须使用存储类型%Storage.Persistent,而不是存储类型' %Storage.SQL”

定义分片类时,应定义参数DEFAULTCONCURRENCY = 0

然后,可以定义ShardKey索引。

创建分片表时,将自动生成抽象的分片键索引。分片键索引的目的是用作确定行所在的分片的键。

分片类方法

分片类(Sharded = 1)支持%Library.Persistent方法%Open(),%OpenId(),%Save(),%Delete()和%DeleteId()具有以下限制:并发concurrency参数被忽略;删除将始终使用并发concurrency= 0,而不管用户提供的并发值如何。完全支持回调方法%OnDelete(),%OnAfterDelete(),%OnOpen(),%OnBeforeSave()和%OnAfterSave()。这些回调方法在分片主机上执行,而不是在分片服务器上执行。分片本地类(Sharded = 2)不支持这些方法。

分片类(Sharded = 1)不支持%Library.Persistent方法%LockExtent()%UnlockExtent()。定义并发参数的对象方法中的所有并发参数都要求值concurrency = 0;否则,值为0。可以通过设置DEFAULTCONCURRENCY = 0来建立默认值

分片类限制

  • 分片类不支持的类参数:CONNECTIONDEFAULTGLOBALDSINTERVALDSTIMEIDENTIFIEDBYOBJJOURNAL
  • 分片类不支持的类关键字:languageViewQuery
  • 分片类不支持的超级类:%Library.IndexBuilder%DocDB.Document
  • 分片类不支持的属性数据类型:%Library.Text
  • 分片类不支持关系属性。
  • 分片类不支持投影。
  • 分片类不支持功能索引(无法定义索引TypeClass)。
  • 分片类不支持使用除“对象”以外的语言的任何方法。
  • 分片类不支持任何非%SQLQuery类型的类查询。

尝试使用任何这些功能来编译分片类都会导致编译时错误。

0
0 152
文章 姚 鑫 · 三月 6, 2021 16m read

第五章 SQL定义表

表名称和架构名称

可以通过定义表(使用CREATE TABLE)或通过定义投影到表的持久类来创建表:

  • DDL:InterSystemsIRIS®数据平台使用CREATE TABLE中指定的表名来生成相应的持久类名,并使用指定的架构名来生成相应的包名。
  • 类定义:InterSystemsIRIS®数据平台使用持久类名称来生成对应的表名,并使用包名称来生成对应的模式名。

由于以下原因,这两个名字之间的对应关系可能不相同:

  • 持久化类和SQL表遵循不同的命名约定。 适用不同的有效字符和长度要求。 模式和表名不区分大小写; 包名和类名区分大小写。 系统自动将有效提供的名称转换为有效的对应名称,以确保生成的名称是惟一的。
  • 持久化类名与对应的SQL表名之间的匹配是默认的。 可以使用SqlTableName类关键字来提供不同的SQL表名。
  • 默认模式名可能与默认包名不匹配。 如果指定一个非限定的SQL表名或持久类名,系统将提供一个默认的模式名或包名。 初始的默认模式名是SQLUser; 初始默认包名为“User”

模式名称

表、视图或存储过程名称可以是限定的(schema.name),也可以是限定的(name)。

  • 如果指定模式名(限定名),则指定的表、视图或存储过程将被分配给该模式。 如果模式不存在,则InterSystems SQL创建模式,并将表、视图或存储过程分配给它。
  • 如果没有指定模式名(非限定名),InterSystems SQL将使用默认模式名或模式搜索路径分配模式,如下所述。

模式命名注意事项

模式名遵循标识符约定,需要特别注意非字母数字字符的使用。 模式名不应该指定为带分隔符的标识符。 尝试指定“USER”或任何其他SQL保留字作为模式名会导致SQLCODE -312错误。INFORMATION_SCHEMA模式名和相应的信息。 模式包名在所有命名空间中保留。 用户不应该在这个模式/包中创建表/类。

当执行一个创建操作(比如create TABLE),指定一个还不存在的模式时,InterSystems IRIS将创建新的模式。 InterSystems IRIS使用模式名生成相应的包名。 由于模式及其对应包的命名约定不同,用户应该注意非字母数字字符的名称转换注意事项。 这些名称转换的注意事项与表不同:

  • 初始字符:
    • % (percent):指定%作为模式名的第一个字符,表示相应的包为系统包,其所有类为系统类。 这种用法需要适当的权限; 否则,这种用法会发出一个SQLCODE -400错误,%msg表示<PROTECT>错误。
    • _(下划线):如果模式名的第一个字符为下划线,则该字符将被对应包名中的小写“u”替换。 例如,模式名_MySchema生成名为uMySchema的包。
  • 后续的字符:
    • _(下划线):如果模式名第一个字符以外的其他字符是下划线,则该字符将被对应包名中的句点(.)替换。 由于句点是类的分隔符,下划线将模式分为包和子包。 因此,My_Schema生成包含包模式(My.Schema)的包My。
    • @#$ characters:如果模式名包含任何这些字符,这些字符将从相应的包名中剥离。 如果剥离这些字符会产生重复的包名,那么将进一步修改剥离的包名:将剥离的模式名的最后一个字符替换为顺序整数(以0开始),以产生唯一的包名。 因此,My@#$Schema生成MySchema包,然后创建My#$Schema生成MySchem0包。 同样的规则也适用于表名对应的类名。

保留模式名

INFORMATION_SCHEMA模式名和相应的信息。 模式包名在所有命名空间中保留。 用户不应该在这个模式/包中创建表/类

在所有名称空间中保留IRIS_Shard模式名。 用户不应在此模式中创建表、视图或过程。 存储在IRIS_Shard模式中的项不会通过编目查询或INFORMATION_SCHEMA查询显示。

默认模式名称

  • 在执行DDL操作(例如创建或删除表、视图、触发器或存储过程)时,会提供一个非限定名称作为默认的模式名。 架构搜索路径值将被忽略。
  • 在执行DML操作时,例如通过选择、调用、插入、更新或删除访问现有表、视图或存储过程,将从模式搜索路径(如果提供了)提供一个不限定的名称。 如果没有架构搜索路径,或者没有使用架构搜索路径定位指定项,则提供默认的架构名称。

初始设置是对所有名称空间(系统范围)使用相同的默认模式名。 可以为所有命名空间设置相同的默认模式名,也可以为当前命名空间设置默认模式名。

如果创建了一个具有非限定名称的表或其他项,InterSystems IRIS将为其分配默认模式名和相应的持久类包名。 如果一个命名的或默认的模式不存在,InterSystems IRIS将创建模式(和包),并将创建的项分配给该模式。 如果删除模式中的最后一项,InterSystems IRIS将删除该模式(和包)。 下面的模式名解析描述适用于表名、视图名和存储过程名。

系统范围的初始默认模式名是SQLUser。 对应的持久类包名是User。 因此,非限定表名Employee或限定表名SQLUserEmployee将生成类User.Employee

因为USER是一个保留字,尝试用USER的模式名(或任何SQL保留字)指定限定名会导致SQLCODE -1错误。

要返回当前默认模式名,请调用$SYSTEM.SQL.DefaultSchema()方法:

DHC-APP>WRITE $SYSTEM.SQL.DefaultSchema()
SQLUser

或者使用以下预处理器宏:

#Include %occConstant
  WRITE $$$DefSchema

可以使用以下任意一种方式更改默认模式名:

  • 进入管理界面。 在系统管理中,选择Configuration,然后选择SQL和对象设置,然后选择SQL。 在这个屏幕上,可以查看和编辑当前系统范围内的默认模式设置。 这个选项设置系统范围的默认模式名。image

image

这个系统范围的设置可以被当前命名空间的SetDefaultSchema()方法值覆盖。

  • $SYSTEM.SQL.SetDefaultSchema()方法。默认情况下,此方法在系统范围内设置默认架构名称。但是,通过将布尔值第3个参数设置为1,可以仅为当前名称空间设置默认架构。当不同的名称空间具有不同的默认架构名称时,DefaultSchema()方法将返回当前名称空间的默认架构名称。

注意:当更改默认的SQL模式名称时,系统将自动清除系统上所有名称空间中的所有缓存查询。 通过更改默认模式名称,可以更改所有包含非限定表、视图或存储过程名称的查询的含义。 强烈建议在安装InterSystems IRIS时建立默认的SQL模式名,以后不要修改。

模式名用于生成相应的类包名。 因为这些名称有不同的命名约定,所以它们可能不相同。

可以通过将其设置为系统范围的默认模式来创建与SQL保留字同名的模式,但是不建议这样做。 名为User的默认模式根据类命名唯一性约定,生成相应的类包名称User0

_CURRENT_USER关键字

  • 作为系统范围的默认模式名:如果指定_CURRENT_USER作为默认模式名,InterSystems IRIS将指定当前登录进程的用户名作为默认模式名。 _CURRENT_USER值是$USERNAME ObjectScript特殊变量值的第一部分。 如果$USERNAME包含一个名字和一个系统地址(Deborah@TestSys), _CURRENT_USER只包含名字片段; 这意味着_CURRENT_USER可以将相同的默认模式名分配给多个用户。 如果进程没有登录,_CURRENT_USER指定SQLUser作为默认的模式名。

如果指定_CURRENT_USER/name作为默认模式名,其中name是选择的任意字符串,那么InterSystems IRIS将当前登录进程的用户名分配为默认模式名。 如果进程没有登录,则name将用作默认的模式名。 例如,如果进程没有登录,_CURRENT_USER/HMO使用HMO作为默认模式名。

$SYSTEM.SQL.SetDefaultSchema()中,指定"_CURRENT_USER"作为带引号的字符串。

  • DDL命令中的模式名:如果在DDL语句中指定_CURRENT_USER作为显式的模式名,InterSystems IRIS将其替换为当前系统范围内的默认模式。 例如,如果系统范围的默认模式是SQLUser,则命令DROP TABLE _CURRENT_USEROldTable SQLUser.OldTable下降。 这是一种方便的方式来限定名称,以显式地指示应该使用系统范围的默认模式。 它在功能上与指定非限定名相同。 此关键字不能在DML语句中使用。

模式搜索路径

当访问一个现有的表(或视图,或存储过程)进行DML操作时,将从模式搜索路径中提供一个非限定的名称。 按照指定的顺序搜索模式,并返回第一个匹配项。 如果在搜索路径中没有找到匹配的模式,或者没有搜索路径,则使用默认的模式名。 (注意,#Import宏指令使用了不同的搜索策略,不会“失败”到默认的模式名。)

  • 在嵌入式SQL中,可以使用#SQLCompile Path宏指令或#Import宏指令来提供架构搜索路径,系统间IRIS使用该路径来解析非限定名称。 #SQLCompile Path根据遇到的第一个匹配项解析不限定的名称。 如果搜索路径中列出的所有模式只有一个匹配项,则#Import解析非限定名。
  • 下面的示例提供了包含两个模式名的搜索路径:
#SQLCompile Path=Customers,Employees
  • 在动态SQL中,可以使用%SchemaPath属性提供模式搜索路径,系统间IRIS使用该路径解析不限定的表名。 可以直接指定%SchemaPath属性,也可以将其指定为%SQL的第二个参数。 声明%new()方法。 下面的示例提供了包含两个模式名的搜索路径:
  SET tStatement = ##class(%SQL.Statement).%New(0,"Customers,Employees")
  • 在SQL Shell中,可以设置PATH SQL Shell配置参数来提供架构搜索路径,系统间IRIS使用该路径解析不限定的名称。

如果非限定名与模式搜索路径中指定的任何模式或默认模式名不匹配,则会发出SQLCODE -30错误,例如:SQLCODE: -30消息:Table 'PEOPLE' not found in schemas: CUSTOMERS,EMPLOYEES,SQLUSER

包含特定于平台的模式名

当创建一个基于odbc的查询以通过Mac上的Microsoft query从Microsoft Excel运行时,如果从可用的表列表中选择一个表,则生成的查询不包括该表的模式(相当于类的包)。 例如,如果选择从示例模式返回Person表的所有行,则生成的查询为:

SELECT * FROM Person

因为InterSystems IRIS将不限定的表名解释为SQLUser模式中的表名,所以该语句要么失败,要么从错误的表返回数据。 要纠正这一点,编辑查询(在SQL View选项卡上),显式引用所需的模式。 然后查询应该是:

SELECT * FROM Sample.Person

List模式

INFORMATION.SCHEMASCHEMATA persistent类列出当前名称空间中的所有模式。

下面的示例返回当前命名空间中的所有非系统模式名:

SELECT SCHEMA_NAME 
FROM INFORMATION_SCHEMA.SCHEMATA WHERE NOT SCHEMA_NAME %STARTSWITH '%'

Management Portal SQL界面的左侧允许查看模式(或匹配筛选器模式的多个模式)的内容。

表名

每个表在其模式中都有一个唯一的名称。 一个表有一个SQL表名和一个对应的持久化类名; 这些名称在允许的字符、区分大小写和最大长度方面有所不同。 如果使用SQL CREATE TABLE命令定义,则指定遵循标识符约定的SQL表名; 系统生成一个对应的持久化类名。 如果定义为持久类定义,则必须指定只包含字母和数字字符的名称; 这个名称既用作区分大小写的持久类名,也用作(默认情况下)对应的不区分大小写的SQL表名。 可选的SqlTableName class关键字允许用户指定不同的SQL表名。

当使用CREATE TABLE命令创建表时,InterSystems IRIS使用表名生成相应的持久化类名。 由于表及其对应类的命名约定不同,用户应该注意非字母数字字符的名称转换:

  • 初始字符:
    • % (percent): %作为表名的第一个字符是保留的,应该避免(参见标识符)。 如果指定了,%字符将从对应的持久化类名中剥离。
    • _(下划线):如果表名的第一个字符是下划线,则该字符将从对应的持久化类名中剥离。 例如,表名_MyTable生成类名MyTable
    • 数字:表名的第一个字符不能是数字。 如果表名的第一个字符是标点符号,则第二个字符不能是数字。 这将导致一个SQLCODE -400错误,%msg值为" error #5053:类名'schema.name' is invalid "(没有标点字符)。 例如,指定表名_7A会生成%msg " ERROR #5053: Class name 'User.7A' is invalid "
  • 后续的字符:
    • 字母:表名中至少包含一个字母。 表名的第一个字符或初始标点字符后的第一个字符必须是字母。 如果一个字符通过$ZNAME测试,它就是一个有效的字母; $ZNAME字母验证因不同的地区而不同。 (注意,$ZNAME不能用于验证SQL标识符,因为标识符可能包含标点字符。)
    • _(下划线),@#$ characters:如果表名包含这些字符中的任何一个,这些字符将从对应的类名中剥离出来,并生成一个唯一的持久类名。 由于生成的类名不包括标点字符,因此不建议创建仅在标点字符上不同的表名。
  • 表名在其模式中必须是唯一的。 如果试图创建一个名称仅与现有表大小写不同的表,将会产生SQLCODE -201错误。

同一个模式中的视图和表不能具有相同的名称。 尝试这样做会导致SQLCODE -201错误。

可以使用$SYSTEM.SQL.TableExists()方法确定一个表名是否已经存在。 可以使用$SYSTEM.SQL.ViewExists()方法确定视图名是否已经存在。 这些方法还返回与表或视图名称对应的类名。 管理门户SQL interface Catalog Details表信息选项显示与所选SQL表名称对应的类名。

试图指定“USER”或任何其他SQL保留字作为表名或模式名会导致SQLCODE -312错误。 要指定SQL保留字作为表名或模式名,可以指定名称作为带分隔符的标识符。 如果使用带分隔符的标识符指定包含非字母数字字符的表或模式名,InterSystems IRIS将在生成相应的类或包名时删除这些非字母数字字符。

适用以下表名长度限制:

  • 唯一性:InterSystems IRIS对持久化类名的前189个字符执行唯一性检查。 对应的SQL表名可能超过189个字符,但是,当去掉非字母数字字符时,它必须在189个字符的限制内是唯一的。 InterSystems IRIS对包名的前189个字符执行唯一性检查。
  • 建议最大长度:一般来说,一个表名不应该超过128个字符。 一个表名可能比96个字符长得多,但是在前96个字母数字字符中不同的表名更容易处理。
  • 最大组合长度:包名和它的持久类名(加在一起时)不能超过220个字符。 这包括默认的模式(包)名(如果没有指定模式名)和分隔包名和类名的点字符。 当表名转换为对应的持久化类名时,删除超过220个字符时,模式和表名的组合长度可以超过220个字符。

RowID字段

在SQL中,每条记录都由一个唯一的整数值标识,这个整数值称为RowID 在InterSystems SQL中,不需要指定RowID字段。 当创建表并指定所需的数据字段时,会自动创建RowID字段。 这个RowID在内部使用,但没有映射到类属性。 默认情况下,只有当持久化类被投影到SQL表时,它的存在才可见。 在这个投影表中,将出现一个额外的RowID字段。 默认情况下,这个字段被命名为“ID”,并分配给第1列。

默认情况下,当在表中填充数据时,InterSystems IRIS将从1开始向该字段分配连续的正整数。RowID数据类型为BIGINT(%Library.BigInt)。为RowID生成的值具有以下约束:每个值都是唯一的。不允许使用NULL值。排序规则是精确的。默认情况下,值不可修改。

默认情况下,InterSystems IRIS将此字段命名为“ ID”。但是,此字段名称不是保留的。每次编译表时都会重新建立RowID字段名。如果用户定义了一个名为“ ID”的字段,则在编译表时,InterSystems IRIS会将RowID命名为“ ID1”。例如,如果用户随后使用ALTER TABLE定义了一个名为“ ID1”的字段,则表编译会将RowID重命名为“ ID2”,依此类推。在持久性类定义中,可以使用SqlRowIdName类关键字直接为此类投影到的表指定RowID字段名。由于这些原因,应避免按名称引用RowID字段。

InterSystems SQL提供了%ID伪列名称(别名),无论分配给RowID的字段名称如何,该伪列名称始终返回RowID值。 (InterSystems TSQL提供了$IDENTITY伪列名称,其作用相同。)

ALTER TABLE无法修改或删除RowID字段定义。

将记录插入表中后,InterSystems IRIS将为每个记录分配一个整数ID值。 RowID值始终递增。它们不被重用。因此,如果已插入和删除记录,则RowID值将按升序排列,但可能不连续。

  • 默认情况下,使用CREATE TABLE定义的表使用$SEQUENCE执行ID分配,从而允许多个进程快速同时填充该表。当使用$SEQUENCE填充表时,会将RowID值序列分配给进程,然后该进程将顺序分配它们。因为并发进程使用它们自己分配的序列分配RowID,所以不能假定多个进程插入的记录按插入顺序排列。

可以通过设置SetDDLUseSequence()方法,将InterSystems IRIS配置为使用$INCREMENT执行ID分配。若要确定当前设置,请调用$ SYSTEM.SQL.CurrentSettings()方法。

  • 默认情况下,通过创建持久性类定义的表将使用$INCREMENT执行ID分配。在持久性类定义中,可以将IdFunction存储关键字设置为序列或增量;否则,可以设置为0。例如,<IdFunction>序列</ IdFunction>

在持久性类定义中,IdLocation存储关键字global(例如,对于持久性类Sample.Person:<IdLocation> ^ Sample.PersonD </ IdLocation>)包含RowID计数器的最高分配值。 (这是分配给记录的最高整数,而不是分配给进程的最高整数。)请注意,此RowID计数器值可能不再与现有记录相对应。要确定是否存在具有特定RowID值的记录,请调用表的%ExistsId()方法。

通过TRUNCATE TABLE命令重置RowID计数器。即使使用DELETE命令删除表中的所有行,也不会通过DELETE命令将其重置。如果没有数据插入表中,或者已使用TRUNCATE TABLE删除所有表数据,则IdLocation存储关键字全局值未定义。

默认情况下,RowID值不可用户修改。尝试修改RowID值会产生SQLCODE -107错误。覆盖此默认值以允许修改RowID值可能会导致严重的后果,只有在非常特殊的情况下并应格外谨慎。 Config.SQL.AllowRowIDUpdate属性允许RowID值是用户可修改的。

基于字段的RowID

通过定义一个用于投影表的持久类,可以定义RowID以具有字段或字段组合中的值。为此,请使用IdKey index关键字指定一个索引。例如,一个表可以具有一个RowID,其RowId通过在PatientName [IdKey]上指定索引定义IdxId来与PatientName字段的值相同;或者可以通过指定索引定义IdxId来将PatientNameSSN字段的组合值在(PatientName,SSN)[IdKey];上。

  • 基于字段的RowID效率比采用系统分配的连续正整数的RowId效率低。
  • INSERT上:为构成RowId的字段或字段组合指定的值必须唯一。指定非唯一值将生成SQLCODE -119“在插入时唯一性或主键约束唯一性检查失败”。
  • UPDATE上:默认情况下,组成RowId的每个字段的值都是不可修改的。尝试修改这些字段之一的值会生成SQLCODE -107“无法基于字段更新RowIDRowID”。

RowID基于多个字段时,RowID值是由||连接的每个组成字段的值。操作员。例如,Ross,Betsy || 123-45-6789。 InterSystems IRIS尝试确定基于多个字段的RowID的最大长度。如果无法确定最大长度,则RowID长度默认为512。

隐藏的RowID?

  • 使用CREATE TABLE创建表时,默认情况下隐藏RowIDSELECT *不会显示隐藏字段,而是PRIVATE。创建表时,可以指定%PUBLICROWID关键字以使RowID不隐藏和公开。可以在CREATE TABLE逗号分隔的表元素列表中的任何位置指定此可选的%PUBLICROWID关键字。不能在ALTER TABLE中指定。
  • 创建作为表投影的持久类时,默认情况下不会隐藏RowID。它由SELECT *显示,并且是PUBLIC。可以通过指定类关键字SqlRowIdPrivate来定义具有隐藏且为PRIVATERowID的持久类。

用作外键引用的RowID必须是公共的。

默认情况下,不能将具有公共RowID的表用作源表或目标表,以使用INSERT INTO Sample.DupTable SELECT * FROM Sample.SrcTable将数据复制到重复表中。

可以使用Management Portal SQL界面“目录详细信息字段”列出“隐藏”列来显示RowID是否被隐藏。

可以使用以下程序返回指定字段(在此示例中为ID)是否被隐藏:

/// d ##class(PHA.TEST.SQL).RowID()
ClassMethod RowID()
{
	SET myquery = "SELECT FIELD_NAME,HIDDEN FROM %Library.SQLCatalog_SQLFields(?) WHERE FIELD_NAME='ID'"
	SET tStatement = ##class(%SQL.Statement).%New()
	SET qStatus = tStatement.%Prepare(myquery)
	IF qStatus'=1 {
		WRITE "%Prepare failed:" 
		DO $System.Status.DisplayError(qStatus) 
		QUIT
	}
	SET rset = tStatement.%Execute()
	DO rset.%Display()
	WRITE !,"End of data"
}

2
0 294
文章 姚 鑫 · 三月 4, 2021 11m read

第三章 SQL语言元素(二)

算术运算符和函数

InterSystems SQL支持以下算术运算符:

  • + 加法操作符。 例如,17+7 = 24

  • 减法运算符。 例如,17-7等于10。 注意,这些字符中的一对是InterSystems SQL注释指示器。 因此,要指定两个或多个减法操作符或负号,必须使用空格或圆括号。 例如,17- -7或17-(-7)等于24

运算符描述
+加法操作符。
减法运算符。例如,17-7等于10。注意,这些字符中的一对是InterSystems SQL注释指示器。因此,要指定两个或多个减法操作符或负号,必须使用空格或圆括号。
*乘法运算符。例如,17*7等于119
/除法操作符。例如:17/7 = 2.428571428571428571
\整数除法运算符。例如,17\7等于2
#模运算符。例如,17 #7等于3。注意,因为#字符也是一个有效的标识符字符,要将它用作模运算符,应该指定它与操作数之间用前后空格分隔
E求幂(科学记数法)运算符。可以是大写或小写。例如:7E3 = 7000。指数过大会导致SQLCODE -7“指数超出范围”错误。例如1E309、7E308。
()分组操作符。用于嵌套算术运算。除非使用了圆括号,否则在InterSystems SQL中算术操作的执行顺序是严格的从左到右的顺序。例如,17+7*2等于48,但17+(7 * 2)等于31
`

算术运算是对标准形式的数字进行的。

产生的数据类型

当对两个具有不同数据类型的数值执行算术运算时,结果数据类型确定如下:

对于加法(+),减法(-),整数除法(\),和取模(#):

描述NUMERICINTEGERTINYINTSMALLINTBIGINTDOUBLE
NUMERICNUMERICNUMERICNUMERICNUMERICNUMERICDOUBLE
INTEGERNUMERICBIGINTBIGINTBIGINTBIGINTDOUBLE
TINYINTNUMERICBIGINTSMALLINTINTEGERBIGINTDOUBLE
SMALLINTNUMERICBIGINTINTEGERINTEGERBIGINTDOUBLE
BIGINTNUMERICBIGINTBIGINTBIGINTBIGINTDOUBLE
DOUBLEDOUBLEDOUBLEDOUBLEDOUBLEDOUBLEDOUBLE

对于乘法(*)或除法(/):

描述NUMERICINTEGERTINYINTSMALLINTBIGINTDOUBLE
NUMERICNUMERICNUMERICNUMERICNUMERICNUMERICDOUBLE
INTEGERNUMERICNUMERICNUMERICNUMERICNUMERICDOUBLE
TINYINTNUMERICNUMERICNUMERICNUMERICNUMERICDOUBLE
SMALLINTNUMERICNUMERICNUMERICNUMERICNUMERICDOUBLE
BIGINTNUMERICNUMERICNUMERICNUMERICNUMERICDOUBLE
DOUBLEDOUBLEDOUBLEDOUBLEDOUBLEDOUBLEDOUBLE

连接任意数据类型的两个数字将产生VARCHAR字符串。

在动态SQL中,可以使用SQL列元数据来确定结果集字段的数据类型。

运算符优先级

SQL-92标准在操作符优先级方面不精确; 关于这个问题的假设在不同的SQL实现中有所不同。 InterSystems SQL可以配置为支持任意一种优先级:

  • 在InterSystems IRIS 2019.1及其后续版本中,InterSystems SQL默认支持算术运算符的ANSI优先级。 这是一个系统范围的配置设置。 当配置ANSI优先级时,"*""\""/""#"操作符的优先级高于"+""-""||"操作符。 优先级高的操作符在优先级低的操作符之前执行。 因此,3+3*5 = 18。 如果需要,可以使用括号覆盖优先级。 因此,(3+3)*5 = 30

在安装InterSystems IRIS 2019.1时,支持默认的ANSI优先级; 升级InterSystems IRIS 2018.1到InterSystems IRIS 2019.1时,操作符优先级仍然配置为InterSystems IRIS 2018.1 default:严格从左到右的顺序。

  • 在InterSystems IRIS 2018.1中,InterSystems SQL默认不提供算术运算符的优先级。 默认情况下,InterSystems SQL严格按照从左到右的顺序执行算术表达式,没有操作符优先级。 这与ObjectScript中使用的约定相同。 因此,3+3*5 = 30。 可以使用括号来强制要求的优先级。 因此,3+(3*5)= 18。 谨慎的开发人员应该使用圆括号来明确地表达他们的意图。

可以使用$SYSTEM.SQL.SetANSIPrecedence()方法在系统范围内配置任意一种SQL操作符优先级。 1 = ANSI优先; 0 =严格从左到右的计算 要确定当前设置,调用$SYSTEM.SQL.CurrentSettings()。 更改此SQL选项将立即在系统范围内生效。 更改此选项将导致在系统范围内清除所有缓存的查询。

更改SQL优先级对ObjectScript没有影响。 ObjectScript总是严格遵循从左到右的算术运算符执行。

精度和等级

数字结果的精度(数字中存在的最大数字数)为:

  • 使用以下算法确定加减:resultprecision=max(scale1, scale2)+ max(precision1-scale1, precision2-scale2)+1。 当计算结果精度大于36时,将精度值设置为36。
  • 乘法使用以下算法确定:resultprecision=min(36, precision1+precision2+1)
  • 除法(value1 / value2)通过以下算法确定:resultprecision=min(36, precision1-scale1 +scale2+max(6, scale1+precision2+1))

以下数字结果的比例(最大小数位数):

  • 加法或减法使用以下算法确定:resultscale=max(scale1, scale2)
  • 乘法使用如下算法确定:resultscale=min(17, scale1+scale2)
  • 除法(value1 / value2)通过如下算法确定:resultscale=min(17, max(6, scale1+precision2+1))

算术和三角函数

InterSystems SQL支持以下算术函数:

代码描述
ABS返回数字表达式的绝对值。
CEILING返回大于或等于数字表达式的最小整数。
EXP返回数值表达式的对数指数(以e为底)值。
FLOOR返回小于或等于数字表达式的最大整数。
GREATEST从逗号分隔的数字列表中返回最大的数字。
ISNUMERIC返回一个布尔码,指定表达式是否为有效数字。
LEAST从逗号分隔的数字列表中返回最小的数字。
LOG返回数字表达式的自然对数(以e为基数)值。
LOG10返回数字表达式的以10为基数的日志值。
MOD返回除法运算的模值(余数)。与#操作符相同。
PI返回数值常量pi。
POWER返回数值表达式的指定幂的值
ROUND返回四舍五入(或截断)到指定数字数目的数字表达式。
SIGN返回数值代码,指定数值表达式的计算结果是正、零还是负。
SQRT返回数值表达式的平方根。
SQUARE返回数值表达式的平方。
TRUNCATE返回截断为指定数字数目的数字表达式。

InterSystems SQL支持下列三角函数。

代码描述
ACOS返回数值表达式的反余弦值。
ASIN返回数字表达式的反正弦值。
ATAN返回数值表达式的正切。
COS返回数值表达式的余弦值。
COT返回数值表达式的余切。
SIN返回数值表达式的正弦值。
TAN返回数值表达式的切线。
DEGREES将弧度转换为角度。
RADIANS将角度转换为弧度。

关系运算符

条件表达式的计算结果为布尔值。条件表达式可以使用以下关系运算符:

代码描述
=等于运算符。
!=<>不等于运算符。这两种句法形式在功能上是相同的。
<少于运算符。
>大于运算符。
<=小于或等于运算符。
>=大于或等于运算符。

比较表格字段值时,这些相等运算符将使用字段的默认排序规则。 InterSystems IRIS默认值不区分大小写。比较两个文字时,比较区分大小写。

比较浮点数时,应避免使用等号运算符(等于或不等于)。浮点数(数据类型为%Library.Decimal%Library.Double类)存储为二进制值,而不是固定精度的数字。在转换过程中,舍入运算可能会导致两个浮点数不完全相等,这些浮点数旨在表示相同的数字。使用小于/大于测试来确定两个浮点数是否“相同”至所需的精度。

包含并跟随运算符

InterSystems SQL还支持“包含”和“跟随”比较运算符:

  • [ 包含运算符。返回包含操作数的所有值,包括等于该操作数的值。该运算符使用EXACT(区分大小写)排序规则。取反是NOT [
    • Contains运算符确定一个值是否包含指定的字符或字符串。区分大小写。
    • %STARTWITH谓词条件确定值是否以指定的字符或字符串开头。它不区分大小写。
    • InterSystems SQL搜索可用于确定值是否包含指定的单词或短语。 SQL Search执行上下文感知匹配。它不区分大小写。
  • ] 跟随运算符。返回排序规则序列中跟随操作数的所有值。排除操作数值本身。该运算符使用字段的默认排序规则。 InterSystems IRIS默认值不区分大小写。反之则不是]

例如,SELECT Age FROM MyTable,其中Age] 88返回89或更大的值,但也返回9,因为在排序序列中9在88之后。 SELECT Age FROM MyTable WHERE Age > 88返回89以上; 它不会返回9。 字符串操作数,如' ABC ',排序在任何包含附加字符的字符串(如' ABCA ')之前; 因此,要从[操作符或>操作符中排除操作数字符串,必须指定整个字符串。 Name ] ‘Smith,John’ 包含 ‘Smith,John’ 不包含 ‘Smith,John P.’

逻辑运算符

SQL逻辑运算符用于评估为True或False的条件表达式中。这些条件表达式在SELECT语句WHEREHAVING子句,CASE语句WHEN子句,JOIN语句ON子句和CREATE TRIGGER语句WHEN子句中使用。

非一元运算符

可以使用NOT一元逻辑运算符来指定条件的逻辑逆,如以下示例所示:

SELECT Name,Age FROM Sample.Person
WHERE NOT Age>21
ORDER BY Age
SELECT Name,Age FROM Sample.Person
WHERE NOT Name %STARTSWITH('A')
ORDER BY Name

可以将NOT运算符放在条件之前(如上所示)。或者,不能将NOT放在单字符运算符之前;例如,NOT <NOT [等。请注意,NOT和它求反的单字符运算符之间必须没有空格。

ANDOR运算符

可以在一系列两个或多个条件下,在两个操作数之间使用ANDOR逻辑运算符。这些逻辑运算符可以用关键字或符号指定:

代码描述
AND&
OR!

在符号运算符及其操作数之间不需要空格(尽管为了可读性建议使用空格)。关键字运算符前后需要空格。

这些逻辑运算符可以与NOT一元逻辑运算符一起使用,例如:WHERE Age<65 & NOT Age=21.

以下两个示例使用逻辑运算符根据年龄安排计算。每三年对20至40岁的人群进行计算,每两年对40至64岁的人群进行计算,每年对65岁及65岁以上的人群进行计算。这些示例给出了相同的结果。第一个示例使用关键字,第二个示例使用符号:

SELECT Name,Age FROM Sample.Person
WHERE Age>20
      AND Age<40 AND (Age # 3)=0 
      OR Age>=40 AND (Age # 2)=0 
      OR Age>=65
ORDER BY Age
SELECT Name,Age FROM Sample.Person
WHERE Age>20
      & Age<40 & (Age # 3)=0 
      ! Age>=40 & (Age # 2)=0 
      ! Age>=65
ORDER BY Age

可以使用括号将逻辑运算符分组。这将建立分组级别;评估从最低的分组级别到最高的分组级别进行。在下面的第一个示例中,“与”条件仅应用于第二个“或”条件。它返回来自MA的任何年龄的人,以及来自NY的小于25岁的人:

SELECT Name,Age,Home_State FROM Sample.Person
WHERE Home_State='MA' OR Home_State='NY' AND Age < 25
ORDER BY Age

使用括号对条件进行分组会得出不同的结果。以下示例返回来自MA或NY的年龄小于25的人员:

SELECT Name,Age,Home_State FROM Sample.Person
WHERE (Home_State='MA' OR Home_State='NY') AND Age < 25
ORDER BY Age
  • SQL执行使用短路逻辑。如果条件失败,将不会测试其余的AND条件。如果条件成功,则将不会测试其余的OR条件。
  • 但是,由于SQL优化了WHERE子句执行,因此无法预测并且不应该依赖多个条件(在同一分组级别)的执行顺序。

注释

InterSystems SQL支持单行注释和多行注释。注释文本可以包含任何字符或字符串,当然,指示注释结尾的字符除外。

注意:使用嵌入式SQL标记语法(&sql<marker>(...)<reversemarker>) 对SQL注释的内容强加了限制。如果使用标记语法,则SQL代码中的注释可能不包含字符序列“)<reversemarker>”。

可以使用preparse()方法返回去除注释的SQL DML语句。 preparse()方法还用替换每个查询参数。字符并返回这些参数的%List结构。以下示例中的preparse()方法返回查询的解析版本,除去单行和多行注释以及空格:

/// d ##class(PHA.TEST.SQL).Null5()
ClassMethod Null5()
{
	SET myq=4
	SET myq(1)="SELECT TOP ? Name /* first name */, Age "
	SET myq(2)="   FROM Sample.MyTable -- this is the FROM clause"
	SET myq(3)="   WHERE  /* various conditions "
	SET myq(4)="apply */ Name='Fred' AND Age > 21 -- end of query"
	DO ##class(%SQL.Statement).preparse(.myq,.stripped,.args)
	WRITE stripped,!
	WRITE $LISTTOSTRING(args)
}
DHC-APP>d ##class(PHA.TEST.SQL).Null5()
 SELECT TOP ? Name , Age FROM Sample . MyTable WHERE Name = ? AND Age > ?
?,?,c,Fred,c,21

单行注释

单行注释由两个连字符前缀指定。注释可以在单独的行上,也可以与SQL代码显示在同一行上。当注释在同一行上跟随SQL代码时,至少一个空格必须将代码与双连字符注释运算符分隔开。注释可以包含任何字符,包括连字符,星号和斜杠。注释继续到该行的末尾。

下面的示例包含多个单行注释:

-- This is a simple SQL query
-- containing -- (double hyphen) comments
SELECT TOP 10 Name,Age, -- Two columns selected
Home_State -- A third column
FROM Sample.Person -- Table name
-- Other clauses follow
WHERE Age > 20 AND -- Comment within a clause
Age < 40
ORDER BY Age,  -- Comment within a clause
Home_State
-- End of query

多行注释

多行注释由/ * 开头定界符和 * /结束定界符指定。注释可以出现在一个或多个单独的行上,或者可以与SQL代码在同一行上开始或结束。注释定界符应与SQL代码分隔至少一个空格。注释可以包含任何字符,包括连字符,星号和斜杠,但* /字符对显然是例外。

下面的示例包含多个多行注释:

/* This is 
   a simple 
   SQL query. */
SELECT TOP 10 Name,Age /* Two fields selected */
FROM Sample.Person  /* Other clauses 
could appear here */ ORDER BY Age
/* End of query */

当注释掉嵌入式SQL代码时,请始终在&sql指令之前或括号内开始注释。下面的示例正确注释掉了两个嵌入式SQL代码块:

    SET a="default name",b="default age"
    WRITE "(not) Invoking Embedded SQL",!
    /*&sql(SELECT Name INTO :a FROM Sample.Person) */
    WRITE "The name is ",a,!
    WRITE "Invoking Embedded SQL (as a no-op)",!
    &sql(/* SELECT Age INTO :b FROM Sample.Person */)
    WRITE "The age is ",b

SQL代码保留为注释

嵌入式SQL语句可以保留为例程的.INT代码版本中的注释。这是通过设置$SYSTEM.SQL.SetRetainSQL()方法完成的。若要确定当前设置,请调用$ SYSTEM.SQL.CurrentSettings(),它将显示“将SQL保留为注释”设置。默认值为1(“是”)。

将此选项设置为“是”以将SQL语句保留为例程的.INT代码版本中的注释。将此选项设置为“是”还会在注释文本中列出SQL语句使用的所有非%变量。这些列出的变量也应该在ObjectScript过程的PUBLIC变量列表中列出,并使用NEW命令重新初始化。

5
0 261
文章 姚 鑫 · 二月 28, 2021 7m read

第一章 InterSystems SQL简介

InterSystems SQL提供对InterSystems IRIS®Data Platform数据库中存储的数据的无懈可击的标准关系访问。

InterSystems SQL提供以下优势:

  • 高性能和可扩展性-InterSystems SQL提供优于其他关系数据库产品的性能和可扩展性。此外,InterSystems SQL可以在各种硬件和操作系统上运行;从笔记本电脑到高端多CPU系统。
  • 与InterSystems IRIS对象技术集成-InterSystems SQL与InterSystems IRIS Object技术紧密集成。可以混合使用关系访问和对象访问数据,而不会牺牲任何一种方法的性能。
  • 维护成本低-与其他关系数据库不同,InterSystems IRIS应用程序不需要在已部署的应用程序中重建索引和压缩表格。
  • 支持标准SQL查询-InterSystems SQL支持SQL-92标准语法和命令。在大多数情况下,可以毫不费力地将现有关系应用程序迁移到InterSystems IRIS,并自动利用InterSystems IRIS更高的性能和对象功能。

可以将InterSystems SQL用于多种目的,包括:

  • 基于对象和基于Web的应用程序-可以在InterSystems IRIS对象和Web Server Page应用程序中使用SQL查询来执行强大的数据库操作,如查找和搜索。
  • 在线事务处理-InterSystems SQL为INSERT和UPDATE操作以及事务处理应用程序中常见的查询类型提供了出色的性能。
  • 商业智能和数据仓库-InterSystems IRIS多维数据库引擎和位图索引技术的结合使其成为数据仓库式应用程序的最佳选择。
  • 即时查询和报告-可以使用InterSystems SQL附带的功能齐全的ODBC和JDBC驱动程序连接到流行的报告和查询工具。
  • 企业应用程序集成-InterSystems SQL Gateway使能够无缝地通过SQL访问ODBC或JDBC兼容的外部关系数据库中存储的数据。这使得在InterSystems IRIS应用程序中集成来自各种来源的数据变得容易。

架构

InterSystems SQL的核心由以下组件组成:

  • 统一数据字典-存储为一系列类定义的所有元信息的存储库。InterSystems IRIS自动为统一字典中存储的每个持久类创建关系访问(表)。
  • SQL处理器和优化器-一组程序,用于解析和分析SQL查询,确定给定查询的最佳搜索策略(使用复杂的基于成本的优化器),并生成执行查询的代码。
  • InterSystems SQL Server-一组InterSystems IRIS服务器进程,负责与InterSystems ODBC和JDBC驱动程序的所有通信。它还管理频繁使用的查询的高速缓存;当同一查询被多次执行时,可以从查询高速缓存中检索其执行计划,而不必由优化器再次处理。

特点

InterSystems SQL包括一整套标准的关系型功能。这些措施包括:

  • 定义表和视图(DDL或数据定义语言)的能力。
  • 对表和视图(DML或数据操作语言)执行查询的能力。
  • 能够执行事务,包括插入、更新和删除操作。执行并发操作时,InterSystems SQL使用行级锁。
  • 为更高效的查询定义和使用索引的能力。
  • 能够使用各种数据类型,包括用户定义的类型。
  • 定义用户和角色并为其分配权限的能力。
  • 定义外键和其他完整性约束的能力。
  • 定义INSERT、UPDATE和DELETE触发器的能力。
  • 定义和执行存储过程的能力。
  • 能够以不同的格式返回数据:用于客户端访问的ODBC模式;用于在基于服务器的应用程序中使用的显示模式。

符合SQL-92

SQL-92标准在算术运算符优先级方面是不精确的;关于这一问题的假设因SQL实现而异。InterSystems SQL支持将系统配置为以下任一系统范围的SQL算术运算符优先级替代方案:

  • InterSystems SQL可以配置为严格按照从左到右的顺序解析算术表达式,没有运算符优先级。这与ObjectScript中使用的约定相同。因此,3+35=30。可以使用括号来强制执行所需的优先顺序。因此,3+(35)=18。
  • InterSystems SQL可以配置为使用ANSI优先级分析算术表达式,这为乘法和除法运算符提供了比加法、减法和串联运算符更高的优先级。因此,3+3*5=18。如果需要,可以使用括号覆盖此优先级。因此,(3+3)*5=30。

SQL运算符优先级的默认值取决于InterSystems IRIS版本。

InterSystems SQL支持完整的入门级SQL-92标准,但有以下例外:

  • 不支持向表定义添加附加的CHECK约束。
  • 不支持SERIALIZABLE(序列化)隔离级别。
  • 分隔标识符不区分大小写;标准规定它们应该区分大小写。
  • 在HAVING子句中包含的子查询中,应该能够引用该HAVING子句中“可用”的聚合。这不受支持。

拓展

  • InterSystems SQL支持许多有用的扩展。其中许多都与InterSystems IRIS提供对数据的同步对象和关系访问这一事实有关。

其中一些扩展包括:

  • 支持用户可定义的数据类型和函数。
  • 以下对象引用的特殊语法。
  • 支持子类化和继承。
  • 支持对存储在其他数据库中的外部表进行查询。
  • 用于控制表的存储结构以实现最高性能的多种机制。

互操作性

  • InterSystems SQL支持多种与其他应用程序和软件工具互操作的方法。

JDBC

InterSystems IRIS包括一个符合标准的第4级JDBC客户机(全部是纯Java代码)。

InterSystems JDBC驱动程序提供以下特性:

  • 高性能
  • 纯JAVA代码实现
  • UNICODE支持
  • 线程安全

可以将InterSystems JDBC与任何支持JDBC的工具、应用程序或开发环境一起使用。

ODBC

InterSystems SQL的c语言调用级接口是ODBC。与其他数据库产品不同,InterSystems ODBC驱动程序是一个本机驱动程序——它不是构建在任何其他专有接口之上的。

InterSystems ODBC驱动程序提供以下功能:

  • 高性能
  • 可移植性
  • 原生Unicode支持
  • 线程安全

可以将InterSystems ODBC与支持ODBC的任何工具,应用程序或开发环境一起使用。

嵌入式SQL

在ObjectScript中,InterSystems SQL支持嵌入式SQL: 将SQL语句放置在方法(或其他代码)主体中的能力。使用嵌入式SQL,可以查询单个记录,或定义一个游标,然后使用该游标查询多个记录。嵌入式SQL已编译。默认情况下,它是在第一次执行(运行时)时进行编译的,而不是在包含它的例程进行编译时进行的。因此,在运行时检查SQLCODE错误很重要。 还可以与包含嵌入式SQL的ObjectScript例程同时编译嵌入式SQL。

与InterSystems IRIS的对象访问功能结合使用时,嵌入式SQL的功能非常强大。例如,以下方法查找具有给定Name值的记录的RowID:

/// w ##class(PHA.TEST.SQL).FindByName("姚鑫")
ClassMethod FindByName(fullname As %String)
{
	&sql(SELECT %ID INTO :id FROM Sample.Person WHERE Name = :fullname)

	IF SQLCODE < 0 {
		SET baderr="SQLCODE ERROR:"_SQLCODE_" "_%msg
		RETURN baderr 
	} ELSEIF SQLCODE = 100 {
		SET nodata="Query returns no data"
		RETURN nodata 
	}
	RETURN "RowID="_id
}
DHC-APP>w ##class(PHA.TEST.SQL).FindByName("姚鑫")
RowID=6

注意: 如果 Name 查处多条的话 id为查询的第一条数据

指定倒序,为最后一条。

&sql(SELECT %ID INTO :id FROM Sample.Person WHERE Name = :fullname order by ID desc)
DHC-APP>w ##class(PHA.TEST.SQL).FindByName("姚鑫")
RowID=14

image

动态SQL

作为其标准库的一部分,InterSystems IRIS提供了一个%SQL.Statement类,可以使用它来执行动态(即在运行时定义的)SQL语句。可以在ObjectScript方法中使用动态SQL。例如,下面的方法查询指定数量的21世纪出生的人。该查询选择1999年12月31日之后出生的所有人,按出生日期对所选记录进行排序,然后选择前x条记录:

/// w ##class(PHA.TEST.SQL).Born21stC("姚鑫")
ClassMethod Born21stC(x)
{
/// w ##class(PHA.TEST.SQL).Born21stC("1")
ClassMethod Born21stC(x)
{
  SET myquery=2
  SET myquery(1) = "SELECT TOP ? Name,%EXTERNAL(DOB) FROM Sample.Person "
  SET myquery(2) = "WHERE DOB > 58073 ORDER BY DOB"
  SET tStatement = ##class(%SQL.Statement).%New()
  SET qStatus = tStatement.%Prepare(.myquery)
  IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
  SET rset = tStatement.%Execute(x)
  DO rset.%Display()
  WRITE !,"End of data"
  q ""
}

DHC-APP>w ##class(PHA.TEST.SQL).Born21stC("2")
Name    Expression_2
Ingrahm,Susan N.        02/10/2001
Goldman,Will H. 09/22/2002
 
2 Rows(s) Affected
End of data

准备查询时,该查询的优化版本将存储为缓存查询。该缓存查询被执行用于查询的后续调用,从而避免了每次执行查询时重新优化查询的开销。

限制

请注意InterSystems SQL的以下限制:

NLS可用于为单个全局变量以及当前运行的进程中的局部变量指定特定国家区域设置行为的$ORDER行为。InterSystems SQL可以在任何国家语言环境中使用和良好地工作。然而,InterSystems SQL当前的一个限制是,对于任何特定进程,它引用的所有相关全局变量都必须使用与当前进程区域设置相同的国家区域设置。

2
0 375
文章 姚 鑫 · 二月 27, 2021 4m read

第四十九章 Caché 变量大全 ^$ROUTINE 变量

提供例程信息。

大纲

^$|nspace|ROUTINE(routine_name)
^$|nspace|R(routine_name)

参数

  • |nspace|[nspace] 可选-扩展SSVN引用,可以是显式名称空间名称,也可以是隐含名称空间。必须计算为带引号的字符串,该字符串括在方括号([“nspace”])或竖线(|“nspace”|)中。命名空间名称不区分大小写;它们以大写字母存储和显示。
  • routine_name 计算结果为包含例程名称的字符串的表达式。

描述

可以将^$ROUTINE结构化系统变量用作$DATA$ORDER$QUERY函数的参数,以从当前命名空间(默认)或指定命名空间返回例程信息。^$ROUTINE返回有关例程的OBJ代码版本的例程信息。

在InterSystems ObjectScript中,一个例程有三个代码版本:MAC(用户编写的代码,可能包括宏预处理器语句)、INT(编译的MAC代码,用于执行宏预处理)和OBJ(可执行目标代码)。可以使用^$ROUTINE global返回关于int代码版本的信息。可以使用^$ROUTINE返回有关OBJ代码版本的信息。

参数

nspace

此可选参数允许使用扩展SSVN引用在另一个命名空间中指定全局。可以显式地将命名空间名称指定为带引号的字符串文字或变量,也可以通过指定隐含的命名空间来指定。命名空间名称不区分大小写。可以使用方括号语法[“user”]或环境语法|“user”|。Nspace分隔符前后不允许有空格。

   WRITE ##class(%SYS.Namespace).Exists("USER"),!  ; an existing namespace
   WRITE ##class(%SYS.Namespace).Exists("LOSER")   ; a non-existent namespace

可以使用$NAMESPACE特殊变量来确定当前名称空间。更改当前名称空间的首选方式是新建$NAMESPACE,然后设置$NAMESPACE=“nspace ename”

routine_name

计算结果为包含现有例程名称的字符串的表达式。例程名称在前255个字符内必须是唯一的;应避免超过220个字符。

示例

以下示例使用^$例程作为$DATA$ORDER$QUERY函数的参数。

作为$DATA的参数

$DATA(^$|nspace|ROUTINE(routine_name))

^$ROUTINE作为$DATA的参数将返回一个整数值,该整数值指定例程名OBJ代码版本是否作为^$ROUTINE中的节点存在。下表显示了$DATA可以返回的整数值。

ValueMeaning
0例程不存在
10例程存在

下面的Terminal示例测试myrou例程的OBJ代码版本是否存在。此示例假定在USER名称空间中有一个名为myrou的已编译MAC例程:

USER>WRITE ^ROUTINE("myrou",0,"GENERATED")  // INT code version exists
1
USER>WRITE $DATA(^$ROUTINE("myrou"))        // OBJ code version exists
1
USER>KILL ^rOBJ("myrou")                    // Kills the OBJ code version

USER>DO ^myrou

DO ^myrou
^
<NOROUTINE> *myrou
USER>WRITE ^ROUTINE("myrou",0,"GENERATED")  // INT code version exists
1
USER>WRITE $DATA(^$ROUTINE("myrou"))        // OBJ code version does not exist
0
USER>

作为$ORDER的参数

$ORDER(^$|nspace|ROUTINE( routine_name),direction)

^$ROUTINE作为$ORDER的参数,按整理顺序返回指定的例程名称的下一个或上一个例程名称。如果在^$ROUTINE中没有这样的例程名称作为节点存在,则$ORDER返回空字符串。

direction参数指定是否返回下一个或上一个例程名称:1 =下一个,-1 =上一个。如果不提供方向参数,则InterSystems IRIS将按整理顺序将下一个例程名称返回到指定的名称。

以下子例程搜索USER名称空间,并将例程名称存储在名为ROUTINE的本地数组中。

/// d ##class(PHA.TEST.SpecialVariables).ROUTINE()
ClassMethod ROUTINE()
{
  SET rname=""
  FOR I=1:1 { 
      SET rname=$ORDER(^$|"USER"|ROUTINE(rname)) 
      QUIT:rname=""
      SET ROUTINE(I)=rname
      WRITE !,"Routine name: ",rname
  }
  WRITE !,"All routines stored"
  QUIT
}
Routine name: INFORMATION.SCHEMA.TABLECONSTRAINTS.1
Routine name: INFORMATION.SCHEMA.TABLES.0
Routine name: INFORMATION.SCHEMA.TABLES.1
Routine name: INFORMATION.SCHEMA.TRIGGERS.0
Routine name: INFORMATION.SCHEMA.TRIGGERS.1
Routine name: INFORMATION.SCHEMA.VIEWCOLUMNUSAGE.0
Routine name: INFORMATION.SCHEMA.VIEWCOLUMNUSAGE.1
Routine name: INFORMATION.SCHEMA.VIEWS.0
Routine name: INFORMATION.SCHEMA.VIEWS.1
Routine name: INFORMATION.SCHEMA.VIEWTABLEUSAGE.0
Routine name: INFORMATION.SCHEMA.VIEWTABLEUSAGE.1
All routines stored

作为$QUERY的参数

$QUERY(^$|nspace|ROUTINE(routine_name))

^$ROUTINE作为$QUERY的参数,按整理顺序将下一个例程名称返回到指定的例程名称。指定的例程名称不必存在。如果以后在排序序列中没有例程名称,则$QUERY(^$ROUTINE)返回一个空字符串。

在下面的示例中,两个$QUERY函数在USER名称空间中指定例程名称之后返回下一个例程。

/// d ##class(PHA.TEST.SpecialVariables).ROUTINE1()
ClassMethod ROUTINE1()
{
	SET rname=""
	WRITE !,"1st routine: ",$QUERY(^$|"USER"|ROUTINE(rname))
	SET rname="%m"
	WRITE !,"1st ",rname, " routine: ",$QUERY(^$|"USER"|ROUTINE(rname))
	QUIT
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ROUTINE1()
 
1st routine: ^$|"USER"|ROUTINE("%APILIB")
1st %m routine: ^$|"USER"|ROUTINE("%mgw1")
2
0 133
文章 姚 鑫 · 三月 5, 2021 9m read

第四章 标识符

标识符

标识符是SQL实体的名称,例如表、视图、列(字段)、模式、表别名、列别名、索引、存储过程、触发器或其他SQL实体。 标识符名称在其上下文中必须是唯一的; 例如,同一模式中的两个表或同一表中的两个字段不能具有相同的名称。 但是,不同模式中的两个表或不同表中的两个字段可以具有相同的名称。 在大多数情况下,相同的标识符名称可以用于不同类型的SQL实体; 例如,一个模式、该模式中的表以及该表中的字段都可以具有相同的名称,而不会产生冲突。 但是,同一个模式中的表和视图不能具有相同的名称。

InterSystems IRIS®数据平台SQL标识符遵循一组命名约定,根据标识符的使用,这可能会受到进一步的限制。 标识符不区分大小写。

标识符可以是简单标识符,也可以是分隔符。 InterSystems SQL默认支持简单标识符和分隔标识符。

简单标识符

简单标识符有以下语法:

simple-identifier ::= identifier-start { identifier-part }
      identifier-start ::= letter | % | _ 
      identifier-part ::=  letter | number | _ | @ | # | $

命名约定

标识符start是SQL标识符的第一个字符。 它必须是下列之一:

  • 大写或小写字母。 字母定义为通过ObjectScript $ZNAME函数验证的任何字符; 默认情况下,这些字母是大写字母A到Z (ASCII 65-90),小写字母a到z (ASCII 97-122),以及带有重音标记的字母(ASCII 192-255,不包括ASCII 215和247)。 InterSystems IRIS可以在SQL标识符中使用任何有效的Unicode(16位)字母字符。 简单的标识符是不区分大小写的(不过,请参见下面的内容)。 按照惯例,它们用首字母大写来表示。

日语区域设置不支持标识符中的重音拉丁字母字符。 日语标识符可能包含(除了日语字符之外)拉丁字母字符A-Z和a-z(65-90和97-122),以及希腊大写字母字符(913-929和931-937)。

  • 一个下划线(_)。
  • 百分号(%)。InterSystems IRIS以%字符开头的名称(以%Z%z开头的除外)保留为系统元素,不应用作标识符。

标识符部分是SQL标识符的任何后续字符。这些剩余字符可能由零个或多个字符组成:

  • 字母(包括Unicode字符)。
  • 数字。数字被定义为数字0到9。
  • 下划线(_)。
  • At标志(@)。
  • 井号(#)。
  • 美元符号($)。

一些符号字符也用作运算符。在SQL中,#符号用作模运算符。在SQL中,下划线字符可以用来连接两个字符串;提供这种用法是为了与ObjectScript兼容,首选的SQL串联运算符是|| 将符号解释为标识符字符总是优先于将其解释为运算符。任何关于符号字符作为运算符的正确解析的歧义都可以通过在运算符前后添加空格来解决。

简单标识符不能包含空格或非字母数字字符(上面指定的符号字符除外)。系统间SQL导入工具从导入的表名中删除空格。

注意:SQL游标名称不遵循标识符命名约定。

InterSystems SQL包含不能用作简单标识符的保留字。 有关这些保留词的列表, 要测试一个单词是否是保留单词,请使用$SYSTEM.SQL.IsReservedWord()方法。 但是,带分隔符的标识符可以与SQL保留字相同。

任何不遵循这些命名约定的标识符都必须在SQL语句中表示为带分隔符的标识符。

字母

默认情况下,InterSystems SQL标识符不区分大小写。 InterSystems SQL通过将标识符转换为所有大写字母后比较它们来实现这一点。 这对名称的实际使用情况没有影响。 (注意,SQL的其他实现可能会以不同的方式处理标识符的大小写敏感性。 因此,建议避免使用基于案例的标识符。)

请注意,系统间SQL中的游标名称和密码是区分大小写的。

测试有效标识符

InterSystems IRIS提供了%SYSTEM.SQLIsValidRegularIdentifier()方法。它测试字符串是否是有效的标识符。它测试字符用法和保留字。它还执行200个字符的最大长度测试(这是用于避免错误输入的任意长度;这不是标识符验证)。以下对象脚本示例显示了此方法的使用:

/// d ##class(PHA.TEST.SQL).Identifiers()
ClassMethod Identifiers()
{
	WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("Fred")
	WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("%Fred#123")
	WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("%#$@_Fred")
	WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("_1Fred")
	WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("%#$")

	WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("1Fred")
	WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("Fr ed")
	WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("%sqlupper")
}
DHC-APP>d ##class(PHA.TEST.SQL).Identifiers()
 
1
1
1
1
1
0
0
0

前三个方法调用返回1,表示有效的标识符。第四个和第五个方法调用也返回1;这些是有效的标识符,尽管它们不能用作表名或字段名。最后三个方法调用返回0,表示标识符无效。其中两个是无效的,因为它们违反了字符规则——在这些情况下是以数字开头或包含空格。最后一次方法调用返回0,因为指定的字符串是保留字。请注意,这些规则测试是最低要求;它们不能证明标识符对所有的SQL使用都有效。

这个方法也可以作为存储过程从ODBC或JDBC调用:%SYSTEM.SQL_IsValidRegularIdentifier("nnnn")

名称空间的名字

命名空间名称(也称为数据库名称)遵循标识符命名约定,并对标点字符和最大长度有额外的限制。

命名空间名称可以作为带分隔符的标识符,并且可以与SQL保留字相同。 但是,相同的命名空间名称标点限制适用于简单标识符和分隔标识符。

标识符和类实体名称

通过去除非字母数字字符,SQL表名、视图名、字段名、索引名、触发器名和过程名用于生成相应的持久类实体。 生成的类实体和全局变量的名称遵循这些规则。

注意:命名空间名称和SQL模式名称以及相应的包名称不遵循这些规则。

  • 仅在包含标点字符方面不同的标识符是有效的。 因为类对象名称不能包含标点字符,InterSystems IRIS通过去掉所有标点字符来生成相应的唯一对象名称。 如果去掉标识符的标点字符会导致非唯一的类对象名称,InterSystems IRIS将最后一个字母数字字符替换为一个递增的字符后缀,从而创建一个唯一的名称。

对于表、视图、字段、触发器和过程类方法名,这是一个以0开头的整数后缀。 例如,mynamemy_name生成mynamemynam0,添加我的#name生成mynam1。 如果生成的惟一名称的数量大于10 (mynam9),则通过替换以(mynamA)开头的大写字母后缀生成额外的名称。 因为表和视图共享相同的名称空间,所以表或视图的后缀计数器都是递增的。

对于索引名,这个后缀是一个大写字母,以a开头。例如,myindexmy_index生成myindexmyindeA

如果定义了一个以后缀字符结束的名称(例如my_name0my_index), InterSystems IRIS将通过递增到下一个未使用的后缀来处理惟一名称的生成。

  • 第一个字符为标点字符,第二个字符为数字的标识符对于表名、视图名或过程名无效。 它们对字段名和索引名有效。 如果SQL字段名或索引名的第一个字符是标点字符(%_),第二个字符是数字,InterSystems IRIS将追加小写的“n”作为相应属性名的第一个字符。
  • 完全由标点字符组成的标识符,或以两个下划线字符(__name)开头的标识符,或包含两个井号(nn##nn)的标识符作为SQL实体名称通常是无效的,应该在所有上下文中避免使用。

可以将SQL标识符中的特定字符转换为相应对象标识符中的其他字符。 在允许的标识符字符规则不同的环境中,这有助于标识符的使用。 使用 %SYSTEM.SQLSetDDLIdentifierTranslations()方法。 要确定当前设置,调用$SYSTEM.SQL.CurrentSettings()

在DDL运行时将SQL标识符转换为对象标识符时,“From”字符串中的字符被转换为“to”字符串中的字符。

在类定义中指定SQL名称

定义投射SQL实体的持久化类时,每个SQL实体的名称与其对应的持久化类定义元素的名称相同。 要使SQL表、字段或索引名称不同,可以使用SqlTableNameSqlFieldNameSqlName(对于索引)关键字在类定义中指定SQL名称。 例如:

Property LName As %String [SqlFieldName = "Family#Name"];
Index NameIdx As %String [SqlName = "FullNameIndex"];

标识符长度注意事项

SQL标识符的最大长度为128个字符。当InterSystems IRIS将SQL标识符映射到相应的对象实体时,它会创建最多96个字符的相应属性、方法、查询或索引名称。如果前96个字符的两个SQL标识符相同,InterSystems IRIS会将相应对象名称的第96个字符替换为整数(从0开始)以创建唯一名称。

分隔标识符

分隔标识符的语法如下:

delimited-identifier ::= " delimited-identifier-part { delimited-identifier-part } "
    delimited-identifier-part ::= non-double-quote-character | double-quote-symbol
    double-quote-symbol ::= ""

带分隔符的标识符是由分隔符字符括起来的唯一标识符。InterSystems SQL支持双引号()作为分隔符,分隔符一般用于避免简单标识符的命名限制。

请注意,InterSystems SQL使用单引号字符()来分隔文字。因此,必须使用双引号字符()指定分隔标识符,必须使用单引号字符()指定文字。例如,’7‘是数字文字7,但”7“是分隔标识符。当SQL语句用双引号括起来时(例如,在动态SQL中),该字符串中的双引号字符必须是双引号。

SQL空字符串应始终指定为一对单引号字符‘’。启用分隔标识符支持时,一对双引号字符“”将被解析为无效的分隔标识符,并生成SQLCODE-1错误。

分隔标识符有效名称

分隔的标识符必须是唯一的名称。带分隔符的标识符不区分大小写;按照惯例,标识符用首字母大写表示。

分隔标识符可以与SQL保留字相同。分隔标识符通常用于避免与SQL保留字的命名冲突。

分隔标识符几乎可以包含任何可打印字符,包括空格。大多数分隔的标识符名称不能包含以下字符:逗号()、句点(.)、插入符号(^)和两个字符的箭头序列(->);但是分隔的标识符角色名称和用户名可以包含这些字符。分隔的标识符类名可以包含句点(.)。任何分隔的标识符都不能以星号(*)开头。以下术语不能用作分隔标识符:%vid。违反这些命名约定会导致SQLCODE-1错误。

用作表、架构、列或索引名的分隔标识符必须能够转换为有效的类实体名称。因此,它必须至少包含一个字母数字字符。以数字(或标点符号后跟数字)开头的分隔标识符会生成带有字母“n”前缀的相应类实体名称。

以下示例显示了对列名和表名使用分隔标识符的查询:

SELECT "My Field" FROM "My Table" WHERE "My Field" LIKE 'A%'

为表名指定分隔标识符时,必须分别分隔表名和架构名。因此,“schema”“tablename”schema“tablename”是有效的标识符,但是“schema.tablename”不是有效的标识符。

禁用分隔标识符支持

默认情况下,启用对定界标识符的支持。

禁用分隔标识符支持时,双引号内的字符将被视为字符串文字。

可以使用带有SUPPORT_DELIMITED_IDENTIFIERS关键字的SET OPTION命令在系统范围内设置分隔标识符支持。

可以使用%SYSTEM.SQL类的SetDelimitedIdentifiers()方法在系统范围内设置分隔标识符支持。

若要确定当前设置,请调用$SYSTEM.SQL.CurrentSettings()

SQL保留字

SQL包含一长串不能用作标识符的保留字。

1
0 301
文章 姚 鑫 · 三月 1, 2021 7m read

第二章 InterSystems SQL基础

本章概述了InterSystems SQL的特性,特别是那些SQL标准未涵盖的特性,或者与InterSystems IRIS®数据平台统一数据架构相关的特性。 本教程假定读者具备SQL知识,并不是为介绍SQL概念或语法而设计的。

本章讨论以下主题:

  • 查询
  • 权限
  • 数据显示选项
  • 数据排序类型
  • 执行SQL

在InterSystems SQL中,数据显示在表中。每个表都包含许多列。一个表可以包含零个或多个数据值行。以下术语大体上等效:

数据术语关系数据库术语InterSystems IRIS术语
数据库架构
数据库persistent class(持久类)
字段属性
记录

表有两种基本类型:基表(包含数据,通常简称为表)和视图(基于一个或多个表提供逻辑视图)。

模式与架构

SQL模式提供了一种将相关表,视图,存储过程和缓存查询的集合进行分组的方法。模式的使用有助于防止表级别的命名冲突,因为表,视图或存储过程的名称在其模式内必须唯一。应用程序可以在多个架构中指定表。

SQL模式与持久性类包相对应。通常,模式与其相应的程序包具有相同的名称,但是由于不同的模式命名约定或故意指定了不同的名称,因此这些名称可能有所不同。模式到程序包的映射在SQL到类名的转换中有进一步描述。

模式是在特定的名称空间中定义的。模式名称在其名称空间内必须是唯一的。将第一个项目分配给它时,会自动创建一个模式(及其对应的程序包),从中删除最后一个项目时,会自动将其删除。

可以指定一个限定或不限定的SQL名称,限定名称指定模式:schema.name。 非限定名不指定模式名。 如果不指定模式,InterSystems IRIS将提供如下模式:

  • 对于DDL操作,InterSystems IRIS使用系统范围的默认架构名称。此默认值可配置。它适用于所有名称空间。
  • 对于DML操作,InterSystems IRIS可以使用用户提供的模式搜索路径或系统范围内的默认模式名称。在动态SQL,嵌入式SQL和SQL Shell中,使用了不同的技术来提供模式搜索路径。

DML(data manipulation language): 它们是SELECT、UPDATE、INSERT、DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 DDL(data definition language): DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的链接和约束等初始化工作上,他们大多在建立表时使用 DCL(Data Control Language): 是数据库控制功能。是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)语句。在默认状态下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人员才有权力执行DCL

要查看名称空间内的所有现有模式,请执行以下操作:

  1. 在管理门户中,选择“系统资源管理器”,然后选择“ SQL”。使用页面顶部的Switch选项选择一个名称空间;这将显示可用名称空间的列表。选择一个名称空间。

image

image

  1. 选择屏幕左侧的Schema下拉列表。这将显示当前名称空间中的架构列表。从该列表中选择一个模式;所选名称将出现在“模式”框中。

image

  1. 如果有数据下拉列表允许选择表,视图,过程或缓存的查询,或所有属于模式的所有这些。设置此选项后,单击三角形以查看项目列表。如果没有项目,则单击三角形无效。

image

查询

在InterSystems SQL中,可以通过查询查看和修改表中的数据。粗略地说,查询有两种形式:查询数据(SELECT语句)和修改数据(INSERT,UPDATE和DELETE语句)。

可以通过多种方式使用SQL查询:

  • 在ObjectScript中使用嵌入式SQL。
  • 在ObjectScript中使用动态SQL。
  • 调用使用CREATE PROCEDURE或CREATE QUERY创建的存储过程。
  • 使用类查询。
  • 使用来自各种其他环境的ODBC或JDBC接口。

权限

InterSystems SQL提供了一种通过权限来限制对表、视图等的访问的方法。

数据显示选项

InterSystems SQL使用SelectMode选项来指定如何显示或存储数据。 可用的选项有Logical、Display和ODBC。 数据在内部以逻辑模式存储,并且可以在这些模式中的任何一种中显示。 通过使用LogicalToDisplay()LogicalToODBC()DisplayToLogical()odbcological()方法,每个数据类型类都可以在内部逻辑格式和显示格式或ODBC格式之间进行转换。 当显示SQL SelectMode时,将应用LogicalToDisplay转换,并对返回值进行格式化以便显示。 默认的SQL SelectMode是逻辑的; 因此,默认情况下返回值以存储格式显示。

SelectMode影响查询结果集数据显示的格式,SelectMode还影响应该提供数据值的格式,例如在WHERE子句中。 InterSystems IRIS根据存储模式和指定的SelectMode选择合适的转换方法。 所提供的数据值与SelectMode之间的不匹配可能导致错误或错误的结果。 例如,如果DOB是一个以$HOROLOG逻辑格式存储的日期,并且WHERE子句指定DOB > 2000-01-01 (ODBC格式),则SelectMode = ODBC返回预期的结果。 SelectMode = Display生成SQLCODE -146,无法将日期输入转换为有效的逻辑日期值。 SelectMode =Logic2000-01-01解析为逻辑日期值,并返回零行。

对于大多数数据类型,三种SelectMode模式返回相同的结果。 以下数据类型受SelectMode选项影响:

  • 日期,时间和时间戳数据类型。 InterSystems SQL支持多种日期,时间和时间戳数据类型(%Library.Date%Library.Time%Library.PosixTime%Library.TimeStamp%MV.Date)。除%Library.TimeStamp外,这些数据类型对逻辑,显示和ODBC模式使用不同的表示形式。在其中的几种数据类型中,InterSystems IRIS以$HOROLOG格式存储日期。此逻辑模式内部表示包括从任意起始日期(1840年12月31日)起的天数的整数,逗号分隔符以及从当天午夜开始的秒数的整数。 InterSystems IRIS将%PosixTime时间戳存储为编码的64位带符号整数。在“显示”模式下,日期和时间通常以数据类型的FORMAT参数指定的格式显示,或者当前语言环境的日期和时间格式默认为%SYS.NLS.Format。美国语言环境的默认值为DD / MM / YYYY hh:mm:ss。在ODBC模式下,日期和时间始终表示为YYYY-MM-DD hh:mm:ss.fff%Library.TimeStamp数据类型还将这种ODBC格式用于逻辑和显示模式。
  • %LIST数据类型。InterSystems IRIS逻辑模式使用两个非打印字符存储列表,这两个字符出现在列表中的第一个项目之前,并显示为列表项目之间的分隔符。在ODBC SelectMode中,列表项显示时列表项之间带有逗号分隔符。在Display SelectMode中,列表项显示时,列表项之间有空格分隔符。
  • 指定VALUELISTDISPLAYLIST的数据类型。如果处于显示模式,并且在字段具有DISPLAYLIST的表中插入一个值,则输入的显示值必须与DISPLAYLIST中的一项完全匹配。
  • 空字符串和空BLOB(流字段)。在逻辑模式下,空字符串和BLOB由非显示字符$CHAR(0)表示。在显示模式下,它们由空字符串(“”)表示。

SQL SelectMode可以指定如下:

  • 对于当前进程,请使用$SYSTEM.SQL.SetSelectMode()
  • 对于InterSystems SQL Shell会话,请使用SET SELECTMODE命令。
  • 使用“显示模式”下拉列表,从管理门户“执行查询”用户界面(系统资源管理器,SQL)获得查询结果集。
  • 对于动态SQL %SQL.Statement实例,请使用%SelectMode属性。
  • 对于嵌入式SQL,请使用ObjectScript #SQLCompile Select预处理器指令设置。该伪指令允许使用第四个值Runtime,它将选择模式设置为RuntimeMode属性设置为:逻辑,显示或ODBC。 RuntimeMode的默认值为Logical。
  • 对于使用SELECTMODE关键字的SQL命令CREATE QUERY,CREATE METHOD,CREATE PROCEDURE和CREATE FUNCTION。
  • 通过使用%EXTERNAL%INTERNAL%ODBCOUT函数在SQL查询中的单个列。

数据排序

Collation种类决定了值的排序和比较方式,它是InterSystems SQL和InterSystems IRIS对象的一部分。

可以指定排序规则类型作为字段/属性保护的一部分。除非另有说明,否则字符串字段/属性默认为命名空间默认排序规则。默认情况下,字符串的命名空间默认排序规则是SQLUPPER。 SQLUPPER排序规则将字符串转换为大写,以便排序和比较。因此,除非另有说明,字符串排序和比较不区分大小写。

可以指定排序规则类型作为索引保护的一部分,或者使用索引字段的排序规则类型。

通过将排序函数应用于字段名,SQL查询可以覆盖未保护的字段/属性排序规则类型。ORDER BY子句指定查询的结果集序列;如果指定的字符串字段被保护为SQLUPPER,查询结果顺序不区分大小写。

执行SQL

InterSystems IRIS支持多种方法来编写和执行SQL代码。其中包括:

  • 嵌入式SQL:嵌入在ObjectScript代码中的SQL代码。
  • 动态SQL:使用%SQL.Statement类从ObjectScript中执行的SQL代码。
  • Execute()方法:使用%SYSTEM.SQL类的Execute()方法执行SQL代码。
  • 包含SQL代码的存储过程,使用CREATE PROCEDURE或CREATE Query创建。
  • SQL Shell:从终端界面执行的SQL语句。
  • 执行查询界面:从管理门户执行的SQL语句。

可以使用InterSystems IRIS对象(类和方法)执行以下操作:

  • 持久性类(SQL表)。
  • 定义索引。
  • 定义并使用类查询。
2
0 226
文章 姚 鑫 · 三月 4, 2021 9m read

第三章 SQL语言元素(一)

命令和关键字

InterSystems SQL命令(也称为SQL语句)以关键字开头,后跟一个或多个参数。其中一些参数可能是子句或函数,由它们自己的关键字标识。

  • InterSystems SQL命令没有命令终止符,除非在特殊情况下(例如SQL过程代码或触发代码),在这种情况下,SQL命令以单个分号(;)终止。否则,InterSystems SQL命令不需要或接受分号命令终止符。在InterSystems SQL中指定分号命令终止符会导致SQLCODE -25错误。 TSQL的InterSystemsIRIS®数据平台实现(Transact-SQL)接受但不需要分号命令终止符。在将SQL代码导入Inter Systems SQL时,会去除分号命令终止符。
  • InterSystems SQL命令没有空格限制。如果命令项之间用空格隔开,则至少需要一个空格。 如果命令项之间用逗号分隔,则不需要空格。算术运算符之前或之后不需要空格。可以在以空格分隔的项目之间,以逗号分隔的参数列表中的项目之间或在算术运算符之前或之后插入换行符或多个空格。

InterSystems SQL关键字包括命令名称,函数名称,谓词条件名称,数据类型名称,字段约束,优化选项和特殊变量。它们还包括ANDORNOT逻辑运算符,NULL列值指示符以及ODBC函数构造,例如{d dateval}{fn CONCAT(str1,str2)}

  • 关键字不区分大小写。按照惯例,在本文档中,关键字用大写字母表示,但是InterSystems SQL没有大小写限制。
  • 有许多关键字是SQL保留字。 InterSystems SQL仅保留那些不能明确解析的关键字。 SQL保留字可用作分隔符。

函数:内在的和外在的

  • 内在的:InterSystems SQL支持大量内在的(系统提供的)函数。 这些函数包括数字函数、字符串函数以及日期和时间函数。

聚合函数是SQL固有函数,它计算列的所有值并返回单个聚合值。

  • InterSystems SQL也可以支持用户提供的ObjectScript函数调用(外部函数),如下所示:

这种写法只能在mac routine里,类文件里编译报错。

MySQL
	 &sql(SELECT Name,$$MyFunc() INTO :n,:f FROM Sample.Person)
	 WRITE "name is: ",n,!
	 WRITE "function value is: ",f,!
	 QUIT
MyFunc()
	SET x="my text"
	QUIT x

如果将用户提供的(外部)函数的使用配置为系统范围的选项,则该SQL语句只能调用用户提供的(外部)函数。默认为“否”。默认情况下,尝试调用用户提供的函数会发出SQLCODE -372错误。可以使用%SYSTEM.SQL类的SetAllowExtrinsicFunctions()方法在系统范围内配置SQL对外部函数的使用。若要确定当前设置,请调用$SYSTEM.SQL.CurrentSettings(),该显示显示“允许在SQL语句中使用外部函数”选项。

不能使用用户提供的函数来调用%routine(名称以%字符开头的例程)。 尝试这样做会发出SQLCODE -373错误。

文字

InterSystems SQL文字具有以下语法:

literal ::= 
number | string-literal
number ::= 
 {digit}[.]digit{digit}[E[+|-]digit{digit}] 
digit ::=
 0..9
string-literal ::= 
std-string-literal | ObjectScript-empty-string
std-string-literal ::= 
 ' {std-character-representation} '
std-character-representation ::=
nonquote-character | quote-symbol
quote-symbol ::= 
 ''
ObjectScript-empty-string ::= 
 ""

文字是一系列代表实际(文字)值的字符。它可以是数字或字符串。

  • 数字不需要任何分隔符。它可以由数字0到9,小数点字符,指数符号以及加号和减号组成。数字中只能使用一个小数点字符。该小数点只能用于数字的基数部分,不能用于指数部分。小数点后不需要数字。允许前导零和尾随零。指数(科学符号)符号为字母E;大写字母E和小写字母E都可以接受,但是大写字母E是首选用法。加号或减号可以加一个底数或一个指数。多个加号和减号可以加上x个基数; SQL将这些符号视为运算符。 x只能有一个正负号。 SQL将此符号视为文字的一部分。请勿在数字中使用逗号或空格。
  • 字符串文字包含一对分隔符,其中包含任何类型的字符串。首选的定界符是单引号字符。要将分隔符指定为字符串中的文字,请将该字符加倍;例如: 'Mary's office'.

空字符串是文字字符串;它由两个单引号字符('')表示。 NULL不是文字值;它表示没有任何值。

注意:在嵌入式SQL中,不允许在字符串文字中使用以##开头的一些字符序列,如“使用嵌入式SQL”一章的“文字值”中所述。此限制不适用于其他SQL调用,例如动态SQL。

字符串分割符

使用单引号(')字符作为字符串定界符。 SQL兼容性支持双引号字符()的使用,但由于与定界标识符标准冲突,因此强烈建议不要使用。将一对双引号字符""解析为无效的定界标识符。并生成SQLCODE -1错误。

要在字符串中指定单引号字符作为字面字符,请指定一对这样的字符作为字面转义序列。 例如,'a 'normal' string'

串联

双竖条(||)是首选的SQL连接操作符。 它可以用于连接两个数字、两个字符串或一个数字和一个字符串。

下划线(_)作为SQL连接操作符提供,以保证ObjectScript的兼容性。 此连接操作符只能用于连接两个字符串。

如果两个操作数都是字符串,并且两个字符串都具有相同的排序规则类型,则所得的级联字符串具有该排序规则类型。在所有其他情况下,连接的结果是排序类型EXACT

NULL和空字符串

使用NULL关键字表示没有指定值。 在SQL中,NULL始终是表示数据值因任何原因未指定或不存在的首选方式。

SQL零长度字符串(空字符串)由两个单引号字符指定。 空字符串(")与空字符串是不同的。 空字符串是一个已定义的值,一个不包含字符的字符串,一个长度为0的字符串。 一个零长度的字符串在内部由非显示字符$CHAR(0)表示。

注意:不建议使用SQL零长度字符串作为字段输入值或字段默认值。 使用NULL表示数据值的缺失。

在SQL编码中应避免使用SQL零长度字符串。 但是,由于许多SQL操作都会删除末尾的空格,所以只包含空格字符(空格和制表符)的数据值可能会导致SQL的零长度字符串。

注意,不同的SQL length函数返回不同的值:lengthCHAR_LENGTHDATALENGTH返回SQL长度。 $LENGTH返回ObjectScript表示长度。 长度不计算尾随空格; 所有其他长度函数都计算末尾的空格。

null 处理

NOT NULL数据约束要求字段必须接收一个数据值; 不允许指定NULL而不是值。 这个约束不阻止使用空字符串值。

SELECT语句的WHEREHAVING子句中的IS NULL谓词选择空值; 它不选择空字符串值。

IFNULL函数计算一个字段值,如果字段值为NULL,则返回第二个参数中指定的值。 它不会将空字符串值视为非空值。

COALESCE函数从提供的数据中选择第一个非空值。 它将空字符串值视为非空值。

CONCAT函数或concenate操作符(||)连接一个字符串和一个NULL时,结果是NULL。 如下面的例子所示:

SELECT {fn CONCAT('fred',NULL)} AS FuncCat,   -- returns <null>
       'fred'||NULL AS OpCat                  -- returns <null>

AVG、COUNT、MAX、MINSUM聚合函数在执行操作时忽略NULL值。 (COUNT *统计所有行,因为不可能有一个所有字段都为空值的记录。) SELECT语句的DISTINCT关键字在其操作中包含NULL; 如果指定的字段有空值,DISTINCT返回一个空行.

AVGCOUNTMIN、聚合函数受空字符串值的影响。 MIN函数将空字符串视为最小值,即使存在值为0的行。 MAXSUM聚合函数不受空字符串值的影响。

null 表达式

对大多数SQL函数提供NULL作为操作数将返回NULL

任何以NULL作为操作数的SQL算术操作都返回NULL值。 因此,7 +零=零。 这包括二元运算加法(+)、减法(-)、乘法(*)、除法(/)、整数除法(\)和取模(#),以及一元符号运算符加号(+)和减号(-)。

算术操作中指定的空字符串将被视为0(零)值。 除法(/),整数除法(\),或对空字符串(6/ ")取模(#)会导致<DIVIDE>错误。

NULL的长度

在SQL中,NULL的长度是没有定义的(它返回< NULL >)。 然而,空字符串的长度被定义为长度为0。 如下面的例子所示:

SELECT LENGTH(NULL) AS NullLen,   -- returns <null>
       LENGTH('') AS EmpStrLen    -- returns 0

如本例所示,SQL LENGTH函数返回SQL长度。

可以使用ASCII函数将SQL的零长度字符串转换为NULL,示例如下:

SELECT LENGTH(NULL) AS NullLen,                  -- returns <null> 
       LENGTH({fn ASCII('')}) AS AsciiEmpStrLen, -- returns <null>
       LENGTH('') AS EmpStrLen                   -- returns 0

但是,对标准SQL的某些系统间IRIS扩展对NULL和空字符串的长度的处理是不同的。 $LENGTH函数返回这些值的InterSystems IRIS内部表示:NULL表示为长度为0的已定义值,SQL空字符串表示为长度为0的字符串。 该功能与ObjectScript兼容。

SELECT $LENGTH(NULL) AS NullLen,    -- returns 0
$LENGTH('') AS EmpStrLen,           -- returns 0
$LENGTH('a') AS OneCharStrLen,      -- returns 1
$LENGTH(CHAR(0)) AS CharZero        -- returns 0 

这些值的内部表示方式的另一个重要位置是%STRING%SQLSTRING%SQLUPPER函数,它们将空格附加到值中。 因为NULL实际上没有值,所以在它后面添加一个空格会创建一个长度为1的字符串。 但是一个空字符串确实有一个字符值,所以在它后面加上一个空格会创建一个长度为2的字符串。 如下面的例子所示:

SELECT CHAR_LENGTH(%STRING(NULL)) AS NullLen,  -- returns 1
CHAR_LENGTH(%STRING('')) AS EmpStrLen          -- returns 2

注意,这个例子使用的是CHAR_LENGTH,而不是LENGTH。 因为LENGTH函数删除了末尾的空格,所以LENGTH(%STRING(NULL))返回长度为0的字符串; LENGTH(%STRING("))返回长度为2的字符串,因为%STRING追加的是前导空格,而不是尾随空格。

ObjectScript和SQL

当SQL NULL输出到ObjectScript时,它由ObjectScript空字符串("")表示,长度为0的字符串。

当SQL零长度字符串数据输出到ObjectScript时,它由包含$CHAR(0)的字符串表示,该字符串长度为1。


/// d ##class(PHA.TEST.SQL).Null()
ClassMethod Null()
{
	&sql(SELECT NULL,'' INTO :a,:b)
	WRITE !,"NULL length: ",$LENGTH(a)         // returns 0
	WRITE !,"empty string length: ",$LENGTH(b) // returns 1
}

DHC-APP>d ##class(PHA.TEST.SQL).Null()
 
NULL length: 0
empty string length: 1

在ObjectScript中,没有值通常用空字符串("")表示。 当这个值被传递到嵌入式SQL中时,它会被视为空值,如下面的例子所示:

/// d ##class(PHA.TEST.SQL).Null1()
ClassMethod Null1()
{
	SET x=""
	SET myquery="SELECT NULL As NoVal,:x As EmpStr"
	SET tStatement=##class(%SQL.Statement).%New()
	SET qStatus=tStatement.%Prepare(myquery)
	IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
	SET rset=tStatement.%Execute()
	WHILE rset.%Next() {
		WRITE "NoVal:",rset.%Get("NoVal")," length ",$LENGTH(rset.%Get("NoVal")),!      // length 0
		WRITE "EmpStr:",rset.%Get("EmpStr")," length ",$LENGTH(rset.%Get("EmpStr")),!   // length 0
	}
	WRITE "End of data"
}
DHC-APP>d ##class(PHA.TEST.SQL).Null1()
NoVal: length 0
EmpStr: length 0
End of data

如果指定了一个未定义的输入主机变量,嵌入式SQL将其值视为NULL

当将NULL或空字符串值从嵌入式SQL传递到ObjectScript时,NULL被转换为长度为0的字符串,空字符串被转换为长度为1的字符串。 如下面的例子所示:

/// d ##class(PHA.TEST.SQL).Null2()
ClassMethod Null2()
{
	&sql(SELECT 
	    NULL,
	    ''
	    INTO :a,:b)
	WRITE !,"The length of NULL is: ",$LENGTH(a)         // length 0
	WRITE !,"The length of empty string is: ",$LENGTH(b) // length 1
}
DHC-APP>d ##class(PHA.TEST.SQL).Null2()
 
The length of NULL is: 0
The length of empty string is: 1

在下面的例子中,SQL的空字符串加上一个空格被传递为长度为2的字符串:

/// d ##class(PHA.TEST.SQL).Null3()
ClassMethod Null3()
{
	&sql(SELECT %SQLUPPER('')
	    INTO :y )
	WRITE !,"SQL empty string length: ",$LENGTH(y)
}

DHC-APP> d ##class(PHA.TEST.SQL).Null3()
 
SQL empty string length: 2
5
0 451
文章 姚 鑫 · 二月 26, 2021 9m read

第四十八章 Caché 变量大全 ^$LOCK 变量

提供锁名信息。

大纲

^$|nspace|LOCK(lock_name,info_type,pid) 
^$|nspace|L(lock_name,info_type,pid)

参数

  • |nspace|[nspace] [nspace]可选-扩展SSVN引用,显式名称空间名称或隐含名称空间。必须计算为带引号的字符串,该字符串括在方括号([“nspace”])或竖线(|“nspace”|)中。命名空间名称不区分大小写;它们以大写字母存储和显示。
  • lock_name 计算结果为包含锁定变量名称(带下标或无下标)的字符串的表达式。如果是文字,则必须指定为带引号的字符串。
  • info_type 可选-解析为所有大写字母指定为带引号字符串的关键字的表达式。info_type指定返回关于lock_name的哪种类型的信息。可用选项有“所有者”、“标志”、“模式”和“计数”。作为独立函数调用^$LOCK时需要。
  • pid 可选-用于“计数”关键字。一个整数,指定锁所有者的进程标识。如果指定,最多为“计数”返回一个列表元素。如果省略(或指定为0),将为持有指定锁的每个所有者返回一个列表元素。pid对其他info_type关键字没有影响。

描述

^$LOCK结构化系统变量返回有关当前命名空间或本地系统上指定命名空间中的锁的信息。可以通过两种方式使用^$LOCK:

  • info_type作为独立函数返回指定锁的信息。
  • $DATA$ORDER$QUERY函数没有info_type作为参数。

注意:^$LOCK从本地系统的锁表中检索锁表信息。它不会从远程服务器上的锁表中返回信息。

ECP环境中的^$LOCK。

  • 本地系统:为本地系统持有的锁调用^$LOCK时,^$LOCK的行为与没有ECP时相同,只有一个例外:info_type的“FLAGS”返回一个星号(*),表示锁处于ECP环境中。这意味着一旦锁被释放,远程系统间IRIS实例就能够持有锁。
  • 应用服务器:当通过ECP(数据服务器或另一个应用服务器)在一个应用服务器上为另一个服务器上持有的锁调用^$LOCK时,^$LOCK不返回任何信息。请注意,这是与锁不存在时相同的行为。
  • 数据服务器:当在数据服务器上为应用服务器持有的锁调用^$LOCK时,^$LOCK的行为与本地系统略有不同,如下所示:
    • “Owner”:如果锁由连接到调用^$Lock的数据服务器的应用程序服务器持有,则^$Lock(LOCKNAME,“OWNER”)为持有该锁的实例返回“ECPConfigurationName:MachineName:InstanceName”,但不标识持有该锁的特定进程。
    • “FLAGS”:如果锁由连接到调用^$LOCK的数据服务器的应用程序服务器持有,则独占锁的^$LOCK(lockname,“FLAGS”)将返回“Z”标志。这个“Z”表示除了ECP环境之外,在InterSystems IRIS中不再使用的一种遗留锁。
    • “mode”:如果锁由连接到调用^$lock的数据服务器的应用程序服务器持有,则独占锁的^$lock(lockname,“mode”)返回“ZAX”而不是“X”ZA是一种遗留锁,除ECP环境外,在系统间IRIS中不再使用。对于共享锁,^$lock(lockname,“mode”)返回“S”,与本地锁相同。

参数

nspace

此可选参数允许您使用扩展的SSVN引用在另一个名称空间中指定全局变量。可以显式指定名称空间名称,将其命名为带引号的字符串文字或变量,或者通过指定隐式名称空间。命名空间名称不区分大小写。可以使用方括号语法[“ USER”]或环境语法|“ USER” |。 nspace分隔符前后不允许有空格。

可以使用以下方法测试是否定义了名称空间:

   WRITE ##class(%SYS.Namespace).Exists("USER"),! 
   WRITE ##class(%SYS.Namespace).Exists("LOSER")   

可以使用$NAMESPACE特殊变量来确定当前的名称空间。更改当前名称空间的首选方法是NEW $NAMESPACE,然后SET $NAMESPACE =“nspacename”

lock_name

该表达式的计算结果为包含锁定变量名称(带下标或未下标)的字符串。使用LOCK命令定义一个锁变量(通常是全局变量)。

info_type

当将^$LOCK用作独立函数时,需要一个info_type关键字;当将^$LOCK用作另一个函数的参数时,则是一个可选参数。 info_type必须以大写字母指定为带引号的字符串。

  • “OWNER”返回锁所有者的进程ID(pid)。如果该锁是共享锁,则以逗号分隔列表的形式返回该锁的所有所有者的进程ID。如果指定的锁不存在,则^$LOCK返回空字符串。
  • “FLAGS”返回锁的状态。它可以返回以下值:“D”-处于挂起挂起状态; “P”-处于锁定挂起状态; “N”-这是一个节点锁定,后代未锁定; “Z”-此锁处于ZAX模式; “L”-锁丢失,服务器不再具有此锁; “*”-这是一个远程锁定。如果指定的锁处于正常锁状态或不存在,则^$LOCK返回空字符串。
  • “MODE”返回当前节点的锁定模式。对于排他锁定模式,它返回“X”,对于共享锁定模式,它返回“S”,对于ZALLOCATE锁定模式,它返回“ZAX”。如果指定的锁不存在,则^$LOCK返回空字符串。
  • “COUNTS”返回锁的锁计数,指定为二进制列表结构。对于排他锁,列表包含一个元素;对于共享锁,列表包含每个锁所有者的元素。可以使用pid参数仅返回指定锁定所有者的list元素。每个元素都包含所有者的pid,独占模式增量计数和共享模式增量计数。如果独占模式和共享模式的增量计数均为0(或“”),则锁定处于“ZAX”模式。增量计数后可以跟一个“D”,以指示该锁已在当前事务中解锁,但是其释放被延迟(“D”),直到事务被提交或回滚为止。如果指定的锁不存在,则^$LOCK返回空字符串。

必须使用所有大写字母指定info_type关键字。指定无效的info_type关键字会生成<SUBSCRIPT>错误。

pid

锁所有者的进程ID。仅在使用“COUNTS”关键字时有意义。用于将“ ”返回值限制为(最多)一个列表元素。 pid在所有平台上均指定为整数。如果pid与lock_name ^$LOCK的所有者的进程ID匹配,则返回该所有者的“COUNTS”列表元素;如果pid与lock_name ^$LOCK的所有者的进程ID不匹配,则返回空字符串。将pid指定为0表示与省略pid相同; ^$LOCK返回所有“COUNTS”列表元素。pid参数与“OWNER”“FLAGS”“MODE”关键字一起使用,但被忽略。

示例

下面的示例显示由info_type关键字返回的排他锁的值:

/// d ##class(PHA.TEST.SpecialVariables).LOCK()
ClassMethod LOCK()
{
	LOCK ^B(1,1)  ; define lock
	WRITE !,"lock owner: ",^$LOCK("^B(1,1)","OWNER")
	WRITE !,"lock flags: ",^$LOCK("^B(1,1)","FLAGS")
	WRITE !,"lock mode: ",^$LOCK("^B(1,1)","MODE")
	WRITE !,"lock counts: "
	ZZDUMP ^$LOCK("^B(1,1)","COUNTS")
	LOCK -^B(1,1) ; delete lock
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).LOCK()
 
lock owner: 17824
lock flags:
lock mode: X
lock counts:
0000: 0B 01 04 04 A0 45 03 04 01 02 01                        ....??E.....

下面的示例显示在递增和递减独占锁时,info_type “COUNTS”返回的值如何变化:

/// d ##class(PHA.TEST.SpecialVariables).LOCK1()
ClassMethod LOCK1()
{
	LOCK ^B(1,1)      ; define exclusive lock
	ZZDUMP ^$LOCK("^B(1,1)","COUNTS")
	LOCK +^B(1,1) ; increment lock
	ZZDUMP ^$LOCK("^B(1,1)","COUNTS")
	LOCK +^B(1,1) ; increment lock again
	ZZDUMP ^$LOCK("^B(1,1)","COUNTS")
	LOCK -^B(1,1) ; decrement lock
	ZZDUMP ^$LOCK("^B(1,1)","COUNTS")
	LOCK -^B(1,1) ; decrement lock again
	ZZDUMP ^$LOCK("^B(1,1)","COUNTS")
	LOCK -^B(1,1) ; delete exclusive lock
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).LOCK1()
 
0000: 0B 01 04 04 A0 45 03 04 01 02 01                        ....??E.....
0000: 0B 01 04 04 A0 45 03 04 02 02 01                        ....??E.....
0000: 0B 01 04 04 A0 45 03 04 03 02 01                        ....??E.....
0000: 0B 01 04 04 A0 45 03 04 02 02 01                        ....??E.....
0000: 0B 01 04 04 A0 45 03 04 01 02 01                        ....??E.....

下面的示例显示在递增和递减共享锁时,info_type“COUNTS”返回的值如何变化

/// d ##class(PHA.TEST.SpecialVariables).LOCK2()
ClassMethod LOCK2()
{
	LOCK ^S(1,1)#"S"   ; define shared lock
	ZZDUMP ^$LOCK("^S(1,1)","COUNTS")
	LOCK +^S(1,1)#"S" ; increment lock
	ZZDUMP ^$LOCK("^S(1,1)","COUNTS")
	LOCK +^S(1,1)#"S" ; increment lock again
	ZZDUMP ^$LOCK("^S(1,1)","COUNTS")
	LOCK -^S(1,1)#"S" ; decrement lock
	ZZDUMP ^$LOCK("^S(1,1)","COUNTS")
	LOCK -^S(1,1)#"S" ; decrement lock again
	ZZDUMP ^$LOCK("^S(1,1)","COUNTS")
	LOCK -^S(1,1)#"S" ; delete shared lock
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).LOCK2()
 
0000: 0B 01 04 04 A0 45 02 01 03 04 01                        ....??E.....
0000: 0B 01 04 04 A0 45 02 01 03 04 02                        ....??E.....
0000: 0B 01 04 04 A0 45 02 01 03 04 03                        ....??E.....
0000: 0B 01 04 04 A0 45 02 01 03 04 02                        ....??E.....
0000: 0B 01 04 04 A0 45 02 01 03 04 01                        ....??E.....

以下示例显示如何将^$lock用作$DATA$ORDER$QUERY函数的参数。

作为$DATA的参数

$DATA(^$|nspace|LOCK(lock_name))

^$lock作为$DATA的参数返回一个整数值,该值指定锁定名称是否作为节点存在于^$lock中。下表显示了$DATA可以返回的整数值。

ValueMeaning
0锁信息不存在
10锁信息存在

请注意,在此上下文中使用的$DATA只能返回0或10,其中10表示指定的锁存在。它不能确定锁是否有后代,也不能返回1或11。

下面的示例测试当前命名空间中是否存在锁名。第一次写入返回10(锁名存在),第二次写入返回0(锁名不存在):

/// d ##class(PHA.TEST.SpecialVariables).LOCK3()
ClassMethod LOCK3()
{
	LOCK ^B(1,2)  ; define lock
	WRITE !,$DATA(^$LOCK("^B(1,2)"))
	LOCK -^B(1,2) ; delete lock
	WRITE !,$DATA(^$LOCK("^B(1,2)"))
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).LOCK3()
 
10
0

作为$ORDER的参数

$ORDER(^$|nspace|LOCK(lock_name),direction)

^$lock作为$ORDER的参数,按排序顺序将下一个或上一个^$lock锁名节点返回到指定的锁名。如果不存在这样的锁名作为^$lock节点,$ORDER将返回空字符串。

锁以区分大小写的字符串排序顺序返回。使用数字排序规则以下标树顺序返回命名锁的下标。

Direction参数指定是返回下一个锁名称还是返回上一个锁名称。如果不提供方向参数,InterSystems IRIS会将排序序列中的下一个锁名返回到您指定的锁名。

以下子例程在Samples名称空间中搜索锁,并将锁名称存储在名为locket的本地数组中。

/// d ##class(PHA.TEST.SpecialVariables).LOCK4()
ClassMethod LOCK4()
{
LOCKARRAY
	SET lname=""
	FOR I=1:1 {
	SET lname=$ORDER(^$|"SAMPLES"|LOCK(lname))
		QUIT:lname=""
		SET LOCKET(I)=lname
		WRITE !,"the lock name is: ",lname
	}
	WRITE !,"All lock names listed"
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).LOCK4()
 
the lock name is: ^%SYS("CSP","Daemon")
All lock names listed

作为$QUERY的参数

$QUERY(^$|nspace|LOCK(lock_name))

^$lock作为$query的参数,将排序序列中的下一个锁名返回到您指定的锁名。如果没有将下一个锁名定义为^$lock中的节点,则$query将返回空字符串。

锁以区分大小写的字符串排序顺序返回。使用数字排序规则以下标树顺序返回命名锁的下标。

在下面的示例中,在当前命名空间中(按随机顺序)创建了五个全局锁名称。

/// d ##class(PHA.TEST.SpecialVariables).LOCK5()
ClassMethod LOCK5()
{
	LOCK (^B(1),^A,^D,^A(1,2,3),^A(1,2))
	WRITE !,"lock name: ",$QUERY(^$LOCK(""))
	WRITE !,"lock name: ",$QUERY(^$LOCK("^C"))
	WRITE !,"lock name: ",$QUERY(^$LOCK("^A(1,2)"))
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).LOCK5()
 
lock name: ^$LOCK("^%SYS(""CSP"",""Daemon"")")
lock name: ^$LOCK("^D")
lock name: ^$LOCK("^A(1,2,3)")

$QUERY将所有全局锁变量名(带下标或无下标)视为字符串,并按字符串排序顺序检索它们。因此,$QUERY(^$LOCK(“”))按排序顺序检索第一个锁名:^$LOCK(“^A”)或排序序列中位置较高的InterSystems IRIS定义的锁。$QUERY(^$LOCK(“^C”))检索排序序列中不存在的^C^$LOCK(“^D”)之后的下一个锁名。$QUERY(^$LOCK(“^A(1,2)”))检索排序规则序列中它后面的^$LOCK(“^A(1,2,3)”)

2
0 153
文章 Qiao Peng · 三月 5, 2021 3m read

大家好!

InterSystems IRIS 有一个名为 Interoperability(互操作性)的菜单。

它提供了轻松创建系统集成(适配器、记录映射、BPM、数据转换等)的机制,因此可以轻松连接不同的系统。

数据中继过程中可以包括各种操作,例如:为了连接没有正常连接的系统,可以根据目标系统的规范来接收(或发送)数据。 此外,在发送数据之前,可以从其他系统获取和添加信息。 还可以从数据库(IRIS 等)获取和更新信息。

在本系列文章中,我们将讨论以下主题,同时查看 示例代码 以帮助您了解工作原理以及在系统中集成互操作性时需要进行哪种开发。

首先,我介绍一下我们将在本系列文章中使用的案例研究。

某公司运营着一个购物网站,他们正在更改产品信息的显示顺序以配合季节变化。
但是,有些商品无论季节如何都能卖得很好,而有些商品在意料之外的时间卖出,这不符合当前的显示顺序更改规则,
因此,我们研究了按照当天的温度而不是季节来更改显示顺序的可能性。 调查购买产品时的温度变得非常必要。
由于可以使用外部 Web API 来查询天气信息,因此我们计划收集购买时的天气信息,并将其记录在后面的审核数据库中。

案例非常简单,但您需要使用“外部 Web API”来收集信息,并且需要将获得的信息和购买信息结合起来记录在数据库中。

具体说明将在相关文章中讨论(不包括网站的创建)。 请移步观看!

至于我们这次使用的“外部 Web API”,我们使用的是 OpenWeather当前天气数据.

(如果您想要尝试一下,您需要注册一个帐户并获得 API ID).

以下是一个 REST 客户端发出的 GET 请求的结果(我们将以在 Interoperability 中实现的机制来运行此流程)。

HTTP 响应的 JSON 如下所示:

{
    "coord": {
        "lon": 135.5022,
        "lat": 34.6937
    },
    "weather": [
        {
            "id": 803,
            "main": "Clouds",
            "description": "broken clouds",
            "icon": "04d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 17.05,
        "feels_like": 13.33,
        "temp_min": 16,
        "temp_max": 18,
        "pressure": 1017,
        "humidity": 55
    },
    "visibility": 10000,
    "wind": {
        "speed": 4.63,
        "deg": 70
    },
    "clouds": {
        "all": 75
    },
    "dt": 1611635756,
    "sys": {
        "type": 1,
        "id": 8032,
        "country": "JP",
        "sunrise": 1611612020,
        "sunset": 1611649221
    },
    "timezone": 32400,
    "id": 1853909,
    "name": "Osaka",
    "cod": 200
}

下一篇文章中,我们将讨论如何使用 Interoperability 菜单进行系统集成。

0
0 113
文章 Qiao Peng · 三月 5, 2021 1m read

InterSystems IRIS 元素周期表

GlobalsSQL DatabaseDocDB - Document DatabaseMultidimensional Cube DatabaseNLP DatabaseObject DatabaseJDBC DriverODBC DriverNative API for JavaNative API for .NETNative API for PythonC/C++ Callin/CalloutNative API for Node.jsObject ScriptCaché MultivalueCaché Object ScriptCaché BasicCSP/HTML SupportT-SQLInfrastructure as Code (IaC)DockerInterSystems Kubernetes OperatorIRIS in the Google Cloud PlatformIRIS Community EditionZPM - Package ManagerIRIS in the AzureIRIS in the TencentIRIS Sharding supportInterSystems Cloud ManagerInterSystems in the AWSInterSystems On-PremisesEnterprise Cache Protocol - ECPMachine LearningR and AI robotizationNLP - Natural Language ProcessingMDX - MultiDimensional ExpressionsAutoML - InterSystems IntegratedMLAnalytics/BI - Business IntelligenceInterSystems ReportsPowerBI SupportPMML - Predictive Model Markup LanguageApache UIMAApache SparkAnalytical DashboardsInterSystems Developer CommunityInterSystems Open Exchange - Open Source Apps, Samples and templatesInterSystems Worldwide Response Center InterSystems Learning ServicesInteroperability AdaptersDTL - Data TransformationMQ - Message QueueEAI - Enterprise Application IntegrationESB - Enterprise Service BusAPI ManagerCDC - Change Data CaptureBAM - Business Activity MonitoringBPLIoT - Internet of ThingsSOA - Service Oriented ArchitectureApplication/Service GovernanceData EncryptionAuthorization ManagementAuthentication ManagementAudit ManagementLabel SecuritySSL/TLSSOAP/API SecurityUser Portal SecurityData/Assets SecurityDisaster Recovery - Backup and RestoreData Intensive - ESG ReviewBig DataArtificial IntelligenceAPI Driven EconomyDigital HealthPublic SectorDigital TransformationHyper automationBusiness SectorData as ServiceSoftware as ServiceIRIS as BackendIRIS as Mobile backendIoT Backend

PDF 版本:https://github.com/yurimarx/iris-periodic-table/raw/master/periodic%20table%20iris.pdf

GIT 源:https://github.com/yurimarx/iris-periodic-table

InterSystems IRIS 是一个具有许多功能的数据平台。 这些功能和相关的 IRIS 主题都体现在元素周期表中。

0
0 128
文章 Claire Zheng · 一月 20, 2021 6m read

简介

最近完成了针对IRIS医疗版2020.1版本的性能及可扩展性基准测试,重点关注HL7v2的互操作性。本文介绍了在各种工作负载下观察到的吞吐量,并提供了IRIS医疗版用作HL7v2消息传输互操作性引擎时的系统常规配置和调整准则。

基准测试模拟了与实际环境接近的工作负载(详细信息请参见“工作负载说明和方法”部分)。本次测试的工作负载包括HL7v2患者管理(ADT)和生命体征结果(ORU)数据,并包含数据内容转换和路由。

IRIS医疗版2020.1版本可以表明,采用第二代Intel®Xeon®可扩展处理器和Intel®Optane™SSD DC P4800X系列SSD存储的商用服务器,每天的持续消息吞吐量超过23亿条(入站和出站总量),与此前的Ensemble 2017.1 HL7v2吞吐量基准测试相比,扩展性提高了一倍多。

2
0 348
文章 Michael Lei · 二月 26, 2021 1m read

不少客户问我关于从Cache迁移到IRIS的问题。为什么要迁移到IRIS?Cache是优秀的,稳定的,有很好的性能,为什么要迁移到IRIS呢?这些客户是对的,但在过去几年,数字化转型提出了不少新问题、新需求和新挑战,客户需要更灵活、更完整、更前瞻的解决方案,InterSystems公司很有远见地洞察到了这一点,推出了IRIS。
一句话,IRIS是一套数据平台解决方案,它帮助客户和合作伙伴为迎接数字化转型的挑战提供了充足的弹药。

0
0 179
文章 姚 鑫 · 二月 25, 2021 3m read

第四十七章 Caché 变量大全 ^$JOB 变量

提供系统间IRIS进程(JOB)信息。

大纲

^$JOB(job_number)
^$J(job_number)

参数

  • job_number 输入ObjectScript命令时创建的系统特定OBJ编号。每个活动的InterSystems IRIS进程都有一个唯一的作业号。登录到系统会启动一个作业。在UNIX®系统上,作业号是调用InterSystems IRIS时启动的子进程的PIDJOB_NUMBER必须指定为整数;不支持十六进制值。

描述

可以将^$JOB结构化系统变量用作$DATA$ORDER$QUERY函数的参数,以获取有关本地InterSystems IRIS系统上是否存在InterSystems IRIS作业的信息。

示例

以下示例显示如何将^$JOB用作$DATA$ORDER$QUERY函数的参数。

作为$DATA的参数

$DATA(^$JOB(job_number))

^$JOB作为$DATA的参数返回一个整数值,该值指示指定的作业是否作为节点存在于^$JOB中。下表显示了$DATA可以返回的整数值。

ValueMeaning
0JOB不存在
1JOB存在

以下示例测试系统间IRIS进程是否存在。

DHC-APP>SET x=$JOB
 
DHC-APP>WRITE !,$DATA(^$JOB(x))
 
1

变量x设置为当前进程的作业号(例如:4294219937)。写入操作返回布尔值1,表示此进程存在。

作为$ORDER的参数

$ORDER(^$JOB(job_number),direction)

^$JOB作为$ORDER的参数,按排序顺序将下一个或上一个^$JOB编号返回到指定的作业编号。如果不存在作为^$JOB节点的此类JOB编号,$ORDER将返回空字符串。

Direction参数指定是否返回下一个或上一个job编号。如果不提供方向参数,InterSystems IRIS会将排序顺序中的下一个job编号返回给指定的job编号。

以下子例程搜索InterSystems IRIS作业表,并将job号存储在名为job的本地数组中。

/// d ##class(PHA.TEST.SpecialVariables).JOB()
ClassMethod JOB()
{
JOB
	SET pid=""
	FOR i=1:1 {
		SET pid=$ORDER(^$JOB(pid))
		QUIT:pid="" 
		SET JOB(i)=pid
	}
	zw JOB
	WRITE "总共job有: ",i
	QUIT
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).JOB()
JOB(1)=612
JOB(2)=1424
JOB(3)=1972
JOB(4)=5624
JOB(5)=7244
JOB(6)=7864
JOB(7)=7872
JOB(8)=7892
JOB(9)=7920
JOB(10)=8332
JOB(11)=9048
JOB(12)=9084
JOB(13)=9340
JOB(14)=10084
JOB(15)=10112
JOB(16)=10156
JOB(17)=10200
JOB(18)=10212
JOB(19)=10828
JOB(20)=22432
总共job有: 21

作为$QUERY的参数

$QUERY(^$JOB(job_number))

^$JOB作为$QUERY的参数,按排序顺序将下一个^$JOB编号返回到指定的JOB编号。如果^$JOB中没有这样的JOB编号作为节点,则$QUERY将返回空字符串。

以下示例返回InterSystems IRISJOB表中的前两个JOB。请注意间接运算符(@)的用法:

DHC-APP>SET x=$QUERY(^$JOB(""))
 
DHC-APP> WRITE !,x
 
^$JOB("612")
DHC-APP>WRITE !,$QUERY(@x)
 
^$JOB("1424")
0
0 162
文章 姚 鑫 · 二月 24, 2021 6m read

第四十六章 Caché 变量大全 ^$GLOBAL 变量

提供有关全局变量和进程私有全局变量的信息。

大纲

^$|nspace|GLOBAL(global_name)
^$|nspace|G(global_name)

^$||GLOBAL(global_name)
^$||G(global_name)

参数

  • |nspace|[nspace] - 可选-扩展SSVN引用,可以是显式名称空间名称,也可以是隐含名称空间。必须计算为带引号的字符串,该字符串括在方括号([“nspace”])或竖线(|“nspace”|)中。命名空间名称不区分大小写;它们以大写字母存储和显示。
  • global_name 计算结果为包含无下标全局名称的字符串的表达式。全局名称区分大小写。使用^$||global()语法时,与进程专用全局名称相对应的无下标全局名称:^a表示^||a

描述

可以将^$GLOBAL用作$DATA$ORDER$QUERY函数的参数,以返回有关当前名称空间(默认名称空间)或指定名称空间中是否存在全局变量的信息。还可以使用^$global返回有关存在进程私有全局变量的信息。

进程私有全局变量

可以使用^$global获取有关所有命名空间中是否存在进程私有全局变量的信息。可以将进程专用全局的查找指定为^$||global^$|“^”|global

例如,要获取有关进程私有全局^||a及其后代的信息,可以指定$DATA(^$||global(“^a”))。进程私有全局变量不是特定于名称空间的,因此在定义进程私有全局变量时,无论当前名称空间如何,此查找都会返回有关^||a的信息。

请注意,^$GLOBAL不支持在GLOBAL_NAME本身中指定进程专用全局语法。使用进程专用全局语法指定GLOBAL_NAME会导致<NAME>错误。

参数

nspace

此可选参数允许^$GLOBAL查找在另一个命名空间中定义的GLOBAL_NAME。这称为扩展SSVN参考。可以显式地将命名空间名称指定为带引号的字符串文字、变量,也可以通过指定隐含的命名空间来指定。命名空间名称不区分大小写。可以使用方括号语法[“user”]或环境语法|“user”|。Nspace分隔符前后不允许有空格

可以使用以下方法测试是否定义了命名空间:

DHC-APP>WRITE ##class(%SYS.Namespace).Exists("USER")
1
DHC-APP>WRITE ##class(%SYS.Namespace).Exists("LOSER")
0

以使用$NAMESPACE特殊变量来确定当前名称空间。更改当前名称空间的首选方式是新建$NAMESPACE,然后设置$NAMESPACE=“nspace ename”

global_name

计算结果为包含无下标全局名称的字符串的表达式。全局变量区分大小写。

  • ^$global(“^a”)global_name“^a”在当前名称空间中查找此全局名称及其后代。它不查找进程私有全局“^||a”
  • ^$|"USER"|GLOBAL("^a"):global_name "^a"“user”名称空间中查找此全局名称及其后代。它不查找进程-私有全局"^||a"。 - ^$||GLOBAL("^a"):global_name "^a"在所有名称空间中查找进程私有全局"^||a"及其后代。它不查找全"^a"

示例

以下示例显示如何将^$GLOBAL用作$DATA$ORDER$QUERY函数的参数。

作为$DATA的参数

^$GLOBAL作为$DATA的参数返回一个整数值,表示指定的全局名称是否作为^$GLOBAL节点存在。下表显示了$DATA可以返回的整数值。

ValueMeaning
0全局名称不存在
1全局名称是包含数据但没有子代的现有节点。
10全局名称是没有数据但具有子代的现有节点。
11全局名称是包含数据的现有节点,并且具有子代。

下面的示例测试当前命名空间中是否存在指定的全局变量:

/// d ##class(PHA.TEST.SpecialVariables).GLOBAL()
ClassMethod GLOBAL()
{
	KILL ^GBL
	WRITE $DATA(^$GLOBAL("^GBL")),!
	SET ^GBL="test"
	WRITE $DATA(^$GLOBAL("^GBL")),!
	SET ^GBL(1,1,1)="subscripts test"
	WRITE $DATA(^$GLOBAL("^GBL"))
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).GLOBAL()
0
1
11

下面的示例测试user命名空间中是否存在指定的全局变量:

/// d ##class(PHA.TEST.SpecialVariables).GLOBAL1()
ClassMethod GLOBAL1()
{
	SET $NAMESPACE="USER"
	SET ^GBL(1)="test"
	SET $NAMESPACE="%SYS"
	WRITE $DATA(^$|"USER"|GLOBAL("^GBL"))
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).GLOBAL1()
10

下面的示例测试任何命名空间中是否存在指定的进程私有全局变量:

/// d ##class(PHA.TEST.SpecialVariables).GLOBAL2()
ClassMethod GLOBAL2()
{
	SET $NAMESPACE="USER"
	SET ^||PPG(1)="test"
	SET $NAMESPACE="%SYS"
	WRITE $DATA(^$||GLOBAL("^PPG"))
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).GLOBAL2()
10

作为$ORDER的参数

$ORDER(^$|nspace|GLOBAL( global_name),direction)

^$GLOBAL作为$ORDER的参数,将排序序列中的下一个或上一个全局名称返回到指定的全局名称。如果^$GLOBAL中不存在这样的全局名称节点,$ORDER将返回空字符串。

注意:$ORDER(^$GLOBAL(NAME))不会从IRISSYS数据库返回%global names

Direction参数指定是返回下一个全局名称还是返回上一个全局名称。如果不提供方向参数,InterSystems IRIS会将排序顺序中的下一个全局名称返回给您指定的全局名称。

以下子例程搜索当前名称空间,并将全局名称存储在名为global的本地数组中。

/// d ##class(PHA.TEST.SpecialVariables).GLOBAL3()
ClassMethod GLOBAL3()
{
GLOB   
	SET NAME=""
	WRITE !,"以下全局变量在 ",$NAMESPACE
	FOR I=1:1 {
		SET NAME=$ORDER(^$GLOBAL(NAME))
		WRITE !,NAME
		QUIT:NAME=""
		SET GLOBAL(I)=NAME
	}
	WRITE !,"全部完成"
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).GLOBAL3()
 
以下全局变量在 DHC-APP
^%ISCWorkQueue
^%cspSession
^%qCacheMsg
^%qCacheMsgNames
^%qCacheObjectErrors
^%qCacheObjectKey
^%qCacheObjectQualifier
^%qCacheSQL
^%qHTMLElementD
^%qJavaMetaDictionary
^%qMgtPortal.Index
^%qPublicSuffix
^%qStream
^%qcspRule
^A
^AA
<INTERRUPT>Visible+4^%SYS.GD
DHC-APP>

作为$QUERY的参数

^$GLOBAL作为$QUERY的参数,按排序顺序将下一个全局名称返回到指定的全局名称。如果^$GLOBAL中不存在这样的全局名称作为节点,则$QUERY将返回空字符串。

注意:$QUERY(^$GLOBAL(NAME))不会从IRISSYS数据库返回%GLOBAL NAMES

在以下示例中,用user命名空间中存在三个全局变量(^GBL1^GBL2^GBL3)。

/// d ##class(PHA.TEST.SpecialVariables).GLOBAL4()
ClassMethod GLOBAL4()
{
	NEW $NAMESPACE
	SET $NAMESPACE="USER"
	SET (^GBL1,^GBL2,^GBL3)="TEST"
	NEW $NAMESPACE
	SET $NAMESPACE="%SYS"
	WRITE $QUERY(^$|"USER"|GLOBAL("^GBL1")),!
	WRITE $QUERY(^$|"USER"|GLOBAL("^GBL2"))
	NEW $NAMESPACE
	SET $NAMESPACE="USER"
	KILL ^GBL1,^GBL2,^GBL3
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).GLOBAL4()
^$|"USER"|GLOBAL("^GBL2")
^$|"USER"|GLOBAL("^GBL3")

作为MERGE的参数

^$GLOBAL作为MERGE命令的源参数,将全局目录复制到目标变量。Merge将每个全局名称添加为具有空值的目标下标。下面的示例显示了这一点:

   MERGE gbls=^$GLOBAL("")
   ZWRITE gbls
...
gbls("^zlgsql")=""
gbls("^zlgtem")=""
gbls("^zlgtem1")=""
gbls("^zlgtem4")=""
gbls("^zlgtemp")=""
gbls("^zlgtemp1")=""
gbls("^zlgtemp3")=""
gbls("^zlgtemp5")=""
gbls("^zlgtmp")=""
gbls("^zlj")=""
gbls("^zll")=""
gbls("^zltmp")=""
gbls("^zmc")=""
gbls("^znum")=""
gbls("^zpeterc")=""
gbls("^zsb")=""
gbls("^zseq")=""
gbls("^zstock")=""
gbls("^ztTmp")=""
gbls("^ztrap1")=""
gbls("^zwb1")=""
gbls("^zwhtmp")=""
gbls("^zx")=""
gbls("^zx1")=""
gbls("^zx2")=""
gbls("^zxdd")=""
gbls("^zyb")=""
gbls("^zyb1")=""
gbls("^zyb2")=""
gbls("^zyl")=""
gbls("^zzTT")=""
gbls("^zzdt")=""
gbls("^zzp")=""
gbls("^zzy")=""
gbls("^zzz")=""
0
0 156
文章 姚 鑫 · 二月 23, 2021 3m read

第四十五章 Caché 变量大全 $ZVERSION 变量

包含一个字符串,描述do命令后面的InterSystems IRIS.line的当前版本。

大纲

$ZVERSION 
$ZV

描述

$ZVERSION包含一个字符串,该字符串显示当前运行的InterSystems IRIS®Data Platform实例的版本。

以下示例返回$ZVERSION字符串:

DHC-APP>WRITE $ZVERSION
Cache for Windows (x86-64) 2016.2 (Build 736U) Fri Sep 30 2016 11:46:02 EDT

此字符串包括InterSystems IRIS安装的类型(产品和平台,包括CPU类型)、版本号(2018.1)、该版本中的内部版本号(内部版本号中的“U”表示UNICODE以及创建此版本的InterSystems IRIS的日期和时间。“EST”是东部标准时间(美国东部的时区),“EDT”是东部夏令时

通过调用GetVersion()类方法可以返回相同的信息,如下所示:

DHC-APP>WRITE $SYSTEM.Version.GetVersion()
Cache for Windows (x86-64) 2016.2 (Build 736U) Fri Sep 30 2016 11:46:02 EDT

以通过调用其他%SYSTEM.Version方法来获取此版本字符串的组成部分,可以通过调用以下命令列出这些方法:

DHC-APP> DO $SYSTEM.Version.Help()
'Do $system.Version.Help(method)' 将显示单个方法的完整描述.
 
类的方法:%SYSTEM.Version
 
FeatureBits(bit)
     Return all the feature codes stored in $zversion(0)
 
Format(Format,zv)
     Formats the version info according to the following format types:
 
GetBuildDate(zv)
     Returns the date the product was built in $HOROLOG format.
 
GetBuildNumber(zv)
     Returns the build number for the product.
 
GetBuildOS(zv)
     Returns the operating system for which the product was built.
 
GetBuildTime(zv)
     Returns the time of day the product was built in $HOROLOG format.
 
GetCompBuild(component)
     Returns the build number for the specified component. (Deprecated)
...

通过转到InterSystems IRIS启动器并选择关于...,可以查看版本和内部版本号信息。

不能使用SET命令修改$ZVERSION特殊变量。尝试这样做会导致<SYNTAX>错误。

示例

以下示例从版本字符串中提取创建日期,以计算InterSystems IRIS的当前版本有多早(以天为单位)。请注意,此示例特定于Windows平台:


/// d ##class(PHA.TEST.SpecialVariables).ZVERSION()
ClassMethod ZVERSION()
{
	SET createdate=$PIECE($ZVERSION," ",9,11)
	WRITE !,"Creation date: ",createdate
	WRITE !,"Current date:  ",$ZDATE($HOROLOG,6)
	SET nowcount=$PIECE($HOROLOG,",")
	SET thencount=$ZDATEH(createdate,6)
	WRITE !,"This version is ",(nowcount-thencount)," days old"
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZVERSION()
 
Creation date: Sep 30 2016
Current date:  Feb 10 2021
This version is 1594 days old

下面的示例通过调用类方法执行相同的操作:

/// d ##class(PHA.TEST.SpecialVariables).ZVERSION1()
ClassMethod ZVERSION1()
{
	SET createdate=$SYSTEM.Version.GetBuildDate()
	WRITE !,"Creation date: ",$ZDATE(createdate,6)
	WRITE !,"Current date:  ",$ZDATE($HOROLOG,6)
	SET nowcount=$PIECE($HOROLOG,",")
	WRITE !,"This version is ",(nowcount-createdate)," days old"
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZVERSION1()
 
Creation date: Sep 30 2016
Current date:  Feb 10 2021
This version is 1594 days old
0
0 83
文章 姚 鑫 · 二月 22, 2021 7m read

第四十四章 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设置为^routinelabel^routine.尝试这样做将导致<SYNTAX>错误。

在过程中,将$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发出<NOLINE>错误消息。

每个堆栈级别可以有其自己的$ZTRAP值。设置$ZTRAP时,系统会将$ZTRAP的值保存为先前的堆栈级别。当前堆栈级别结束时,InterSystems IRIS会恢复该值。要在当前堆栈级别启用错误陷阱,请通过指定$ZTRAP的位置将其设置为错误陷阱处理程序。例如:


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

在例程中,可以选择在发生错误后保留调用堆栈。为此,请在位置之前和双引号内放置一个星号(*)。该表格不适用于程序。尝试这样做会导致<SYNTAX> 错误。只能在不是过程的子例程中使用此示例中的:

/// 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上执行WRITEZZDUMP时不会显示此星号。

^%ETN

在例程中,set $ZTRAP=“^%ETN”将系统提供的错误例程%ETN建立为当前错误捕获处理程序。%ETN在调用它的发生错误的上下文中执行。(%et%etn的旧名称。它们的功能相同,但%ETN的效率略高一些。)。^%ETN错误处理程序的行为总是前缀星号(*)。

因为过程块中的$ZTRAP不能用于转到过程主体之外的位置,所以不能在过程中使用SET $ZTRAP=“^%ETN”。尝试这样做会导致<SYNTAX>错误。

TRY / CATCH 与 $ZTRAP

不能在TRY块内设置$ZTRAP。尝试这样做会生成编译错误。可以在TRY块之前或在CATCH块内设置$ZTRAP

无论之前是否设置了$ZTRAPTRY块中发生的错误都由CATCH块处理。CATCH块内发生的错误由当前错误捕获处理程序处理。

下面的第一个示例显示了TRY块中发生的错误。下面的第二个示例显示了try块中引发的异常。在这两种情况下,都会采用CATCH块,而不是$ZTRAP

/// 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
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP()
Catch taken
/// 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
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP1()
Catch taken

但是,try块可以调用设置和使用$ZTRAP的代码。在下面的示例中,$ZTRAP而不是CATCH块捕获被零除错误:

/// 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
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP2()
$ZTRAP taken

CATCH块中的Throw命令还可以调用$ZTRAP错误处理程序。

示例

下面的示例将$ZTRAP设置为此程序中的OnError例程。然后,它调用发生错误的Suba(尝试将数字除以0)。当错误发生时,InterSystems IRIS调用$ZTRAP中指定的OnError例程。OnError在设置$ZTRAP的上下文级别调用。因为OnErrorMain处于相同的上下文级别,所以执行不会返回Main

/// 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
}
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


/// 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
}
0
0 97
文章 姚 鑫 · 二月 21, 2021 7m read

第四十三章 Caché 变量大全 $ZTIMEZONE 变量

包含格林威治子午线的时区偏移量。

大纲

$ZTIMEZONE
$ZTZ

描述

$ZTIMEZONE可以通过两种方式使用:

  • 返回计算机的本地时区偏移量。
  • 为当前进程设置本地时区偏移量。

$ZTIMEZONE包含从格林威治子午线偏移的时区(以分钟为单位)。 (格林威治子午线包括整个英国和爱尔兰。)此偏移量表示为-1440到1440范围内的有符号整数。格林威治以西的时区指定为正数;格林威治东部的时区指定为负数。 (时区必须以分钟为单位,因为并非所有时区都以小时为单位。)默认情况下,$ZTIMEZONE初始化为计算机操作系统设置的时区。

注意:$ZTIMEZONE将本地时间调整为固定的偏移量。它不适应夏令时或其他当地时间的变化。 InterSystems IRIS从基础操作系统获取本地时间,该操作系统将本地时间变体应用于为该计算机配置的位置。因此,使用$ZTIMEZONE调整的本地时间将从配置的语言环境中获取其本地时间变化,而不是在$ZTIMEZONE中指定的时区。

使用格林威治子午线($ZTIMEZONE = 0)的时区计数来计算UTC时间。它与当地格林威治时间不同。格林威治标准时间(GMT)一词可能令人困惑;格林威治的当地时间与冬季的UTC相同。在夏季,它与UTC的差异为一小时。这是因为应用了称为英国夏令时的本地时间变体。

对于使用$ZTIMEZONE的函数和程序,经过的本地时间始终是连续的,但是时间值可能需要季节性调整以与本地时钟时间相对应。

设定时区

可以使用$ZTIMEZONE设置当前InterSystems IRIS进程使用的时区。设置$ZTIMEZONE不会更改默认的InterSystems IRIS时区或计算机的时区设置。

注意:更改$ZTIMEZONE特殊变量是为某些特殊情况设计的功能。更改$ZTIMEZONE并不是更改InterSystems IRIS用于本地日期/时间操作的时区的一致方法。除非已准备好处理所有导致的不一致的程序,否则不应更改$ZTIMEZONE特殊变量。

在某些平台上,更改时区可能比更改$ZTIMEZONE特殊变量更好。如果平台具有特定于进程的时区设置(例如POSIX系统上的TZ环境变量),则进行外部系统调用来更改特定于进程的时区可能比更改$ZTIMEZONE更好。在操作系统级别更改特定于流程的时区将更改UTC的本地时间偏移,并应用确定何时应用本地时变的相应算法。如果默认系统时区在北半球,而所需的过程时区在南半球,则这尤其重要。更改$ZTIMEZONE会将本地时间更改为与UTC偏移的新时区,但是确定何时应用本地时变的算法保持不变。

使用SET命令将$ZTIMEZONE设置为指定的带符号整数分钟数。数字的前导零和小数部分将被忽略。如果在设置$ZTIMEZONE时指定非数字值或无值,则InterSystems IRIS会将$ZTIMEZONE设置为0(格林威治子午线)。

例如,北美东部标准时间(EST)在格林威治以西五个小时。因此,要将当前的InterSystems IRIS流程设置为EST,则需要指定300分钟。要指定格林威治以东一小时的时区,请指定–60分钟。要指定格林威治本身,可以指定0分钟。

设置$ZTIMEZONE

  • 影响无参数的$NOW()当地时间值。它更改了$NOW()的时间部分,并且此时间更改也可以更改当前进程的$NOW()的日期部分。 $NOW()精确地反映了$ZTIMEZONE设置,其值未针对本地时变进行调整。
  • 影响$HOROLOG当地时间值。 $HOROLOG$ZTIMEZONE获取其时区值,然后季节性调整本地时间,例如夏令时。因此,$HOROLOG始终符合本地时钟时间,但全年的$HOROLOG经过时间不是连续的。
  • 影响%SYSTEM.Util类方法IsDST()UTCtoLocalWithZTIMEZONE()LocalWithZTIMEZONEtoUTC()
  • 不会影响$ZTIMESTAMP$ZHOROLOG值。
  • 不会影响$ZDATE$ZDATEH$ZDATETIME$ZDATETIMEH$ZTIME$ZTIMEH函数执行的日期和时间格式转换。
  • 不会影响$NOW(n)函数。
  • 不会影响%SYSTEM.Process类的FixedDate()类方法,该方法将$HOROLOG中的日期设置为固定值。

更改$ZTIMEZONE后发生以下异常:

  • $ZDATETIME($HOROLOG,1,7)通常返回UTC时间,但是如果$ZTIMEZONE已更改,它将不返回UTC时间。
  • 如果$ZTIMEZONE已更改,$ZDATETIME($HOROLOG,1,5)将不会返回正确的时区偏移量。
  • 如果$ZTIMEZONE已更改,则本地时间和UTC时间之间的$ZDATETIME($HOROLOG,-3)$ZDATETIMEH($ZTIMESTAMP,-3)转换将不正确。

其他时区方法

可以通过调用TimeZone()类方法来获取相同的时区信息,如下所示:

DHC-APP>WRITE $SYSTEM.SYS.TimeZone()
-480

可以使用tformat值为5或6的$ZDATETIME$ZDATETIMEH函数,将本地时间变化作为日期和时间字符串的一部分返回,如以下示例所示

DHC-APP>WRITE !,$ZDATETIME($HOROLOG,1,5)
 
02/10/2021T18:24:21+08:00

该字符串的最后一部分(+08:00)表示系统的本地时间变化设置,以格林威治子午线为单位,以小时和分钟为单位进行偏移。注意,这种变化不一定是时区偏移量。在上述情况下,时区位于格林威治(-5:00)西部5小时,但是本地时区(夏令时)将时区时间偏移一小时到-04:00。设置$ZTIMEZONE将更改$ZDATETIME($HOROLOG,1,5)返回的当前处理日期和时间,但不会更改系统本地时间变化设置。

$ZDATETIMEH使用时区设置

可以将$ZDATETIMEHdformat = -3一起使用,以将协调世界时(UTC)日期和时间值转换为本地时间。该函数将UTC值($ZTIMESTAMP)作为输入。它使用本地时区设置来返回相应的日期和时间,并在适用的情况下应用本地时变(例如夏时制)。

/// d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE()
ClassMethod ZTIMEZONE()
{
	SET clock=$HOROLOG
	SET stamp=$ZDATETIMEH($ZTIMESTAMP,-3)
	WRITE !,"本地/本地日期和时间: ",$ZDATETIME(clock,1,1,2)
	WRITE !,"UTC/本地日期和时间:   ",$ZDATETIME(stamp,1,1,2)
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE()
 
本地/本地日期和时间: 02/10/2021 18:31:27.00
UTC/本地日期和时间:   02/10/2021 18:31:27.94

使用$ZTIMEZONE的本地/UTC转换方法

%SYSTEM.Util类的两个类方法在本地日期和时间与UTC日期和时间之间进行转换:UTCtoLocalWithZTIMEZONE()LocalWithZTIMEZONEtoUTC()。这些方法受$ZTIMEZONE更改的影响。

/// d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE1()
ClassMethod ZTIMEZONE1()
{
	WRITE $SYSTEM.Util.UTCtoLocalWithZTIMEZONE($ZTIMESTAMP),!
	WRITE $HOROLOG,!
	WRITE $SYSTEM.Util.LocalWithZTIMEZONEtoUTC($H),!
	WRITE $ZTIMESTAMP
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE1()
65785,66819.613
65785,66819
65785,38019
65785,38019.614

示例

以下示例返回当前时区:

/// d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE2()
ClassMethod ZTIMEZONE2()
{
	SET zone=$ZTIMEZONE
	IF zone=0 {
		WRITE !,"时区是格林威治标准时间" 
	} ELSEIF zone>0 {
		WRITE !,"时区是 ",zone/60," 格林威治以西" 
	} ELSE {
		WRITE !,"时区是 ",(-zone)/60," 格林威治以东" 
	}
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE2()
 
时区是 8 格林威治以东

以下示例显示了设置时区可以更改日期和时间:

/// d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE3()
ClassMethod ZTIMEZONE3()
{
	SET zonesave=$ZTIMEZONE
	WRITE !,"当前时区的日期:  ",$ZDATE($HOROLOG)
	IF $ZTIMEZONE=0 {
		SET $ZTIMEZONE=720 
	} ELSEIF $ZTIMEZONE>0 {
		SET $ZTIMEZONE=($ZTIMEZONE-720) 
	} ELSE {
		SET $ZTIMEZONE=($ZTIMEZONE+720) 
	}
	WRITE !,"Date halfway around the world: ",$ZDATE($HOROLOG)
	WRITE !,"格林威治天文台的日期: ",$ZDATE($ZTIMESTAMP)
	SET $ZTIMEZONE=zonesave
}

DHC-APP> d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE3()
 
当前时区的日期:  02/10/2021
Date halfway around the world: 02/10/2021
格林威治天文台的日期: 02/10/2021

以下示例确定本地时间是否与时区时间相同:

/// d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE4()
ClassMethod ZTIMEZONE4()
{
	SET localnow=$HOROLOG, stamp=$ZTIMESTAMP
	WRITE !,"当地日期和时间: ",$ZDATETIME(localnow,1,1)
	SET clocksecs=$PIECE(localnow,",",2)
	SET stampsecs=$EXTRACT(stamp,7,11)-($ZTIMEZONE*60)
	IF clocksecs=stampsecs {
		WRITE !,"没有本地时间变量:" 
		WRITE !,"本地时间是时区时间" 
	} ELSE {
		IF clocksecs=stampsecs+3600 {
			WRITE !,"夏令时变体:"
			WRITE !,"从时区时间偏移1小时的本地时间" 
		} ELSE { 
			WRITE !,"当地时间和时区时间为"
			WRITE !,(clocksecs-stampsecs)/60," 分钟不同" 
		}
	}
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTIMEZONE4()
 
当地日期和时间: 02/10/2021 18:40:21
没有本地时间变量:
本地时间是时区时间
0
0 110
文章 姚 鑫 · 二月 20, 2021 6m read

第四十二章 Caché 变量大全 $ZTIMESTAMP 变量

包含协调世界时间格式的当前日期和时间。

大纲

$ZTIMESTAMP
$ZTS

描述

$ZTIMESTAMP包含协调的通用时间值形式的当前日期和时间。这是世界范围内的时间和日期标准;此值很可能与当地的时间(和日期)值不同。

$ZTIMESTAMP将日期和时间表示为以下格式的字符串:

ddddd,sssss.fff

其中ddddd是一个整数,指定自1840年12月31日起的天数;sssss是一个整数,指定自当天午夜以来的秒数,fff是一个可变的数字,指定小数秒。这种格式类似于$HOROLOG,只是$HOROLOG不包含分数秒。

假设当前日期和时间(世界协调时)如下:

2018-02-22 15:17:27.984

当时,$ZTIMESTAMP的值为:

64701,55047.984

$ZTIMESTAMP报告协调世界时(UTC),它独立于时区。因此,$ZTIMESTAMP提供了一个跨时区的统一时间戳。这可能不同于本地时间值和本地日期值。

$ZTIMESTAMP时间值是一个十进制数值,以秒及其分数为单位计算时间。分数秒的位数可能从零到九不等,具体取决于计算机时钟的精度。在视窗系统上,小数精度是三位小数;在UNIX系统上,它是六位十进制数字。$ZTIMESTAMP在此小数部分中抑制尾随零或尾随小数点。请注意,在午夜后的第一秒内,秒表示为0.fff(例如,0.123);这个数字不是ObjectScript规范形式(例如,. 123),这会影响这些值的字符串排序顺序。在执行排序操作之前,您可以添加一个加号(+)来强制将数字转换为规范形式。

比较了返回当前日期和时间的各种方法,如下所示:。

  • $ZTIMESTAMP包含以系统间IRIS存储($HOROLOG)格式表示的UTC日期和时间(小数秒)。小数秒以三位精度(在Windows系统上)或六位精度(在UNIX®系统上)表示。
  • $NOW返回当前进程的本地日期和时间;不应用本地时间变体(如夏令时)。不带参数值的$NOW根据$ZTIMEZONE特殊变量的值确定当地时区。带有参数值的$NOW返回与指定时区参数对应的时间和日期。$NOW(0)返回UTC日期和时间。忽略$ZTIMEZONE的值。$now返回InterSystems IRIS存储($HOROLOG)格式的日期和时间。它包括小数秒;小数位数是当前操作系统支持的最大精度。因此,$NOW(0)返回的UTC时间可能比$ZTIMESTAMP返回的秒精度高
  • $HOROLOG包含采用InterSystems IRIS存储格式的本地变量调整日期和时间。它不记录小数秒。$HOROLOG如何解析小数秒取决于操作系统平台:在Windows上,它将任何小数秒四舍五入到下一整秒。在UNIX®上,它会截断小数部分。

注意:比较当地时间和UTC时间时要谨慎:

  • 将UTC时间转换为本地时间的首选方法是使用$ZDATETIMEH(UTC,-3)函数。此函数根据当地时间变量进行调整。
  • 不能通过简单地添加或减去$ZTIMEZONE*60的值来转换本地时间和UTC时间。这是因为,在许多情况下,当地时间会根据当地时间的变化进行调整(例如夏令时,它会将当地时间季节性地调整一小时)。这些本地时间变量不会反映在$ZTIMEZONE中。
  • UTC时间是使用格林威治子午线上的时区计数来计算的。这和格林威治当地时间不一样。术语格林威治标准时间(GMT)可能会令人混淆;格林威治当地时间在冬季与UTC相同;在夏季,它与UTC相差一个小时。这是因为采用了当地时间变量,即英国夏令时(British Summer Time)。
  • 时区与UTC和本地时间的偏差(例如季节转换为夏令时)都会影响日期和时间。从本地时间转换为UTC时间(反之亦然)可能会更改日期和时间。

不能使用SET命令修改此特殊变量。尝试这样做会导致<SYNTAX>错误。

协调世界时转换

可以使用带有tFormat值7或8的$ZDATETIME$ZDATETIMEH函数将本地时间信息表示为协调世界时(UTC),如下例所示:

/// d ##class(PHA.TEST.SpecialVariables).ZTIMESTAMP()
ClassMethod ZTIMESTAMP()
{
	WRITE !,$ZDATETIME($ZTIMESTAMP,1,1,2)
	WRITE !,$ZDATETIME($HOROLOG,1,7,2)
	WRITE !,$ZDATETIME($HOROLOG,1,8,2)
	WRITE !,$ZDATETIME($NOW(),1,7,2)
	WRITE !,$ZDATETIME($NOW(),1,8,2)
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTIMESTAMP()
 
02/10/2021 09:46:32.53
02/10/2021T09:46:32.00Z
02/10/2021T09:46Z
02/10/2021T09:46:32.53Z
02/10/2021T09:46Z

上面的$ZDATETIME函数都以协调世界时(而不是本地时间)的形式返回当前时间。这些从本地时间转换的时间值可能不同,因为$Now不会针对本地时间变量进行调整;$ZTIMESTAMP$HOROLOG会针对本地时间变量进行调整,并可能在必要时相应地调整日期。$ZTIMESTAMP显示值与tFormat 7或8转换后的显示值不同。Tformat值7和8在时间值之前插入字母“T”,在时间值之后插入字母“Z”。此外,因为$HOROLOG TIME不包含小数秒,所以上例中精度为2的小数位用零填充。

通过使用以下语法形式之一调用Timestamp()类方法,可以获得与$ZTIMESTAMP相同的时间戳信息:

DHC-APP> WRITE !,$SYSTEM.SYS.TimeStamp()
 
65785,35395.629
DHC-APP>   WRITE !,##class(%SYSTEM.SYS).TimeStamp()
 
65785,35408.245

示例

下面的示例将$ZTIMESTAMP的值转换为本地时间,并将其与本地时间的两种表示形式进行比较:$NOW()$HOROLOG

/// d ##class(PHA.TEST.SpecialVariables).ZTIMESTAMP1()
ClassMethod ZTIMESTAMP1()
{
	SET stamp=$ZTIMESTAMP,clock=$HOROLOG,miliclock=$NOW()
	WRITE !,"当地日期和时间: ",$ZDATETIME(clock,1,1,2)
	WRITE !,"当地日期和时间: ",$ZDATETIME(miliclock,1,1,2)
	WRITE !,"UTC日期和时间:   ",$ZDATETIME(stamp,1,1,2)
	IF $PIECE(stamp,",",2) = $PIECE(clock,",",2) {
		WRITE !,"当地时间为UTC时间" }
	ELSEIF $PIECE(stamp,",") '= $PIECE(clock,",") {
		WRITE !,"时差影响日期" }
	ELSE {
		SET localutc=$ZDATETIMEH(stamp,-3)
		WRITE !,"UTC转换为本地: ",$ZDATETIME(localutc,1,1,2)
	}
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTIMESTAMP1()
 
当地日期和时间: 02/10/2021 17:54:46.00
当地日期和时间: 02/10/2021 17:54:46.93
UTC日期和时间:   02/10/2021 09:54:46.93
UTC转换为本地: 02/10/2021 17:54:46.93

下面的示例比较了$ZTIMESTAMP$HOROLOG返回的值,并显示了如何转换$ZTIMESTAMP的时间部分。(请注意,在此简单示例中,只针对本地时间变化(如夏令时)进行了一次调整。其他类型的局部变化可能会导致时钟秒和戳秒包含不可调和的值。)

/// d ##class(PHA.TEST.SpecialVariables).ZTIMESTAMP2()
ClassMethod ZTIMESTAMP2()
{
	SET stamp=$ZTIMESTAMP,clock=$HOROLOG
	WRITE !,"当地日期和时间: ",$ZDATETIME(clock,1,1,2)
	WRITE !,"UTC日期和时间:   ",$ZDATETIME(stamp,1,1,2)
	IF $PIECE(stamp,",") '= $PIECE(clock,",") {
		WRITE !,"时差影响日期" }
		SET clocksecs=$EXTRACT(clock,7,11)
		SET stampsecs=$EXTRACT(stamp,7,11)-($ZTIMEZONE*60)
		IF clocksecs=stampsecs {
			WRITE !,"没有本地时间变量" 
			WRITE !,"本地时间是时区时间" }
		ELSE {
			SET stampsecs=stampsecs+3600
		IF clocksecs=stampsecs {
			WRITE !,"夏令时变量:"
			WRITE !,"当地时间与时区时间相差1小时" }
		ELSE { 
			WRITE !,"由于当地时间不同,无法协调" 
		}
	}
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTIMESTAMP2()
 
当地日期和时间: 02/10/2021 17:58:16.00
UTC日期和时间:   02/10/2021 09:58:16.85
没有本地时间变量
本地时间是时区时间
0
0 159
文章 姚 鑫 · 二月 19, 2021 2m read

第四十一章 Caché 变量大全 $ZSTORAGE 变量

包含进程的最大可用内存。

大纲

$ZSTORAGE
$ZS

描述

$ZSTORAGE包含JOB的进程私有内存的最大内存量(以KB为单位)。此内存可用于局部变量、堆栈和其他表。此内存限制不包括例程目标代码的空间。此内存根据需要分配给进程,例如在分配数组时。

一旦将此内存分配给进程,通常在该进程退出之前不会释放它。但是,当大量内存被使用(例如,大于32MB)然后被释放时,系统间IRIS会尝试在可能的情况下将释放的内存释放回操作系统。

还可以使用$ZSTORAGE设置最大内存大小。例如,以下语句将作业的最大进程专用内存设置为524288 KB

SET $ZSTORAGE=524288

更改$ZSTORAGE会更改$STORAGE特殊变量的初始值,该变量包含进程的当前可用内存(以字节为单位)。

$ZSTORAGE的最大值为2147483647$ZSTORAGE默认值为262144$ZSTORAGE的最小值为128$ZSTORAGE值大于最大值或小于最小值会自动默认为最大值或最小值。$ZSTORAGE设置为整数值;InterSystems IRIS截断任何小数部分(如果指定)。

可以通过更改最大每进程内存(KB)系统配置设置来更改$ZSTORAGE默认值。在管理门户中,依次选择System Administration、Configuration、Systtem Configuration、Memory和Startup。可以根据需要增加每个进程的最大内存(KB),最大为2147483647 KB。更改每个进程的最大内存(KB)会更改后续启动的进程的$ZSTORAGE值;对当前进程的$ZSTORAGE值没有影响。

image

image

示例

以下示例将$ZSTORAGE设置为其最大值和最小值。尝试将$ZSTORAGE设置为小于最小值的值(16)时,会自动将$ZSTORAGE设置为其最小值(128):


/// d ##class(PHA.TEST.SpecialVariables).ZS()
ClassMethod ZS()
{
	SET $ZS=128
	WRITE "minimum storage=",$ZS,!
	SET $ZS=16
	WRITE "less than minimum storage=",$ZS,!
	SET $ZS=2147483647
	WRITE "maximum storage=",$ZS,!
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZS()
minimum storage=128
less than minimum storage=128
maximum storage=2147483647
0
0 92
文章 姚 鑫 · 二月 18, 2021 6m read

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

包含当前全局变量global引用。

大纲

$ZREFERENCE
$ZR

描述

$ZREFERENCE包含上次全局引用的名称和下标。这就是所谓裸指针。

注意:最后一个全局引用是最近访问的全局节点。通常,这是对全局的最新显式引用。但是,某些命令可能在内部使用$ORDER函数遍历全局下标(ZWRITE命令就是一个例子),或者它们可能在内部引用其他全局脚本。发生这种情况时,$ZREFERENCE包含上次访问的全局节点,该节点可能不是为命令指定的全局节点。

最后一个全局引用可以是全局(^myglob)或进程专用全局(^||myppg)。$ZREFERENCE以最初用于该变量的形式返回进程专用全局前缀,而不管随后对该变量使用哪个进程专用全局前缀。在接下来的$ZREFERENCE描述中,单词“global”指的是这两种类型的变量。

最后一个全局引用是命令或函数最近引用的全局。由于ObjectScript按从左到右的顺序执行操作,因此最后一个全局引用始终是最右侧的全局引用。当命令或函数使用多个参数时,最右侧参数中指定的全局参数是最后一个全局引用。当参数包含多个全局引用时,最右侧指定的全局引用是最后一个全局引用。即使使用圆括号来定义操作顺序,从左到右的严格顺序也是正确的。

当发出显式全局引用时,InterSystems IRIS会更新$ZREFERENCE。调用计算结果为全局引用的表达式(如局部变量)不会更新$ZREFERENCE

$ZREFERENCE包含最新的全局引用,即使此全局引用不成功。当命令引用未定义的全局时,会发出<unfined>错误,InterSystems IRIS会将$ZREFERENCE更新为该全局引用,就像定义了全局一样。此行为不受设置%SYSTEM.Process.Unfined()方法的影响。

$ZREFERENCE通常包含最新的全局引用,即使命令执行不成功。InterSystems IRIS在引用每个全局变量时更新$ZREFERENCE。例如,发出<Divide>错误(试图将数字除以0)的命令会将$ZREFERENCE更新为错误发生前命令中引用的最后一个全局变量。但是,<SYNTAX>错误不会更新$ZREFERENCE

长全局变量名称

如果全局名称超过31个字符(不包括全局前缀字符,如^),$ZREFERENCE将返回缩短为31个字符的全局名称。

裸全局变量引用

如果上一个全局引用是裸全局引用,则$ZREFERENCE包含当前裸全局引用的外部、可读的完整形式。下面的示例演示了这一点:

/// d ##class(PHA.TEST.SpecialVariables).ZREFERENCE()
ClassMethod ZREFERENCE()
{
	SET ^MyData(1)="fruit"
	SET ^MyData(1,1)="apples" ; 完整的全局变量引用
	SET ^(2)="oranges"        ; 裸全局变量引用, 映射 ^MyData(1,2)
	WRITE !,$ZREFERENCE       ; Returns "^MyData(1,2)"
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZREFERENCE()
 
^MyData(1,2)

扩展局变量引用

扩展局变量引用用于引用当前命名空间以外的命名空间中的全局。如果命令使用扩展全局引用引用全局变量,则$ZREFERENCE值将包含该扩展全局引用。在以下情况下,InterSystems IRIS返回扩展的全局引用:

  • 如果最后一个全局引用使用扩展引用来引用另一个命名空间中的全局。
  • 如果最后一个全局引用使用扩展引用来引用当前命名空间中的全局。
  • 如果最后一个全局引用是远程引用(远程系统上的全局引用)。

在所有情况下,$ZREFERENCE都以全部大写字母返回命名空间名称,而不管它在全局引用中是如何指定的。

更新$ZREFERENCE的操作

$ZREFERENCE特殊变量被初始化为空字符串(“”)。更改当前名称空间会将$ZREFERENCE重置为空字符串。

以下操作将$ZREFERENCE设置为最近引用的GLOBAL

  • 使用全局变量作为参数的命令或函数。如果它使用多个全局变量,则$ZREFERENCE被设置为全局变量的最右侧匹配项。(但请注意,$ORDER除外。)
  • 使用全局作为后置条件表达式的命令。
  • ZWRITE之后,InterSystems IRIS将$ZREFERENCE设置为指定全局引用的上次访问的下标节点。
  • 引用未定义的全局变量的命令或函数,它或者生成<unfined>错误,或者在$INCREMENT的情况下定义全局变量。

设置$ZREFERENCE

可以使用set命令设置此特殊变量,如下所示:

  • 设置为空字符串(“”)。这样做会删除裸指示器。如果下一个全局引用是裸全局引用,则InterSystems IRIS会发出<naked>错误。
  • 设置为有效的全局参照(已定义或未定义)。这会导致后续的裸引用使用设置的值,就好像它是最后一个实际的全局引用一样。

不能使用SET命令以其他方式修改$ZREFERENCE。尝试这样做会导致<SYNTAX>错误。

示例

下面的示例返回最后一个全局引用:

/// d ##class(PHA.TEST.SpecialVariables).ZREFERENCE1()
ClassMethod ZREFERENCE1()
{
   SET ^a(1,1)="Hello"  ; 完整的全局变量引用
   SET ^(2)=" world!"   ; 裸全局变量引用
   WRITE $ZREFERENCE
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZREFERENCE1()
^a(1,2)

下面的示例从几个不同的命令返回全局引用。请注意,WRITEZWRITE设置同一全局引用的不同表示形式。

/// d ##class(PHA.TEST.SpecialVariables).ZREFERENCE2()
ClassMethod ZREFERENCE2()
{
   SET (^barney,^betty,^wilma,^fred)="flintstone"
   WRITE !,"1:"_$ZREFERENCE
   KILL ^flies
   WRITE !,"2:"_$ZREFERENCE
   WRITE !,^fred
   WRITE !,"3:"_$ZREFERENCE,!
   ZWRITE ^fred
   WRITE !,"4:"_$ZREFERENCE
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZREFERENCE2()
 
1:^fred  // 按从左到右顺序设置的几个全局变量中的最后一个
2:^flies // KILL设置全局指示器,但没有全局要杀死的指示器
flintstone
3:^fred
^fred="flintstone"
 
4:^fred("")

下面的示例返回扩展的全局引用。请注意,名称空间名称始终以大写字母返回:

/// d ##class(PHA.TEST.SpecialVariables).ZREFERENCE3()
ClassMethod ZREFERENCE3()
{
	SET ^["samples"]a(1,1)="Hello"
	SET ^(2)=" world!"
	WRITE $ZREFERENCE
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZREFERENCE3()
^["SAMPLES"]a(1,2)

下面的示例返回最后一个全局引用。在本例中,它是^a(1),用作$LENGTH函数的参数:

/// d ##class(PHA.TEST.SpecialVariables).ZREFERENCE4()
ClassMethod ZREFERENCE4()
{
	SET ^a(1)="abcdefghijklmnopqrstuvwxyz"
	SET ^b(1)="1234567890"
	SET x=$LENGTH(^a(1))
	WRITE $ZREFERENCE
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZREFERENCE4()
^a(1)

下面的示例返回为$ZREFERENCE设置的值,就好像它是最后一个全局引用一样。在本例中,它是^a(1,1)

/// d ##class(PHA.TEST.SpecialVariables).ZREFERENCE5()
ClassMethod ZREFERENCE5()
{
	SET ^a(1,1)="abcdefghijklmnopqrstuvwxyz"
	SET ^b(1,1)="1234567890"
	WRITE !,^(1) ; 裸全局变量引用使用上一个全局变量:
	SET $ZREFERENCE="^a(1,1)"
	WRITE !,$ZREFERENCE
	WRITE !,^(1)  ; 裸全局变量使用$ZREFERENCE值,而不是最后一个全局值。.
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZREFERENCE5()
 
1234567890
^a(1,1)
abcdefghijklmnopqrstuvwxyz

下面的示例设置扩展的全局引用。请注意双引号:

/// d ##class(PHA.TEST.SpecialVariables).ZREFERENCE6()
ClassMethod ZREFERENCE6()
{
	KILL ^x
	WRITE !,$ZREFERENCE
	SET $ZREFERENCE="^[""samples""]a(1,2)"
	WRITE !,$ZREFERENCE
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZREFERENCE6()
 
^x
^["SAMPLES"]a(1,2)
0
0 91
文章 姚 鑫 · 二月 17, 2021 1m read

第三十七章 Caché 变量大全 $ZPARENT 变量

包含当前进程的父进程的ID

大纲

$ZPARENT
$ZP

描述

$ZPARENT包含使用JOB命令创建当前进程的父进程的ID。如果当前进程不是使用JOB命令创建的,则$ZPARENT包含0(零)。

不能使用SET命令修改此特殊变量。尝试这样做会导致<SYNTAX>错误。

第三十八章 Caché 变量大全 $ZPI 变量

包含pi的值。

大纲

$ZPI

描述

$zpi包含数值常量Pi到小数点后18位的值(3.141592653589793238)。

该值经常用于三角函数,例如正弦函数$ZSIN

第三十九章 Caché 变量大全 $ZPOS 变量

包含读取顺序文件期间的当前文件位置。

大纲

$ZPOS

描述

$ZPOS包含顺序文件读取期间的当前文件位置。如果没有正在进行的顺序文件读取,则$ZPOS包含0(零)。

当打开文件进行顺序读取时,每次从该设备读取都会将$ZPOS设置为文件中下一次读取的位置。$ZPOS值是读取、读取*或读取#n结束时的实际文件偏移量(以字节为单位)。用户在读取多字节字符集时必须适当小心。

可以使用$ZSEEK函数设置当前文件位置。不能使用SET命令修改此特殊变量。尝试这样做会导致<SYNTAX>错误。

0
0 60
文章 姚 鑫 · 二月 16, 2021 2m read

第三十六章 Caché 变量大全 $ZORDER 变量

包含下一个全局节点的值。

大纲

$ZORDER
$ZO

描述

$ZORDER包含当前全局引用之后的下一个全局节点的值(在$QUERY序列中,而不是$ORDER序列中)。如果没有下一个全局节点,访问$ZORDER将导致<unfined>错误,指示$ZORDER成功访问的最后一个全局节点。

不能使用SET命令修改此特殊变量。尝试这样做会导致<SYNTAX>错误。

示例

下面的示例使用WHILE循环重复调用$ZORDER以遍历一系列下标节点:

/// d ##class(PHA.TEST.SpecialVariables).ZORDER()
ClassMethod ZORDER()
{
	SET ^||a="groceries"
	SET ^||a(1)="fruit"
	SET ^||a(1,1)="apples"
	SET ^||a(1,2)="oranges"
	SET ^||a(3)="nuts"
	SET ^||a(3,1)="peanuts"
	SET ^||a(2)="vegetables"
	SET ^||a(2,1)="lettuce"
	SET ^||a(2,2)="tomatoes"
	SET ^||a(2,1,1)="iceberg"
	SET ^||a(2,1,2)="romaine"
	SET $ZERROR="unset"
	WRITE !,"last referenced: ",^||a(1,1)
	WHILE $ZERROR="unset" {
		WRITE !,$ZORDER 
	}
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZORDER()
 
last referenced: apples
oranges
vegetables
lettuce
iceberg
romaine
tomatoes
nuts
peanuts
 
  WRITE !,$ZORDER
          ^
<UNDEFINED>zZORDER+15^PHA.TEST.SpecialVariables.1 ^||a(3,1)

上面的示例从最后引用的全局变量(在本例中是进程私有全局变量)开始:^||a(1,1)$ZORDER不包含^||a(1,1)的值,但从该点开始向前工作。对$ZORDER的调用按以下顺序遍历下标树节点:(1,2),(2),(2,1),(2,1,1),(2,1,2),(2,2),(3),(3,1)。每次写入$ZORDER都会显示每个后续节点中的数据值。然后,它会耗尽节点并生成以下错误:^||a(3,1)。请注意,^||a(3,1)不是未定义的;之所以指定它,是因为$ZORDER在这个全局变量之后找不到另一个全局变量。

0
0 146
文章 姚 鑫 · 二月 15, 2021 3m read

第三十五章 Caché 变量大全 $ZNSPACE 变量

包含当前命名空间名称。

大纲

$ZNSPACE

描述

$ZNSPACE包含当前命名空间的名称。通过设置$ZNSPACE,可以更改当前名称空间。

要获取当前命名空间名称,请执行以下操作:

DHC-APP>SET ns=$ZNSPACE
 
DHC-APP>WRITE ns
DHC-APP

还可以通过调用%SYSTEM.SYS类的Namespace()方法来获取当前命名空间的名称,如下所示:

DHC-APP>SET ns=$SYSTEM.SYS.NameSpace()
 
DHC-APP>WRITE ns
DHC-APP

可以使用%SYS.Namespace类的Existes()方法测试命名空间是否已定义,如下所示:

DHC-APP>WRITE ##class(%SYS.Namespace).Exists("USER")
1
DHC-APP>WRITE ##class(%SYS.Namespace).Exists("LOSER")
0

对于UNIX®系统,默认命名空间建立为系统配置选项。对于Windows系统,它是使用命令行启动选项设置的。

命名空间名称不区分大小写。InterSystems IRIS始终以全大写字母显示显式名称空间名称,以全小写字母显示隐含的名称空间名称。

要获取指定进程的命名空间名称,请使用%SYS.ProcessQuery类的方法,如下例所示:

DHC-APP>WRITE ##CLASS(%SYS.ProcessQuery).%OpenId($JOB).NameSpaceGet()
DHC-APP

设置当前命名空间

可以使用ZNSPACE命令、SET $NAMESPACESET $ZNSPACE%cd实用程序更改当前名称空间。

  • 在终端命令提示符下,ZNSPACE命令是更改名称空间的首选方式。SET $ZNSPACE在功能上与ZNSPACE命令相同。

  • 在代码例程中,新建$NAMESPACE,然后设置$NAMESPACE = NAMESPACE是更改当前名称空间的首选方式。通过使用new $NAMESPACESET $NAMESPACE,可以建立一个名称空间上下文,该上下文在方法结束或发生意外错误时自动恢复到前一个名称空间。

可以使用SET $ZNSPACE更改进程的当前命名空间。将新命名空间指定为字符串文字或计算结果为带引号的字符串的变量或表达式。可以指定显式名称空间(“NAMESPACE”)或隐式名称空间(“^SYSTEM^DIR”或“^^DIR”)。

如果指定当前命名空间,则SET $ZNSPACE不执行任何操作,也不返回任何错误。如果指定了一个未定义的名称空间,则SET $ZNSPACE会生成一个<NAMESPACE>错误。

不能new $ZNSPACE特殊变量。

示例

在以下示例中,如果当前命名空间不是USER,则SET $ZNSPACE命令会将当前命名空间更改为USER。请注意,由于if测试,命名空间必须全部用大写字母指定。

/// d ##class(PHA.TEST.SpecialVariables).ZNSPACE()
ClassMethod ZNSPACE()
{
	SET ns="USER"
	IF $ZNSPACE=ns {
		WRITE !,"命名空间已经 ",$ZNSPACE 
	} ELSEIF 1=##class(%SYS.Namespace).Exists(ns) {
		WRITE !,"命名空间是 ",$ZNSPACE
		SET $ZNSPACE=ns
		WRITE !,"将命名空间设置为 ",$ZNSPACE 
	} ELSE { 
		WRITE !,ns," 不是定义的命名空间" 
	}
	QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZNSPACE()
 
命名空间是 DHC-APP
将命名空间设置为 USER

此示例要求UnnownUser已分配%DB_IRISSYS%DB_USER角色。

0
0 95
文章 姚 鑫 · 二月 14, 2021 1m read

第三十四章 Caché 变量大全 $ZNAME 变量

包含当前例程名称。

大纲

$ZNAME
$ZN

描述

$ZNAME包含在当前进程上执行的例程的名称。通常,这是ZLOAD加载的当前例程。如果当前没有执行任何例程,则$ZNAME包含空字符串。

当ZLOAD加载一个例程时,它将成为所有名称空间中当前进程的当前加载例程。因此,可以使用$ZNAME显示任何名称空间中当前加载的例程的名称,而不仅仅是加载该例程的名称空间。

例程名称区分大小写。

请注意,尝试ZLOAD例程失败会删除当前加载的例程,并将$ZNAME设置为空字符串。

不能使用SET命令修改此特殊变量。尝试这样做会导致<SYNTAX>错误。

$ZNAME值可以通过以下任何命令设置:

  • ZLOAD command
  • ZSAVE command
  • 无参数ZREMOVE命令(设置为空字符串)
  • DO command
  • GOTO command with ^routine
0
0 103
文章 姚 鑫 · 二月 13, 2021 2m read

第三十三章 Caché 变量大全 $ZMODE 变量

包含当前I/O设备打开参数。

大纲

$ZMODE
$ZM

描述

$ZMODE包含使用OPENUSE命令为当前设备指定的参数。返回的字符串包含用于以规范形式打开当前I/O设备的参数。这些参数值由反斜杠分隔符分隔。TCP/IP IO上的开放参数(如“M”)被规范化为“PSTE”“Y”“K”参数值始终放在最后。

不能使用SET命令修改此特殊变量。尝试这样做会导致<SYNTAX>错误。

示例

以下示例使用$ZMODE返回当前设备的参数:

/// d ##class(PHA.TEST.SpecialVariables).ZMODE()
ClassMethod ZMODE()
{
	WRITE !,"当前的开放模式有: ",$PIECE($ZMODE,"\")
	WRITE !,"NLS集合为: ",$PIECE($ZMODE,"\",2)
	WRITE !,"网络编码是: ",$PIECE($ZMODE,"\",4)
}
  • 终端
DHC-APP> d ##class(PHA.TEST.SpecialVariables).ZMODE()
 
当前的开放模式有: RY
NLS集合为: Latin1
网络编码是: GB18030
  • 控制台
d ##class(PHA.TEST.SpecialVariables).ZMODE()

当前的开放模式有: SADY
NLS集合为: Latin1
网络编码是: RAW

下面的示例使用Use命令设置当前设备的参数。它在USE命令前后使用$ZMODE检查当前参数。为了测试是否设置了特定参数,此示例使用带有反斜杠分隔符的$PIECE函数,并使用CONTAINS运算符([)测试值。

/// d ##class(PHA.TEST.SpecialVariables).ZMODE1()
ClassMethod ZMODE1()
{
Zmodetest
	WRITE !, $ZMODE
	IF $PIECE($ZMODE,"\")["S" {
		WRITE !, "S is set"  
	} ELSE {
		WRITE !, "S is not set" 
	}
	USE 0:("":"IS":$CHAR(13,10))
	WRITE !, $ZMODE
	IF $PIECE($ZMODE,"\")["S" {
		WRITE !, "S is set"  
	} ELSE {
		WRITE !, "S is not set" 
	}
	QUIT
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZMODE1()
 
RY\Latin1\K\GB18030\
S is not set
SIRY\Latin1\K\GB18030\
S is set
0
0 116
文章 姚 鑫 · 二月 12, 2021 2m read

第三十二章 Caché 变量大全 $ZJOB 变量

包含JOB状态信息。

大纲

$ZJOB
$ZJ

描述

$ZJOB包含一个数字,其中每个位代表作业状态的一个特定方面。 $ZJOB返回一个整数,该整数由设置的状态位的总和组成。例如,如果$ZJOB = 5,则表示设置了1位和4位。

要测试单个$ZJOB位设置,可以使用整数除(\)和模(#)运算符。例如,$ZJOB\x#2,其中x是位号。下表显示了位的布局(按位的位置值)、其设置和含义:

BitSet toMeaning
11Job 从终端提示符启动。
10Jobroutine开始.
21JobJOB命令启动.
20Job 通过在终端提示下登录或从例程登录开始。
41<INTERRUPT> 已启用。 CTRL-C可以中断正在运行的程序。
40<INTERRUPT>被禁用,但已通过OPENUSE命令显式启用了<INTERRUPT>的终端行除外。
81<Interrupt>已收到并挂起。
80未收到<Interrupt>。值8由OPENUSE命令以及CTRL-C引起的错误陷阱清除。
10241无论其他条件如何,日志记录都会被禁用。
10240如果其他条件指示日志记录,则为此作业启用日志记录。

不能使用SET命令修改此特殊变量。尝试执行此操作会导致<SYNTAX>错误。

示例

以下示例以整数形式返回$ZJOB

DHC-APP>WRITE $ZJOB
5

以下示例返回每个$ZJOB位值:

/// d ##class(PHA.TEST.SpecialVariables).ZJOB()
ClassMethod ZJOB()
{
	WRITE "   bit 1=",$ZJOB\1#2,!
	WRITE "   bit 2=",$ZJOB\2#2,!
	WRITE "   bit 4=",$ZJOB\4#2,!
	WRITE "   bit 8=",$ZJOB\8#2,!
	WRITE "bit 1024=",$ZJOB\1024#2
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZJOB()
   bit 1=1
   bit 2=0
   bit 4=1
   bit 8=0
bit 1024=0

也可以使用$ZJOB#2返回位1。

1
0 142
文章 姚 鑫 · 二月 11, 2021 1m read

第三十一章 Caché 变量大全 $ZIO 变量

包含有关当前终端I / O设备的信息。

$ZIO
$ZI

描述

$ZIO包含有关当前I / O设备的信息。

对于作为终端的终端设备,$ZIO包含字符串TRM:。如果当前终端设备是远程连接的,则$ZIO包含有关远程连接的信息。

对于通过TELNET连接的终端设备,$ZIO包含以下内容:host | port

参数描述
host远程主机IP地址,格式为IPv4:nnn.nnn.nnn.nnn(其中nnn是十进制数字)或IPv6格式:h:h:h:h:h:h:h:h,其中h为十六进制数。
por远程IP端口号。

这两个值由竖线字符分隔。例如127.0.0.1 | 23

如果当前设备不是终端:

  • 如果是文件,则$ZIO包含文件的完整规范路径名。
  • 如果不是文件,则$ZIO包含空字符串。

以下示例返回当前设备信息:

/// d ##class(PHA.TEST.SpecialVariables).ZIO()
ClassMethod ZIO()
{
   SET x = $CASE($ZIO,
				"TRM:":"终端",
				"CON:":"控制台",
				"":"既不是终端也不是文件")
   WRITE "当前设备是 ",x
}

image

image

0
0 128
文章 姚 鑫 · 二月 10, 2021 1m read

第三十章 Caché 变量大全 $ZHOROLOG 变量

包含自Caché启动以来经过的秒数。

大纲

$ZHOROLOG
$ZH

描述

$ZHOROLOG包含自最近的Caché启动以来经过的秒数。这是一个计数,与时钟变化和日期范围无关。该值表示为浮点数,表示秒和秒的分数。小数位数与平台有关。 $ZHOROLOG在此小数部分截断尾随零。

不能使用SET命令修改此特殊变量。尝试这样做会导致<SYNTAX>错误。

注意:由于Windows操作系统的限制,使Windows系统进入休眠或待机模式可能会导致$ZHOROLOG返回不可预测的值。此问题不会影响$HOROLOG$ZTIMESTAMP值。

示例

本示例输出当前的$ZHOROLOG值。

DHC-APP>WRITE $ZHOROLOG
94657.76444

以下示例说明如何使用$ZHOROLOG计时事件并进行基准测试。本示例通过100次执行对应用程序进行计时,然后找到平均运行时间。

/// d ##class(PHA.TEST.SpecialVariables).ZHOROLOG()
ClassMethod ZHOROLOG()
{
Cycletime
	SET start=$ZHOROLOG
	FOR i=1:1:100 { DO Myapp }
	SET end=$ZHOROLOG
	WRITE !,"平均运行时间是 ",(end-start)/100," 秒"
	QUIT
Myapp
	WRITE !,"执行我的申请"
	; 应用程序代码在这里
	QUIT
}

DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZHOROLOG()
 
执行我的申请
...
执行我的申请
平均运行时间是 .00000081 秒
0
0 93
文章 姚 鑫 · 二月 9, 2021 9m read

第二十九章 Caché 变量大全 $ZERROR 变量

包含上一个错误的名称和位置。

大纲

$ZERROR
$ZE 

描述

$ZERROR包含最新错误的名称,最新错误的位置(在适用的情况下)以及(对于某些错误代码而言)有关导致错误的原因的其他信息。 $ZERROR始终包含相应语言模式的最新错误。

$ZERROR值旨在错误后立即使用。由于$ZERROR值可能不会在例程调用中保留,因此希望保留$ZERROR值以供以后使用的用户应将其复制到变量中。强烈建议用户在使用后立即将$ZERROR设置为空字符串(“”)。

$ZERROR中包含的字符串可以是以下任何一种形式:

<error>
<error>entryref
<error> info
<error>entryref info
  • <error> 错误名称。错误名称始终以全部大写字母返回,并用尖括号括起来。它可能包含空格。
  • entryref 对发生错误的代码行的引用。它由标签名称和距该标签的行偏移量组成,后跟^和程序名称。此entryref紧跟在错误名称的右尖括号之后。从终端调用$ZERROR时,此entryref信息没有意义,因此不会返回。对最近使用ZLOAD加载到例程缓冲区中的例程的引用。
  • info 特定于某些错误类型的附加信息(见下表)。此信息与<error><error>entryref之间用空格分隔。如果有多个组件要提供信息,则用逗号分隔。

例如,一个程序(名为zerrortest)包含以下例程(名为ZerrorMain),该例程试图写入fred(一个未定义的局部变量)的内容:

/// d ##class(PHA.TEST.SpecialVariables).ZERROR()
ClassMethod ZERROR()
{
ZerrorMain
	TRY {
	SET $ZERROR=""
	WRITE "$ZERROR = ",$ZERROR,!
	WRITE fred }
	CATCH {
	WRITE "$ZERROR = ",$ZCVT($ZERROR,"O","HTML")
	}
}
DHC-APP> d ##class(PHA.TEST.SpecialVariables).ZERROR()
$ZERROR =
$ZERROR = &lt;UNDEFINED&gt;zZERROR+5^PHA.TEST.SpecialVariables.1 *fred

在上面的示例中,第一个$ZERROR包含一个空字符串(“”),因为自从$ZERROR重置为空字符串以来没有发生任何错误。尝试写入未定义的变量会设置$ZERROR并将其抛给CATCH块。此$ZERROR包含ZerrorMain+4^zerrortest*fred,指定错误的名称、位置和特定于该类型错误的附加信息。在本例中,附加信息是未定义的局部变量fred的名称;星号前缀表示它是局部变量。(请注意,本例中使用$ZCVT($ZERROR,“O”,“HTML”),因为Caché错误名称用尖括号括起来,并且本例从Web浏览器运行。)

Entryref可能如下所示:

  • ZerrorMain+4^zerrortest--程序zerrortest中标签ZerrorMain的4行偏移量
  • ZerrorMain^zerrortest--在程序zerrortest中没有与标签ZerrorMain的偏移量;标签行中出现错误
  • +3^zerrortest--从程序zerrortest开始的3行偏移量;错误行前面没有标签

$ZERROR值的最大长度为512个字符。超过该长度的值将被截断为512个字符。

AsSystemError() Method

%Exception.SystemException类的AsSystemError()方法返回与$ZERROR相同的值。下面的示例显示了这一点:

/// d ##class(PHA.TEST.SpecialVariables).ZERROR1()
ClassMethod ZERROR1()
{
	TRY {
		KILL mylocal
		WRITE mylocal
	}
	CATCH myerr {
		WRITE "AsSystemError is: ",myerr.AsSystemError(),!
		WRITE "$ZERROR is:       ",$ZERROR
	}
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZERROR1()
AsSystemError is: <UNDEFINED>zZERROR1+3^PHA.TEST.SpecialVariables.1 *mylocal
$ZERROR is:       <UNDEFINED>zZERROR1+3^PHA.TEST.SpecialVariables.1 *mylocal

Try/Catch异常处理块结构中,AsSystemError()$ZERROR更可取,因为$ZERROR可能会被异常处理期间发生的错误覆盖。

有关某些错误的其他信息

当发生某些类型的错误时,$ZERROR将以以下格式返回错误:

<ERRORCODE>entryref info

INFO组件包含有关错误原因的附加信息。下表列出了错误列表,其中包括附加信息和该信息的格式。错误代码与INFO组件之间用空格字符分隔。

错误代码信息组件
<UNDEFINED>未定义变量的名称(包括使用的任何下标)。这可以是局部变量、进程私有全局属性、全局属性或多维类属性。局部变量名称以星号作为前缀。多维属性名以句点开头,以区别于本地变量名。通过设置%SYSTEM.Process.Unfined()方法,可以更改Caché行为,以便在引用未定义的变量时不会生成<unfined>错误。
<SUBSCRIPT>错误的下标引用:生成错误的行引用(例程和行偏移)、下标变量以及错误的下标级别。对于结构化系统变量(SSVN),仅提供行引用(例程和行偏移量)。通过设置%SYSTEM.Process.NullSubscript()方法,可以更改默认行为,以便在引用字符串下标为空的全局变量时不会生成错误。局部变量不允许使用空字符串下标。
<NOROUTINE>前缀为星号,即引用的例程名称。
<CLASS DOES NOT EXIST>前缀为星号,即引用的类名。
<PROPERTY DOES NOT EXIST>前缀为星号(引用属性的名称),后跟逗号分隔符和应该在其中的类名。
<METHOD DOES NOT EXIST>前缀是星号,即调用的方法的名称,后跟逗号分隔符和应该在其中的类名。
<PROTECT>全局引用的名称和包含全局引用的目录的名称,用逗号分隔。
<THROW>前缀为星号、对象名称,后跟DisplayString()方法返回的值。
<COMMAND>当不在事务中调用TCOMMIT时,INFO组件为*NoTransaction。当调用不返回值的用户定义函数时,INFO组件是一条消息,其中包含本应返回值的命令的位置。
<DIRECTORY>以星号为前缀的无效目录的完整路径名。
<FRAMESTACK><FRAMESTACK>错误终止进程时,带有附加信息的<FRAMESTACK>错误将作为消息写入mgr/cconsole.log。信息性消息显示已终止进程的进程ID(PID)和产生错误的行引用(例程和行偏移量)。例如:`(PID)0<FRAMESTACK>at+13^

例程(或方法)本地变量的名称以及未定义例程、类、属性和方法的名称都以星号(*)为前缀。进程-专用全局变量由其^||前缀标识。全局变量由它们的^(插入符号)前缀标识。类名以其%前缀形式表示。

以下示例显示了指定错误原因的其他错误信息。在每种情况下,指定的项都不存在。请注意,生成的错误的INFO组件与错误名称之间用空格分隔。星号(*)表示局部变量、类、属性或方法。插入符号(^)表示全局,^||表示进程私有全局。

<unfined>错误示例:

/// d ##class(PHA.TEST.SpecialVariables).ZERROR2()
ClassMethod ZERROR2()
{
UndefTest ;
	SET $NAMESPACE="SAMPLES"
	KILL x,abc(2)
	KILL ^xyz(1,1),^|"USER"|xyz(1,2)
	KILL ^||ppg(1),^||ppg(2)
	TRY {
		WRITE x 
	}             // 未定义的局部变量
	CATCH {
		WRITE $ZERROR,! 
	}                           
	TRY {
		WRITE abc(2)
	}         // 未定义的下标局部变量
	CATCH {
		WRITE $ZERROR,! 
	}
	TRY {
		WRITE ^xyz(1,1) 
	}          // 未定义的全局变量
	CATCH {
		WRITE $ZERROR,! 
	}  
	TRY {
		WRITE ^|"USER"|xyz(1,2) 
	}  // 另一个命名空间中未定义的全局变量
	CATCH {
		WRITE $ZERROR,!
	}
	TRY {
		WRITE ^||ppg(1) 
	}     // 未定义的进程专用全局变量
	CATCH {
		WRITE $ZERROR,! 
	}
	TRY {
		WRITE ^|"^"|ppg(2) 
	}  // 未定义的进程专用全局变量
	CATCH {
		WRITE $ZERROR,! 
	}
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZERROR2()
<UNDEFINED>zZERROR2+7^PHA.TEST.SpecialVariables.1 *x
<UNDEFINED>zZERROR2+13^PHA.TEST.SpecialVariables.1 *abc(2)
<UNDEFINED>zZERROR2+19^PHA.TEST.SpecialVariables.1 ^xyz(1,1)
<UNDEFINED>zZERROR2+25^PHA.TEST.SpecialVariables.1 ^xyz(1,2)
<UNDEFINED>zZERROR2+31^PHA.TEST.SpecialVariables.1 ^||ppg(1)
<UNDEFINED>zZERROR2+37^PHA.TEST.SpecialVariables.1 ^||ppg(2)

<SUBSCRIPT>错误的示例:

/// d ##class(PHA.TEST.SpecialVariables).ZERROR3()
ClassMethod ZERROR3()
{
SubscriptTest ;
	DO $SYSTEM.Process.NullSubscripts(0)
	KILL abc,xyz
	TRY {
		SET abc(1,2,3,"")=123 
	}
	CATCH {
		WRITE $ZERROR,! 
	}
	TRY {
		SET xyz(1,$JUSTIFY(1,1000))=1
	}
	CATCH {
		WRITE $ZERROR,!
	}
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZERROR3()
<SUBSCRIPT>zZERROR3+5^PHA.TEST.SpecialVariables.1 *abc() Subscript 4 is ""
<SUBSCRIPT>zZERROR3+11^PHA.TEST.SpecialVariables.1 *xyz() Subscript 2 > 511 chars
 

<NOROUTINE>错误的示例:

/// d ##class(PHA.TEST.SpecialVariables).ZERROR4()
ClassMethod ZERROR4()
{
NoRoutineTest ;
	KILL ^NotThere
	TRY {
		DO ^NotThere 
	}
	CATCH {
		WRITE $ZERROR,! 
	}
	TRY {
		JOB ^NotThere 
	}
	CATCH {
		WRITE $ZERROR,! 
	}
	TRY {
		GOTO ^NotThere 
	}
	CATCH {
		WRITE $ZERROR,! 
	}
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZERROR4()
<NOROUTINE>zZERROR4+4^PHA.TEST.SpecialVariables.1 *NotThere
<NOROUTINE>zZERROR4+10^PHA.TEST.SpecialVariables.1 *NotThere
<NOROUTINE>zZERROR4+16^PHA.TEST.SpecialVariables.1 *NotThere

对象错误的示例:

DHC-APP>DO $SYSTEM.SQL.MyMethod()
 
DO $SYSTEM.SQL.MyMethod()
^
<METHOD DOES NOT EXIST> *MyMethod,%SYSTEM.SQL
DHC-APP>WRITE $SYSTEM.XXQL.MyMethod()
 
WRITE $SYSTEM.XXQL.MyMethod()
^
<CLASS DOES NOT EXIST> *%SYSTEM.XXQL
DHC-APP>SET x=##class(%SQL.Statement).%New()
 
DHC-APP>WRITE x.MyProp
 
WRITE x.MyProp
^
<PROPERTY DOES NOT EXIST> *MyProp,%SQL.Statement

<PROTECT>错误的示例(在Windows上):

    // 用户没有%SYS名称空间的访问权限
    SET x=^|"%SYS"|var
    <PROTECT> ^var,c:\intersystems\cache\mgr\

调用用户定义函数时的<command>错误示例。在本例中,MyFunc Quit命令不返回值。这将生成一个<command>错误,其中entryref指定$$MyFunc调用的位置,INFO消息指定QUIT命令的位置:

/// d ##class(PHA.TEST.SpecialVariables).ZERROR5()
ClassMethod ZERROR5()
{
Main 
	TRY {
		KILL x
		SET x=$$MyFunc(7,10)
		WRITE "returned value is ",x,!
		RETURN
	}
	CATCH {  
		WRITE "$ZERROR = ",$ZCVT($ZERROR,"O","HTML"),!
	}
MyFunc(a,b)
   SET c=a+b
   QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZERROR5()
$ZERROR = &lt;COMMAND&gt;zZERROR5+4^PHA.TEST.SpecialVariables.1 *Function must return a value at zZERROR5+13^PHA.TEST.SpecialVariables.1

使用PUBLIC关键字将函数作为过程调用时,出现相同的<command>错误:

Main 
	TRY {
		KILL x
		SET x=$$MyFunc(7,10)
		WRITE "returned value is ",x,!
		RETURN
	}
	CATCH {  
		WRITE "$ZERROR = ",$ZCVT($ZERROR,"O","HTML"),! 
	}
MyFunc(a,b) PUBLIC {
   SET c=a+b
   QUIT 
   }

<DIRECTORY>错误示例(在Windows上):

/// d ##class(PHA.TEST.SpecialVariables).ZERROR6()
ClassMethod ZERROR6()
{
	TRY { 
		SET prev=$SYSTEM.Process.CurrentDirectory("bogusdir")
		WRITE "previous directory: ",prev,!
		RETURN 
	}
	CATCH { 
		WRITE "$ZERROR = ",$ZCVT($ZERROR,"O","HTML"),! 
		QUIT 
	}
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZERROR6()
$ZERROR = &lt;DIRECTORY&gt;zCurrentDirectory+2^%SYSTEM.Process.1 *e:\dthealth\db\dthis\data\bogusdir\

5.1版本之前的错误处理代码

在Caché5.1和后续版本的这些错误代码中添加INFO组件的结果是,假设$ZERROR中的字符串格式的5.1版本之前的错误处理例程可能需要重新设计才能像以前一样工作。例如,以下内容在5.1版中将不再有效:

WRITE "Error line: ", $PIECE($ZERROR, ">", 2)

并应更改为类似以下内容:

WRITE "Error line: ", $PIECE($PIECE($ZERROR, ">", 2), " ", 1)

注意

ZLOAD和错误消息

ZLOAD操作之后,加载到例程缓冲区中的例程的名称出现在后续错误消息的entryref部分。这将在整个过程中持续存在,或者直到使用ZREMOVE删除,或者被另一个ZLOAD删除或替换。以下终端示例显示例程缓冲区内容的此显示:

SAMPLES>ZLOAD Sample.Person.1
SAMPLES>WRITE 6/0
<DIVIDE>^Sample.Person.1
SAMPLES>WRITE fred
<UNDEFINED>^Sample.Person.1 *fred
SAMPLES>WRITE ^fred
<UNDEFINED>^Sample.Person.1 ^fred
SAMPLES>ZNAME "USER"
USER>WRITE 7/0
<DIVIDE>^Sample.Person.1
USER>ZREMOVE
USER>WRITE ^fred
<UNDEFINED> ^fred

$ZERROR和程序栈

$ZERROR字符串的<error>部分包含最新的错误消息。$ZERROR字符串的entryref部分的内容反映了最近错误的堆栈级别。以下终端会话试图调用无意义的命令gobbledegook,导致<SYNTAX>错误。它还运行ZerrorMain(上面指定),产生$ZERROR<unfined>。此终端会话期间的后续$ZERROR值反映了此程序调用,如下所示:

SAMPLES>gobbledegook
SAMPLES>WRITE $ZERROR
<SYNTAX>
SAMPLES>DO ^zerrortest
SAMPLES>WRITE $ZERROR
<UNDEFINED>ZerrorMain+2^zerrortest *FRED
SAMPLES 2d0>gobbledegook
SAMPLES 2d0>WRITE $ZERROR
<SYNTAX>^zerrortest
SAMPLES 2d0>QUIT
SAMPLES>WRITE $ZERROR
<SYNTAX>^zerrortest
SAMPLES>gobbledegook
SAMPLES>WRITE $ZERROR
<SYNTAX>

设置$ZTRAP时的$ZERROR操作

发生错误并设置$ZTRAP时,Caché在$ZERROR中返回错误消息,并分支到为$ZTRAP指定的错误陷阱处理程序

设置$ZERROR

只有在Caché模式下,才能使用set命令将$ZERROR设置为最多512个字符的值。长度超过512个字符的值将被截断为512。

强烈建议在错误处理后将$ZERROR重置为空字符串(“”)。

0
0 119