清除过滤器
文章
姚 鑫 · 五月 30, 2021
# 第十一章 发送和接收IBM WebSphere MQ消息
InterSystems IRIS为IBM `WebSphere MQ`提供了一个接口,可以使用该接口在InterSystems IRIS和IBM `WebSphere MQ`的消息队列之间交换消息。要使用此接口,必须能够访问IBM `WebSphere MQ`服务器,并且IBM `WebSphere MQ`客户端必须与InterSystems IRIS在同一台计算机上运行。
该接口由`%Net.MQSend`和`%Net.MQRecv`类组成,这两个类都是`%Net.abstractMQ`的子类。这些类使用由InterSystems IRIS在所有合适的平台上自动安装的动态链接库。(这是Windows上的`MQInterface.dll`;其他平台的文件扩展名不同。)。反过来,InterSystems IRIS动态链接库需要IBM `WebSphere MQ`动态链接库。
该界面仅支持发送和接收文本数据,不支持二进制数据。
# 使用IBM WebSphere MQ的RIS接口
通常,要使用IBM `WebSphere MQ`的InterSystems IRIS接口,请执行以下操作:
1. 确保有权访问`IBM WebSphereMQv7.x`或更高版本。具体而言:
- IBM `WebSphere MQ`客户端必须与InterSystems IRIS安装在同一台计算机上。请注意,安装程序会根据需要更新`PATH`环境变量并添加其他系统变量。
- 确保在安装客户端后重新启动计算机,以便InterSystems IRIS能够识别该客户端。
- 客户端必须能够访问IBM `WebSphere MQ`服务器。
- 将用来访问服务器的用户名必须具有使用队列管理器和计划使用的队列的权限。
2. 创建`%Net.MQSend`或`%Net.MQRecv`的新实例,具体取决于要发送还是接收消息。
3. 连接到IBM `WebSphere MQ`服务器。执行此操作时,您需要提供以下信息:
- 队列管理器的名称。
- 要使用的队列的名称。
- 与该队列通信的通道。可以指定IBM `WebSphere MQ`服务器的通道名称、传输机制以及IP地址和端口。
如果正在使用IBM `WebSphere MQ`的身份验证功能,还可以提供名称和密码。
4. 调用`%Net.MQSend`或`%Net.MQRecv`的相应方法来发送或接收消息。
注意:要在64位Linux平台上使用IBM `Websphere MQ`,必须设置`LD_LIBRARY_PATH`以包括`MQ`库的位置。因为必须为任何使用`MQ`接口的InterSystems IRIS进程设置路径,所以如果正在运行后台进程,则必须在启动InterSystems IRIS之前设置该路径,并在运行IRIS终端之前在任何UNIX®终端中设置该路径。
## 获取错误代码
`%Net.MQSend`和`%Net.MQRecv`的方法如果成功则返回1,如果不成功则返回0。在出现错误的情况下,调用`%GetLastError()`方法,该方法返回IBM `WebSphere MQ`给出的最后一个原因代码。
# 创建连接对象
在可以通过IBM `WebSphere MQ`发送或接收消息之前,必须创建一个`Connection`对象,该对象可以建立到队列管理器的连接、打开通道和打开队列以供使用。有两种方法可以做到这一点:
- 可以使用`%Init`方法,该方法接受指定所有所需信息的参数。
- 可以在首次设置指定所有所需信息的属性后使用`%Connect`方法。
## 使用%Init()方法
要使用`%Init()`方法创建连接对象,请执行以下操作:
1. 创建`%Net.MQSend`(如果要发送消息)或`%Net.MQRecv`(如果要接收消息)的实例。本主题将此实例称为连接对象。
注意:如果收到 ``错误,则表示缺少动态链接库,并且`messages.log`文件(在系统管理器的目录中)有更多详细信息。
2. 如果需要身份验证,请设置`Connection`对象的以下属性:
- 用户名-指定有权使用此频道的用户名。
- 密码-指定给定用户的密码。
3. 调用`Connection`对象的`%Init()`方法。此方法按顺序接受以下参数。
a. 指定队列名称的字符串;这应该是指定队列管理器的有效队列。
b. 指定队列管理器的字符串;它应该是IBM `WebSphere MQ`服务器上的有效队列管理器。
如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认队列管理器。或者,如果IBM `WebSphere MQ`已配置为队列管理器由队列名称确定,则系统将使用适合给定队列名称的队列管理器。
c. 指定频道规范的字符串,格式如下:
```java
"channel_name/transport/host_name(port)"
```
这里,`channel_name`是要使用的通道的名称,`Transport`是通道使用的传输,`host_name`是运行IBM `WebSphere MQ`服务器的服务器名称(或IP地址),`port`是该通道应该使用的端口。
传输可以是以下之一:`TCP`、`LU62`、`NETBIOS`、`SPX`
例如:
```java
"CHAN_1/TCP/rodan(1401)"
```
```java
"CHAN_1/TCP/127.0.0.1(1401)"
```
如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认通道规范。或者,如果系统已配置为通道由队列名称确定,则系统使用适合给定队列名称的通道。
d. 一个可选字符串,它指定要向其中写入错误消息的日志文件。默认情况下,不进行日志记录。
4. 检查`%Init()`方法返回的值。如果该方法返回1,则表明连接已成功建立,可以使用`Connection`对象发送或接收消息(具体取决于使用的类)。
## 使用%Connect()方法
在某些情况下,可能更喜欢单独指定连接的所有详细信息。为此,请使用`%Connect()`方法,如下所示:
1. 创建`%Net.MQSend`(如果要发送消息)或`%Net.MQRecv`(如果要接收消息)的实例。如前所述,本主题将此实例称为连接对象。
注意:如果收到`` 错误,则表示缺少动态链接库,并且`messages.log`文件(在系统管理器的目录中)有更多详细信息。
2. 设置`Connection`对象的以下属性:
- `QName`-(必选)指定队列名称;这应该是指定队列管理器的有效队列。
- `QMgr`-指定要使用的队列管理器;它应该是IBM `WebSphere MQ`服务器上的有效队列管理器。
如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认队列管理器。或者,如果IBM `WebSphere MQ`已配置为队列管理器由队列名称确定,则系统将使用适合给定队列名称的队列管理器。
3. 或者,通过设置`Connection`对象的以下属性来指定要使用的频道:
- `Connection` - 指定IBM `WebSphere MQ`服务器的主机和端口。例如:`"127.0.0.1:1401"`。
- `Channel` - 指定要使用的频道的名称。这必须是IBM WebSphere MQ服务器上的有效通道。
- `Transport` - 指定通道使用的传输。此属性可以是以下之一: `"TCP"`, `"LU62"`, `"NETBIOS"`, `"SPX"`
如果省略这些参数,系统将使用IBM `WebSphere MQ`中配置的默认通道规范。或者,如果系统已配置为通道由队列名称确定,则系统使用适合给定队列名称的通道。
4. 如果频道需要身份验证,请设置`Connection`对象的以下属性:
- 用户名-指定有权使用此频道的用户名。
- 密码-指定给定用户的密码。
5. 调用`Connection`对象的`%ErrLog()`方法。此方法接受一个参数,即要用于此连接对象的日志文件的名称。
6. 检查`%ErrLog()`方法返回的值。
7. 调用`Connection`对象的`%Connect()`方法。
8. 检查`%Connect()`方法返回的值。如果该方法返回1,则表明连接已成功建立,可以使用`Connection`对象发送或接收消息(具体取决于您使用的类)。
# 指定字符集(CCSID)
要设置用于消息转换的字符集,请调用`Connection`对象的`%SetCharSet()`方法。指定在IBM `WebSphere MQ`中使用的整数编码字符集`ID(CCSID)`。
- 如果正在发送消息,这应该是这些消息的字符集。如果不指定字符集,则MQ系统假定消息使用为`MQ`客户端指定的默认字符集。
- 如果要检索邮件,则这是要将这些邮件翻译为的字符集。
要获取当前正在使用的`CCSID`,请调用`%charset()`方法。此方法通过引用返回`CCSID`,并返回1或0以指示是否成功.
# 指定其他消息选项
要指定消息描述符选项,可以选择设置连接对象的以下属性:
- `ApplIdentityData`指定应用程序标识消息描述符选项。
- `PutApplType`指定`PUT Application Type`消息描述符选项。
## 发送消息
要发送邮件,请执行以下操作:
1. 按照“创建连接对象”中的说明创建连接对象。在这种情况下,请创建`%Net.MQSend`的实例。`Connection`对象有一个消息队列,可以向该队列发送消息。
2. 根据需要调用以下方法:
- `%put()`-给定一个字符串,此方法将该字符串写入消息队列。
- `%PutStream()`-给定初始化的文件字符流,此方法将该字符串写入消息队列。请注意,必须设置流的`Filename`属性才能对其进行初始化。不支持二进制流。
- `%SetMsgId()`-给定一个字符串,此方法使用该字符串作为发送的下一条消息的消息ID。
3. 检查调用的方法返回的值。
4. 检索完消息后,调用`Connection`对象的`%Close()`方法以释放动态链接库的句柄。
示例1:`SendString()`
下面的类方法使用队列管理器`QM_antigua`和名为 `S_antigua`的队列通道向队列`mqtest`发送一条简单的字符串消息。通道使用TCP传输,IBM `WebSphere MQ`服务器运行在名为`Antigua`的机器上,并侦听端口1401。
```java
///Method returns reason code from IBM WebSphere MQ
ClassMethod SendString() As %Integer
{
Set send=##class(%Net.MQSend).%New()
Set queue="mqtest"
Set qm="QM_antigua"
Set chan="S_antigua/TCP/antigua(1414)"
Set logfile="c:\mq-send-log.txt"
Set check=send.%Init(queue,qm,chan,logfile)
If 'check Quit send.%GetLastError()
//send a unique message
Set check=send.%Put("This is a test message "_$h)
If 'check Quit send.%GetLastError()
Quit check
}
```
示例2:`SendCharacterStream()`
下面的类方法发送文件字符流的内容。它使用的队列与上一个示例中使用的队列相同:
```java
///Method returns reason code from IBM WebSphere MQ
ClassMethod SendCharacterStream() As %Integer
{
Set send=##class(%Net.MQSend).%New()
Set queue="mqtest"
Set qm="QM_antigua"
Set chan="S_antigua/TCP/antigua(1414)"
Set logfile="c:\mq-send-log.txt"
Set check=send.%Init(queue,qm,chan,logfile)
If 'check Quit send.%GetLastError()
//initialize the stream and tell it what file to use
Set longmsg=##class(%FileCharacterStream).%New()
Set longmsg.Filename="c:\input-sample.txt"
Set check=send.%PutStream(longmsg)
If 'check Quit send.%GetLastError()
Quit check
}
```
示例3:从终端发送消息
以下示例显示了向IBM `WebSphere MQ`队列发送消息的终端会话。这只能在配置了IBM `WebSphere MQ`客户端的计算机上运行。
```java
Set MySendQ = ##class(%Net.MQSend).%New()
Do MySendQ.%Init("Q_1", "QM_1","QC_1/TCP/127.0.0.1(1401)","C:\mq.log")
Do MySendQ.%Put("Hello from tester")
Set MyRecvQ =##class(%Net.MQRecv).%New()
Do MyRecvQ.%Init("Q_1", "QM_1","QC_1","C:\mq.log")
Do MyRecvQ.%Get(.msg, 10000)
Write msg,!
```
文章
姚 鑫 · 二月 3, 2022
[toc]
# 第四十三章 SQL函数 DATEDIFF
日期/时间函数,返回两个日期之间指定日期部分的整数差。
# 大纲
```
DATEDIFF(datepart,startdate,enddate)
```
# 参数
- `datepart` - 日期或时间部分的名称(或缩写)。这个名称可以用大写或小写来指定,有或没有引号。`datepart`可以指定为文字或主机变量。
- `startdate` - 间隔的开始日期/时间。可以是各种标准格式的日期、时间或日期时间。
- `enddate` - 间隔的结束日期/时间。可以是各种标准格式的日期、时间或日期时间。从`enddate`中减去`startdate`,以确定两个日期之间的日期部分间隔。
# 描述
`DATEDIFF`函数返回两个指定日期之间指定日期部分差的整数。日期范围从开始日期开始,到结束日期结束。(如果`enddate`早于`startdate`,`DATEDIFF`将返回一个负整数值。)
`DATEDIFF`返回`startdate`和`enddate`之间指定单位的总数。例如,两个日期时间值之间的分钟数计算日期部分和时间部分,并为每一天的差异增加`1440`分钟。`DATEDIFF`返回开始日期和结束日期之间跨越的指定日期部分边界的计数。例如,指定连续年份的任意两个日期(例如`2018-09-23`和`2019-01-01`)返回的年份`DATEDIFF`为1,而不管这两个日期之间的实际持续时间是大于还是小于`365`天。同样,`12:23:59`和`12:24:05`之间的分钟数是1,尽管实际上只有`6`秒将两个值分开。
请注意,`DATEDIFF`是为Sybase和Microsoft SQL Server兼容性而提供的。使用`TIMESTAMPDIFF ODBC`标量函数可以执行类似的时间/日期比较操作。
也可以使用`DATEDIFF()`方法调用从`ObjectScript`调用此函数:
```sql
$SYSTEM.SQL.Functions.DATEDIFF(datepart,startdate,enddate)
```
为`DATEDIFF()`方法指定无效的`datepart`、`startdate`或`enddate`会生成`< ZDDIF >`错误。
# Datepart 参数
日期部分参数可以是下列日期/时间组件之一,可以是全名(日期部分列)或其缩写(缩写列)。这些`datepart`组件名称和缩写不区分大小写。
Date Part| Abbreviations
---|---
year| yyyy, yy
month |mm, m
week| wk, ww
weekday |dw
day |dd, d
dayofyear| dy
hour |hh
minute| mi, n
second| ss, s
millisecond| ms
microsecond| mcs
nanosecond| ns
`weekday`和`dayofyear datepart`值在功能上与`day datepart`值相同。
`DATEDIFF`和`TIMESTAMPDIFF`不处理季度(间隔`3`个月)。
如果指定包含分数秒的开始日期和结束日期,`DATEDIFF`将以分数秒的整数形式返回差值,如下例所示:
```sql
SELECT DATEDIFF('ms','64701,56670.10','64701,56670.27'), /* returns 170 */
DATEDIFF('ms','64701,56670.1111','64701,56670.27222') /* returns 161 */
```
`datepart`可以指定为带引号的字符串或不带引号的字符串。这些语法变体执行略有不同的操作:
- Quotes: `DATEDIFF('month','2018-02-25',$HOROLOG)`:在创建缓存查询时,`datepart`被视为文字。SQL执行文字替换。这将产生一个更容易重用的缓存查询。
- 无引号: `DATEDIFF(month,'2018-02-25',$HOROLOG)`:创建缓存查询时,`datepart`被视为关键字。没有文字替换。这将生成更具体的缓存查询。
# 日期表达式格式
`startdate`和`enddate`参数可以采用不同的数据类型格式。
`startdate`和`enddate`参数可以采用以下任何格式:
- `%Date`逻辑值(`+$H`),也称为`$HOROLOG`格式。
- `%PosixTime`(`%Library.PosixTime`。逻辑值(编码的64位有符号整数)
- `%TimeStamp`(`%Library.TimeStamp`)逻辑值(`YYYY-MM-DD HH:MM:SS。FFF`),也称为`ODBC`格式。
- `%String`(或兼容)值。
`%String`(或`compatible`)值可以是以下任何一种格式,可以包含或省略小数秒:
- `99999、99999` (`$HOROLOG`格式)。
`$HOROLOG`特殊变量不返回小数秒。
但是,可以使用`$HOROLOG`格式指定一个包含分数秒的值:`99999,99999.999`
- Sybase/SQL-Server-date Sybase/SQL-Server-time
- Sybase/SQL-Server-time Sybase/SQL-Server-date
- Sybase/SQL-Server-date (default time is 00:00:00)
- Sybase/SQL-Server-time (default date is 01/01/1900)
Sybase/SQL-Server-date是以下五种格式之一:
```sql
mm/dd/[yy]yy dd Mmm[mm][,][yy]yy dd [yy]yy Mmm[mm] yyyy Mmm[mm] dd yyyy [dd] Mmm[mm]
```
在第一种语法格式中,分隔符可以是斜杠(`/`)、连字符(`-`)或句点(`.`)。
Sybase/SQL-Server-time表示以下三种格式之一:
```sql
HH:MM[:SS[:FFF]][{AM|PM}] HH:MM[:SS[.FFF]] HH['']{AM|PM}
```
## Years
如果年份以两位数字表示,或者日期被完全省略, IRIS会检查滑动窗口来解释日期。
系统范围内滑动窗口的默认值是`1900`;
因此,在默认情况下,两位数的年份被认为是在20世纪。
如下示例所示:
```sql
SELECT DATEDIFF('year','10/11/14','02/22/2018'),
DATEDIFF('year','12:00:00','2018-02-22 12:00:00')
```
## 分数秒
`DATEDIFF`返回以毫秒(3位整数)、微秒(6位整数)或纳秒(9位整数)表示的小数秒,而不管`startdate`和`enddate`中的小数位数精度是多少。
如下示例所示:
```sql
SELECT DATEDIFF('ms','12:00:00.1','12:00:00.2'),
DATEDIFF('ms','12:00:00.10009','12:00:00.20007')
```
一些NLS区域设置将分数分隔符指定为逗号(欧洲的用法),而不是句号。
如果当前区域设置是这些区域设置之一,`DATEDIFF`接受句号或逗号作为本地日期格式的秒分隔符。
对于`$HOROLOG`格式的日期或`ODBC`格式的日期,不能使用逗号作为小数秒分隔符。
尝试这样做会生成一个`SQLCODE -8`。
无论当前的NLS语言环境是什么,这两种格式都需要一段时间。
# 时间差异与时间格式无关
`DATEDIFF`返回以秒和毫秒为单位的时间差,即使当前进程的`TimeFormat`被设置为不返回秒。
如下示例所示:
```java
ClassMethod DateDiff()
{
s tfmt = ##class(%SYS.NLS.Format).GetFormatItem("TimeFormat")
d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",1)
w "datetime values (with seconds) are: ",!,
$ZDATETIME("64701,56670.10",1,-1)," ",$ZDATETIME("64701,56673.27",1,-1),!
&sql(SELECT DATEDIFF('ss','64701,56670.10','62871,56673.27') INTO :x)
w "DATEDIFF number of seconds is: ",x,!!
d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",2)
w "datetime values (without seconds) are: ",!,
$ZDATETIME("64701,56670.10",1,-1)," ",$ZDATETIME("64701,56673.27",1,-1),!
&sql(SELECT DATEDIFF('ss','64701,56670.10','64701,56673.27') INTO :x)
w "DATEDIFF number of seconds is: ",x,!
d ##class(%SYS.NLS.Format).SetFormatItem("TimeFormat",tfmt)
}
```
```java
DHC-APP>d ##class(PHA.TEST.SQLCommand).DateDiff()
datetime values (with seconds) are:
02/22/2018 15:44:30 02/22/2018 15:44:33
DATEDIFF number of seconds is: -158111996.83
datetime values (without seconds) are:
02/22/2018 15:44 02/22/2018 15:44
DATEDIFF number of seconds is: 3.17
```
# 范围和值检查
`DATEDIFF`对输入值执行以下检查:
- 在执行任何`DATEDIFF`操作之前,开始日期和结束日期的所有指定部分必须是有效的。
- 日期字符串必须完整,格式正确,包含适当数量的元素和每个元素的数字,以及适当的分隔符。
年必须指定为四位数字。
如果省略输入值的日期部分,`DATEDIFF`默认为`' 1900-01-01 '`。
无效的日期值将导致`SQLCODE -8`错误。
- 日期和时间值必须在有效范围内。
年龄:`0001`到`9999`。
月份:`1 - 12`个月。
天数:`1 - 31`天。
营业时间:`00`至`23`。
分钟:`0`到`59`分钟。
秒:`0 ~ 59`。
一个月中的天数必须与月和年相匹配。
例如,日期`“02-29”`仅在指定的年份为闰年时有效。
无效的日期值将导致`SQLCODE -8`错误。
- 小于`10`(月和日)的日期值可以包括或省略前导零。
不允许使用其他非规范整数值。
因此,`Day`值为`“07”`或`“7”`是有效的,但`“007”`、`“7.0”`或`“7a”`无效。
- 时间值可以全部或部分省略。
如果`startdate`或`enddate`指定了一个不完整的时间,则为未指定的部分提供`0`。
- 小于`10`的小时值必须包含前导零。
省略前导零将导致`SQLCODE -8`错误。
# 错误处理
- 在`Embedded SQL`中,如果指定无效的`datepart`作为输入变量,则会发出`SQLCODE -8`错误码。
如果将无效的日期部分指定为文字,则会发生``错误。
如果将无效的开始日期或结束日期指定为输入变量或文字,则会发出`SQLCODE -8`错误码。
- 在动态SQL中,如果您提供了无效的日期部分、开始日期或结束日期,则`DATEDIFF`函数将返回一个`NULL`值。
没有发出`SQLCODE`错误。
# 示例
下面的例子返回`353`,因为两个时间戳之间有`353`天(D):
```sql
SELECT DATEDIFF(D,'2018-01-01 00:00:00','2018-12-20 12:00:00')
353
```
在下面的示例中,每个`DATEDIFF`返回`1`,因为日期的年份部分相差1。
日期之间的实际持续时间不被考虑:
```sql
SELECT DATEDIFF('yyyy','1910-08-21','1911-08-21') AS ExactYear,
DATEDIFF('yyyy','1910-06-30','1911-01-01') AS HalfYear,
DATEDIFF('yyyy','1910-01-01','1911-12-31') AS Nearly2Years,
DATEDIFF('yyyy','1910-12-31 11:59:59','1911-01-01 00:00:00') AS NewYearSecond
1 1 1 1
```
注意,上面的例子使用了日期部分的缩写。
但是,你可以指定全名,如下例所示:
```sql
SELECT DATEDIFF('year','2017-09-10 13:19:00','2018-12-20 00:00:00')
1
```
下面的嵌入式SQL示例使用主机变量执行与前面示例相同的`DATEDIFF`操作:
```sql
ClassMethod DateDiff1()
{
s x="year"
s date1="2017-09-10 13:19:00"
s date2="2018-12-20 00:00:00"
&sql(SELECT DATEDIFF(:x,:date1,:date2)
INTO :diff)
w diff
}
```
```
1
```
下面的例子使用`WHERE`子句中的`DATEDIFF`来选择上周入院的患者:
```sql
SELECT Name,DateOfAdmission FROM Sample.Patients WHERE DATEDIFF(D,DateOfAdmission,$HOROLOG)