清除过滤器
文章
Jingwei Wang · 五月 5, 2023
WIN SQL是大多数用户使用的普通编辑器。但是我们不能使用winsql下载大量数据。所以我写了一个教程如何连接一个新的基于 Java 的编辑器,叫做 Squirrel SQL,它可以很容易地下载或导出 excel 或任何其他格式的数据。我还包括一个 Java JCBC 连接程序来连接 IRIS 数据库,尤其是镜像/故障转移服务器。
基于 SQL Java 的编辑器导出大量数据和用于 IRIS 连接的 Java JDBC 程序
基于 SQL Java 的编辑器导出大量数据
WinSql 是通常用于从 Iris 数据库中提取数据的编辑器,但是,如果没有许可的 winsql,则无法导出大量数据。
解决方案是使用基于 java 的编辑器,称为 Squirrel SQL。这是一个基于 java 的编辑器,您可以在从 IRIS 数据库执行 fetch 从编辑器中导出大量数据。这是用 Java 构建的开源 SQL 客户端,它使用 JDBC 连接到 IRIS 数据库。
Squirrel SQL 的特点
Java 19 兼容性
多个插入符/光标编辑
全局首选项和新会话属性搜索
Saved Sessions 的多项改进(用于保存和恢复 Session 的所有 SQL 编辑器的特性)
可配置的鼠标右键菜单
重新设计的添加/编辑 JDBC 驱动程序对话框
安装 Squirrel SQL 的步骤
Squirrel SQL 可以从 Squirrel 官网下载https://squirrel-sql.sourceforge.io/
连接 IRIS 数据库的步骤
向 Squirrel Sql 添加驱动程序
点击“+”图标创建一个新的驱动程序,如下图所示
在“添加驱动程序对话框”中,选择“额外类路径”并单击“添加”,为“Intersystems-jdbc-3.2.0.jar”(jdbc 驱动程序jar 文件)添加一个新条目,如下所示。如果您在本地计算机的 C 盘上安装了 IRIS,这将是基于 IRIS 版本的正常路径
C:\InterSystems\IRISHealth2\dev\java\lib\JDK18\intersystems-jdbc-3.2.0.jar。
如下图所示,
输入驱动程序的名称“Intersystems IRIS”(选择任何有意义的名称)
输入示例 URL 作为 jdbc:IRIS://<host>:<port>/<database>
网站 URL 是可选的。
单击右侧的“List Drivers”按钮并选择“com.intersystems.jdbc.IRISDriver”,如下图所示。
单击“确定”保存驱动程序条目。现在您可以在驱动程序下的左侧菜单栏中看到驱动程序。
添加基于驱动程序的别名(连接)
选择squirrel sql左侧的“别名”选项卡,点击“+”添加新别名,如下图。
在“添加别名”窗口中,为别名输入一个有意义的名称。
从下拉菜单中选择我们新创建的 IRIS 驱动程序。选择驱动程序后,URL 格式将填充为新创建的驱动程序配置。通过添加正确的主机名或 IP 地址、端口号和数据库命名空间来编辑 URL。
例如:jdbc:IRIS://00.00.00.00.00:12345/TEST-TRAK
输入具有 SQL 权限的 IRIS 数据库的用户名和密码
单击测试按钮并验证连接是否成功。
单击“确定”保存新别名
连接到 IRIS 数据库
双击新创建的别名连接到数据库,squirrel 编辑器将打开,您可以尝试使用 sql 查询。
用于编写程序的 IRIS 数据库的 JDBC 连接
import java.sql.*;
import com.intersystems.jdbc.*;
import java.util.logging.*;
import java.io.IOException;
import java.util.*;
public class Extract {
public static Connection TrakCache () throws Exception {
IRISDataSource ds = new IRISDataSource();
Connection conn = null ;
ds.setURL( "jdbc:IRIS://1.12.333.444:12345/NAMESPACE-TRAK" );
ds.setUser( "username" );
ds.setPassword( "Password" );
try
{
conn = ds.getConnection();
} catch (Exception e)
{
System.out.println( "catch" +conn); //You can write another connection here if automatically fail over to another server.
} return conn;
}
}
文章
Muhammad Waseem · 八月 11, 2022
嗨社区,
这篇文章公开介绍我的 iris-fhir-client 客户端应用。
iris-fhir-client 可以可以借助嵌入式 python 连接到任何开放的 FHIR 服务器 fhirpy 图书馆.
通过终端和使用 CSP Web 应用程序获取资源信息。
查看和激活注册服务器
连接到 IRIS 终端
docker-compose exec iris iris session iris
应用程序将默认注册 InterSystems FHIR Accelerator Service 和 SmartHealthIT Open FHIR Server,两者都可以使用。使用以下命令列出已注册的服务器
do ##class(dc.FhirClient).ServerList()
InterSystems FHIR 加速器服务处于激活状态。 为了选择 SmartHealthIT 打开 FHIR 服务器,通过传递服务器 ID 使用 dc.FhirClient 类的 SetFhirServer 函数
do ##class(dc.FhirClient).SetFhirServer(2)
注册的 FHIR 服务器
要注册新服务器,请使用 dc.FhirClient 类的 RegisterServer() 函数class(dc.FhirClient).RegsterServer("Server Name","Endpoint","ApiKey"[optional],"EndpointOAuth"[optional]
do ##class(dc.FhirClient).RegisterServer("INTERSYSTEMS FHIR Server","http://localhost:52773/csp/healthshare/samples/fhir/r4/","","")
从 FHIR 服务器获取资源
要检索当前服务器的所有资源,请使用 dc.FhirClient 类的 ListResources() 方法
do ##class(dc.FhirClient).ListResources()
为了显示任何资源的记录数,通过传递 dc.FhirClient 的 Resource 使用 CountResource() 方法下面的命令将从激活的 FHIR 服务器获取患者资源计数器
set count = ##class(dc.FhirClient).CountResource("Patient")
write count
要检索所有创建的资源及其计数,只需将 1 传递给 ListResource() 函数
do ##class(dc.FhirClient).ListResources(1)
要获取资源的详细信息,请通过传递 dc.FhirClient 类的 Resource 使用 GetResource()下面的命令将从激活的FHIR 服务器中检索所有患者
do ##class(dc.FhirClient).GetResource("Patient")
下面的命令将从激活的 FHIR 服务器中检索所有观察结果
do ##class(dc.FhirClient).GetResource("Observation")
从 FHIR 服务器获取特定患者的资源
下面的命令将从激活的 FHIR 服务器中检索针对 Patinet ID 1 的观察详细信息
do ##class(dc.FhirClient).GetPatientResources("Observation","1")
从 CSP Web 应用程序查看 FHIR 服务器信息
导航 http://localhost:55037/csp/fhirclient/index.csp索引页面将显示激活的服务器中患者、观察、从业者和就诊次数以及患者和注册服务器的详细信息
索引页面将显示 FHIR 服务器列表,其中选择了激活的服务器。 从列表中选择其他服务器以查看所选服务器的详细信息
将鼠标悬停到患者 ID 并选择以获取患者资源的详细信息
此页面将显示一些患者资源的数量以及患者观察的详细信息
谢谢
文章
Hao Ma · 三月 25, 2021
**关键字**:PyODBC,unixODBC,IRIS,IntegratedML,Jupyter Notebook,Python 3
## **目的**
几个月前,我简单谈到了关于“[将 Python JDBC 连接到 IRIS](https://community.intersystems.com/post/python-jdbc-connection-iris-database-quick-note)”的话题。我后来频繁提起它, 因此决定再写一篇 5 分钟的笔记,说明如何“将 Python ODBC 连接到 IRIS”。
在 Windows 客户端中通常很容易设置 ODBC 和 PyODBC,不过我每次在 Linux/Unix 风格的服务器中设置 unixODBC 和 PyODBC 客户端时,都会遇到一些麻烦。
有没有一种简单连贯的方法,可以不安装任何 IRIS,在原版 Linux 客户端中让 PyODBC/unixODBC 针对远程 IRIS 服务器运行?
## **范围**
最近,我花了点时间研究如何在 Linux Docker 环境的 Jupyter Notebook 中从头开始让一个 PyODBC 演示运行起来, 记录下这篇稍微有些繁琐的笔记,以供日后快速参考。
#### **范围内**:
这篇笔记将涉及以下组件:
PyODBC over unixODBC
安装了 TensorFlow 2.2 和 Python 3 的 Jupyter Notebook 服务器
带有 IntegratedML 的 IRIS2020.3 CE 服务器,包括示例测试数据。
在此环境中
安装了 Docker-compose over AWS Ubuntu 16.04 的 Docker Engine
Docker Desktop for MacOS 和 Docker Toolbox for Windows 10 也经过了测试
#### **范围外**:
同样,在此演示环境中不评估非功能性方面。 它们很重要,并且可以针对特定站点,如:
端到端安全和审核
性能和可扩展性
许可和可支持性等
## **环境**
任何原版 Linux Docker 镜像都可以用于以下配置和测试步骤,但有一个简单的方法可以在 5 分钟内设置这样的环境:
1. Git **克隆**此[演示模板](https://github.com/tom-dyar/integratedml-demo-template)
2. 在包含 docker-compose.yml 文件的克隆目录中运行“**docker-compose up -d**”。
这将创建一个演示环境,如下面的拓扑所示,其中包含 2 个容器。 一个用于 Jupyter Notebook 服务器作为 PyODBC 客户端,另一个用于 IRIS2020.3 CE 服务器。
在上面的环境中,tf2jupyter 仅包含“Python over JDBC”客户端配置;它尚不包含任何 ODBC 或 PyODBC 客户端配置。
因此,我们将直接在 Jupyter Notebook 内部运行以下设置步骤,以使其易于说明。
## **步骤**
以下配置和测试由我在 AWS Ubuntu 16.04 服务器中运行, 由我的同事 @Thomas.Dyar 在 MacOS 中运行。 另外在 Docker Toolbox for Windows 中也进行了简单的测试。 不过,如果您遇到任何问题,还是请告诉我们。
以下步骤可以自动化到其 Dockerfile。 我在这里特别记录一下,以防几个月后忘记。
### **1. 官方文档:**
IRIS 的 ODBC 支持
在 Unix 上定义 ODBC 数据源
IRIS 的 PyODBC 支持
### **2. 连接到 Jupyter 服务器**
我用本地 Putty 的 SSH 隧道连接到远程 AWS Ubuntu 端口 22,然后按照上述拓扑结构映射到端口 8896。
(举个例子,在本地 Docker 环境中,也可以直接直接 http 到 Docker 机器的 IP:8896。)
### **3. 从 Jupyter Notebook 中运行 ODBC 安装**
直接在 Jupyter 单元格中运行以下代码:
!apt-get update<br>!apt-get install gcc<br>!apt-get install -y tdsodbc unixodbc-dev<br>!apt install unixodbc-bin -y<br>!apt-get clean -y
它将安装 gcc(包括 g++)编译器、FreeTDS、unixODBC 和 unixodbc-dev,以在下一步重新编译 PyODBC 驱动程序。
在原生 Windows 服务器或 PC 上安装 PyODBC 不需要这一步。
### **4. 从 Jupyter 中运行 PyODBC 安装**
!pip install pyodbc
Collecting pyodbc
Downloading pyodbc-4.0.30.tar.gz (266 kB)
|████████████████████████████████| 266 kB 11.3 MB/s eta 0:00:01
Building wheels for collected packages: pyodbc
Building wheel for pyodbc (setup.py) ... done
Created wheel for pyodbc: filename=pyodbc-4.0.30-cp36-cp36m-linux_x86_64.whl size=273453 sha256=b794c35f41e440441f2e79a95fead36d3aebfa74c0832a92647bb90c934688b3
Stored in directory: /root/.cache/pip/wheels/e3/3f/16/e11367542166d4f8a252c031ac3a4163d3b901b251ec71e905
Successfully built pyodbc
Installing collected packages: pyodbc
Successfully installed pyodbc-4.0.30
以上是这个 Docker 演示的最简化 pip 安装。 在[官方文档](https://irisdocs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=BNETODBC_support#BNETODBC_support_pyodbc)中,为“MacOS X 安装”提供了更详细的 pip 安装。
### **5 在 Linux 中重新配置 ODBC INI 文件和链接:**
运行以下命令重新创建 **odbcinst.ini** 和 **odbc.ini** 链接
!rm /etc/odbcinst.ini!rm /etc/odbc.ini
!ln -s /tf/odbcinst.ini /etc/odbcinst.ini!ln -s /tf/odbc.ini /etc/odbc.ini
注:这样的原因是,**第 3 步和第 4 步通常会在 \etc\ directory 下创建 2 个空白(因此无效)的 ODBC 文件。**与 Windows 安装不同,这里的空白 ini 文件会导致问题。因此需要先将其删除,然后重新创建一个链接来指向映射的 Docker 卷中提供的真实 ini 文件:/tf/odbcinst.ini 和 /tf/odbc.ini
看一看这两个 ini 文件。在这种情况下,它们是 Linux ODBC 配置的最简形式:
!cat /tf/odbcinst.ini
[InterSystems ODBC35]
UsageCount=1
Driver=/tf/libirisodbcu35.so
Setup=/tf/libirisodbcu35.so
SQLLevel=1
FileUsage=0
DriverODBCVer=02.10
ConnectFunctions=YYN
APILevel=1
DEBUG=1
CPTimeout=<not pooled>
!cat /tf/odbc.ini
[IRIS PyODBC Demo]
Driver=InterSystems ODBC35
Protocol=TCP
Host=irisimlsvr
Port=51773
Namespace=USER
UID=SUPERUSER
Password=SYS
Description=Sample namespace
Query Timeout=0
Static Cursors=0
以上文件都已预先配置,位于映射的驱动器中。 引用的是驱动程序文件 **libirisodbcu35.so**,可以从 IRIS 服务器的容器实例中获取该文件(在其 {iris-installation}/bin 目录下)。
要使上述 ODBC 安装正常运行,**这 3 个文件**必须存在于**具有正确文件权限**的映射驱动器(或任何 Linux 驱动器)中:
libirisodbcu35.so
odbcinst.ini
odbc.ini
**6. 验证 PyODBC 安装 **
!odbcinst -j
unixODBC 2.3.4
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /root/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8
import pyodbcprint(pyodbc.drivers())
['InterSystems ODBC35']
以上输出将表明 ODBC 驱动程序目前具有有效链接。
我们应该能够在 Jupyter Notebook 中运行一些 Python ODBC 测试
**7. 运行将 Python ODBC 连接到 IRIS 的示例:**
import pyodbc import time
### 1. Get an ODBC connection #input("Hit any key to start")dsn = 'IRIS PyODBC Demo'server = 'irisimlsvr' # IRIS server container or the docker machine's IP port = '51773' # or 8091 if docker machine IP is useddatabase = 'USER' username = 'SUPERUSER' password = 'SYS'
#cnxn = pyodbc.connect('DSN='+dsn+';') # use the user DSN defined in odbc.ini, or use the connection string belowcnxn = pyodbc.connect('DRIVER={InterSystems ODBC35};SERVER='+server+';PORT='+port+';DATABASE='+database+';UID='+username+';PWD='+ password)
###ensure it reads strings correctly.cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf8')cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf8')cnxn.setencoding(encoding='utf8')
### 2. Get a cursor; start the timercursor = cnxn.cursor()start= time.clock()
### 3. specify the training data, and give a model namedataTable = 'DataMining.IrisDataset'dataTablePredict = 'Result12'dataColumn = 'Species'dataColumnPredict = "PredictedSpecies"modelName = "Flower12" #chose a name - must be unique in server end
### 4. Train and predict#cursor.execute("CREATE MODEL %s PREDICTING (%s) FROM %s" % (modelName, dataColumn, dataTable))#cursor.execute("TRAIN MODEL %s FROM %s" % (modelName, dataTable))#cursor.execute("Create Table %s (%s VARCHAR(100), %s VARCHAR(100))" % (dataTablePredict, dataColumnPredict, dataColumn))#cursor.execute("INSERT INTO %s SELECT TOP 20 PREDICT(%s) AS %s, %s FROM %s" % (dataTablePredict, modelName, dataColumnPredict, dataColumn, dataTable)) #cnxn.commit()
### 5. show the predict resultcursor.execute("SELECT * from %s ORDER BY ID" % dataTable) #or use dataTablePredict result by IntegratedML if you run step 4 aboverow = cursor.fetchone() while row: print(row) row = cursor.fetchone()
### 6. CLose and clean cnxn.close()end= time.clock()print ("Total elapsed time: ")print (end-start)
(1, 1.4, 0.2, 5.1, 3.5, 'Iris-setosa')
(2, 1.4, 0.2, 4.9, 3.0, 'Iris-setosa')
(3, 1.3, 0.2, 4.7, 3.2, 'Iris-setosa')
(4, 1.5, 0.2, 4.6, 3.1, 'Iris-setosa')
(5, 1.4, 0.2, 5.0, 3.6, 'Iris-setosa')
... ...
... ...
... ...
(146, 5.2, 2.3, 6.7, 3.0, 'Iris-virginica')
(147, 5.0, 1.9, 6.3, 2.5, 'Iris-virginica')
(148, 5.2, 2.0, 6.5, 3.0, 'Iris-virginica')
(149, 5.4, 2.3, 6.2, 3.4, 'Iris-virginica')
(150, 5.1, 1.8, 5.9, 3.0, 'Iris-virginica')
Total elapsed time:
0.023873000000000033
这里有一些陷阱:
1. **cnxn = pyodbc.connect() **- 在 Linux 环境下,此调用中传递的连接字符串必须正确无误,不能有任何空格。
2. 正确设置连接编码,例如使用 utf8。 在这里默认值对字符串不起作用。
3. **libirisodbcu35.so** - 理想情况下,此驱动程序文件应与远程 IRIS 服务器的版本保持一致。
## **未来计划 **
这样就得到一个带有 Jupyter Notebook 的 Docker 环境,包括 Python3 和 TensorFlow 2.2(无 GPU),通过 PyODBC(以及 JDBC)连接到远程 IRIS 服务器。 所有定制的 SQL 语法应该都可以适用,比如 IRIS Integrated ML 专有的 SQL 语法。那么何不多研究一下 IntegratedML 的功能,用它驱动 ML 生命周期的 SQL 方法以进行一些创新?
另外,我希望接下来能介绍或总结出在 IRIS Native 甚至是 Python 环境中的魔法 SQL 上最简单的 IRIS 服务器挂接方法。 而且,现在有出色的 [Python Gateway](https://github.com/intersystems-community/PythonGateway),我们甚至可以直接从 IRIS 服务器内部调用外部 Python ML 应用和服务。我希望我们也能在这方面多做些尝试。
**附录**
上面的笔记本文件也将被迁入此 Github 存储库以及 Open Exchange 中。
It's also possible to simply put the driver on the driver path. Isn't this configuration of the driver too cumbersome
driver = '/usr/irisodbc/bin/libirisodbc35.so'
server = ''
database = ''
username = ''
password = ''
port = ''
cnxn = pyodbc.connect(driver=driver, server=server,port='1972', database=database, uid=username, pwd=password,charset='UTF-8')
###ensure it reads strings correctly.
cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf8')
cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf8')
cnxn.setencoding(encoding='utf8')
cursor = cnxn.cursor()
cursor.execute("select top 10 * from xx.xx")
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
cnxn.close()
文章
Michael Lei · 五月 17, 2021
我创建了 iris-fhir-portal 来参加当前竞赛 **[InterSystems IRIS for Health FHIR](https://community.intersystems.com/post/welcome-intersystems-iris-health-fhir-contest-developers),**本篇快速概述旨在介绍我的应用程序提供的功能。
iris-fhir-portal 的目标是说明使用 IRIS for Health 中的 FHIR 功能创建患者图表并让用户拥有自己的数据有多么简单。
## 功能
### 患者列表
在左侧面板上,有一个患者列表,顶部是一个筛选栏。

### 患者详细信息

表格提供以下信息:
* FHIR 患者 ID
* SSN(社会保障号码)
* 名字
* 姓氏
* 出生日期
* 性别
* 地址
* 城市
* 州/省
* 国家/地区
在患者详细信息表格后面,是一个包含四个信息块的可折叠项。 提供这些信息的 FHIR 资源为:
* AllergyIntolerance
* Observation
* 类别:vital-signs
* 类别:laboratory
* Immunization
右侧的徽章显示每个项目的结果总数。
附注:我在上一篇文章中写到了如何从 FHIR 资源获取所有这些信息。 https://community.intersystems.com/post/my-experience-working-fhir
例如,以下是实验室数据结果的屏幕截图:

为了以透明的方式处理患者数据,在页面末尾有一个模版,其中包含 FHIR 资源提供的所有信息。

####
#### 您可以在这里试用本应用程序!
如果您喜欢本应用程序,并认为我值得您投票,请为 iris-fhir-portal 投一票! 
****
文章
Michael Lei · 三月 21, 2022
# IRIS Healthtoolkit Service 软件即服务
[](https://youtu.be/lr2B7zSFkds "Video")
轻松实现HL7v2 转 FHIR, CDA 转 FHIR, FHIR 转 HL7v2 即服务.
这个项目的目标是提供 REST API 可以轻松转化不同的医疗行业格式。
在Rest body 发布需要的格式,在答案中获得新的格式。
*  InterSystems 消息转换公有云服务: https://aws.amazon.com/marketplace/pp/prodview-q7ryewpz75cq2 
*  视频(油管) : https://youtu.be/lr2B7zSFkds 
## 安装
克隆这个 repository
```
git clone https://github.com/grongierisc/iris-healthtoolkit-service.git
```
Docker
```
docker-compose up --build -d
```
## 使用
* 访问 : http://localhost:32783/swagger-ui/index.html
## API 细节
* HL7 转 FHIR
```
POST http://localhost:32783/api/hl7/fhir
```
* FHIR 转 HL7 ADT
```
POST http://localhost:32783/api/fhir/hl7/adt
```
* FHIR 转 HL7 ORU
```
POST http://localhost:32783/api/fhir/hl7/oru
```
* FHIR 转 HL7 vxu
```
POST http://localhost:32783/api/fhir/hl7/vxu
```
* CDA 转 FHIR
```
POST http://localhost:32783/api/cda/fhir
```
* FHIR repo
```
GET http://localhost:32783/api/fhir/metadata
```
## 支持的 HL7 inbound 格式 :
* ADT_A01, ADT_A02, ADT_A03, ADT_A04, ADT_A05, ADT_A06, ADT_A07, ADT_A08, ADT_A09, ADT_A10, ADT_A11, ADT_A12, ADT_A13, ADT_A17, ADT_A18, ADT_A23, ADT_A25, ADT_A27, ADT_A28, ADT_A29, ADT_A30, ADT_A31, ADT_A34, ADT_A36, ADT_A39, ADT_A40, ADT_A41, ADT_A45, ADT_A47, ADT_A49, ADT_A50, ADT_A51, ADT_A60
* BAR_P12
* MDM_T02, MDM_T04, MDM_T08, MDM_T11
* OMP_O09
* ORM_O01
* ORU_R01
* PPR_PC1, PPR_PC2, PPR_PC3
* RDE_O11
* SIU_S12, SIU_S13, SIU_S14, SIU_S15, SIU_S16, SIU_S17, SIU_S26
* VXU_V04
## 如何工作
这个项目基于SDA模型工作.
SDA (Summary Document Architecture) 是InterSystems系联公司的临床数据格式。
SDA FHIR 的对应关系在 [这里](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=HXFHIR_transforms), CDA -> SDA 的对应在[这里](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=HXCDA).

文章
姚 鑫 · 八月 9, 2024
# 第五章 引用 SOAP 操作(仅限 SOAP 1.1)
# 引用 `SOAP` 操作(仅限 `SOAP 1.1`)
在 `SOAP 1.1` 请求消息中,`HTTP` 标头包含如下 `SOAPAction` 行:
```java
POST /csp/gsop/GSOP.DivideWS.cls HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; InterSystems IRIS;)
Host: localhost:8080
Connection: Close
Accept-Encoding: gzip
SOAPAction: http://www.mynamespace.org/GSOAP.DivideWS.Divide
Content-Length: 397
Content-Type: text/xml; charset=UTF-8
...
```
默认情况下,`SOAPAction`的值不带引号。要将此值放在引号中,请在 Web 客户端类中将 `SOAPACTIONQUOTED` 指定为 `1`。然后请求消息的 `HTTP` 标头将如下所示:
```java
POST /csp/gsop/GSOP.DivideWS.cls HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; InterSystems IRIS;)
Host: localhost:8080
Connection: Close
Accept-Encoding: gzip
SOAPAction: "http://www.mynamespace.org/GSOAP.DivideWS.Divide"
Content-Length: 397
Content-Type: text/xml; charset=UTF-8
...
```
在 `SOAP 1.2` 中,`SOAPACTIONQUOTED` 参数不起作用。这是因为请求消息没有 `SOAPAction` 行。相反,`SOAP` 操作始终被引用,并包含在 `Content-Type` 行中,如下所示:
```java
Content-Type: application/soap+xml;
charset=UTF-8; action="http://www.mynamespace.org/GSOAP.DivideWS.Divide"
```
注意:此示例显示了人为的换行符,以确保当此内容格式化为 `PDF` 时,该行适合页面。
# 将 `HTTP` 状态 `202` 视为状态 `200`
默认情况下, `Web` 客户端遵循标准 `WS-I` 基本配置文件,仅当 `HTTP` 响应不包含 `SOAP` 信封时才使用 `HTTP` 响应状态 `202`。
如果要以与 `HTTP` 状态 `200` 相同的方式处理 `HTTP` 状态 `202`,请将客户端的 `HttpAccept202` 属性设置为 `1`。要查看实际的返回状态,请检查客户端的 `HttpResponse.StatusCode` 属性。
`WS-I` 基本配置文件支持但不鼓励这种做法:“该配置文件接受这两种状态代码,因为某些 `SOAP` 实现对 `HTTP` 协议实现几乎没有控制权,并且无法控制发送哪一个响应状态代码。”
文章
姚 鑫 · 五月 11, 2022
# 第139章 SQL函数 TIMESTAMPDIFF
一个标量日期/时间函数,它返回指定日期部分的两个时间戳之间差异的整数计数。
# 大纲
```java
{fn TIMESTAMPDIFF(interval-type,startdate,enddate)}
```
# 参数
- `interval-type` - 返回值将表示的时间/日期间隔类型。
- `startdate` - 时间戳值表达式。
- `enddate` - 将与 `startdate` 进行比较的时间戳值表达式。
# 描述
`TIMESTAMPDIFF` 函数返回指定日期部分间隔(秒、天、周等)的两个给定时间戳之间的差异(即,从另一个中减去一个时间戳)。返回的值是一个 `INTEGER`,即两个时间戳之间的这些间隔数。 (如果 `enddate` 早于 `startdate`,则 `TIMESTAMPDIFF` 返回负 `INTEGER` 值。)
开始日期和结束日期是时间戳。这些时间戳可以是 `%Library.TimeStamp` 数据类型格式 (`yyyy-mm-dd hh:mm:ss.ffff`) 或 `%Library.PosixTime` 数据类型格式(编码的 `64` 位有符号整数)。
间隔类型参数可以是以下时间戳间隔之一:
- `SQL_TSI_FRAC_SECOND`
- `SQL_TSI_SECOND`
- `SQL_TSI_MINUTE`
- `SQL_TSI_HOUR`
- `SQL_TSI_DAY`
- `SQL_TSI_WEEK`
- `SQL_TSI_MONTH`
- `SQL_TSI_YEAR`
这些时间戳间隔可以使用单引号或双引号来指定,带或不带引号。它们不区分大小写。
`TIMESTAMPDIFF` 和 `DATEDIFF` 不处理季度`quarters` (3 个月间隔)。
请注意,`TIMESTAMPDIFF` 只能用作 ODBC 标量函数(使用大括号语法)。可以使用 `DATEDIFF` 通用函数对时间戳执行类似的时间/日期比较操作。
# %TimeStamp 格式化
如果 `startdate` 或 `enddate` 参数采用 `%Library.TimeStamp` 数据类型格式 (`yyyy-mm-dd hh:mm:ss.ffff`),则适用以下规则:
- 如果任一时间戳表达式仅指定时间值并且间隔类型指定日期间隔(天、周、月或年),则在计算结果间隔计数之前,时间戳的缺失日期部分默认为`“1900–01–01”` .
- 如果任一时间戳表达式仅指定日期值并且间隔类型指定时间间隔(小时、分钟、秒、小数秒),则在计算结果间隔计数之前,时间戳的缺失时间部分默认为`“00:00:00.000”` .
- 可以包含或省略任意位数精度的小数秒。 `SQL_TSI_FRAC_SECOND` 以千分之一秒的整数计数形式返回小数秒的差异(精度为三位数)。 `%PosixTime` 值始终包含六位精度。
# 范围和值检查
`TIMESTAMPDIFF` 对输入值执行以下检查。
- `startdate` 和 `enddate` 的所有指定部分必须有效,然后才能执行任何 `TIMESTAMPDIFF` 操作。
- 日期字符串必须完整且格式正确,其中包含适当数量的元素和每个元素的数字,以及适当的分隔符。年份必须指定为四位数。无效的日期值会导致 `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` 指定了不完整的时间,则为未指定的部分提供零。
- 小于 10 的小时值必须包含前导零。省略此前导零会导致 `SQLCODE -8` 错误。
# 示例
以下示例返回 `7`,因为第二个时间戳 (`2017-12-20 12:00:00`) 比第一个大 `7` 个月:
```sql
SELECT {fn TIMESTAMPDIFF(SQL_TSI_MONTH,
'2017-5-19 00:00:00','2017-12-20 12:00:00')}
7
```
以下示例返回 `566`,因为第二个时间戳 (`'12:00:00'`)) 比第一个时间戳 (`02:34:12`) 大 `566` 分钟:
```sql
SELECT {fn TIMESTAMPDIFF(SQL_TSI_MINUTE,'02:34:12','12:00:00')}
566
```
以下示例返回 -1440,因为第二个时间戳比第一个小一天(1440 分钟):
```sql
SELECT {fn TIMESTAMPDIFF(SQL_TSI_MINUTE,'2017-12-06','2017-12-05')}
-1440
```
文章
姚 鑫 · 三月 4, 2021
# 第三章 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关键字包括命令名称,函数名称,谓词条件名称,数据类型名称,字段约束,优化选项和特殊变量。它们还包括`AND`,`OR`和`NOT`逻辑运算符,`NULL`列值指示符以及ODBC函数构造,例如`{d dateval}`和`{fn CONCAT(str1,str2)}`。
- 关键字不区分大小写。按照惯例,在本文档中,关键字用大写字母表示,但是InterSystems SQL没有大小写限制。
- 有许多关键字是SQL保留字。 InterSystems SQL仅保留那些不能明确解析的关键字。 SQL保留字可用作分隔符。
# 函数:内在的和外在的
- 内在的:InterSystems SQL支持大量内在的(系统提供的)函数。
这些函数包括数字函数、字符串函数以及日期和时间函数。
聚合函数是SQL固有函数,它计算列的所有值并返回单个聚合值。
- InterSystems SQL也可以支持用户提供的ObjectScript函数调用(外部函数),如下所示:
这种写法只能在mac routine里,类文件里编译报错。
```sql
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函数返回不同的值:`length`、`CHAR_LENGTH`和`DATALENGTH`返回SQL长度。
`$LENGTH`返回ObjectScript表示长度。
长度不计算尾随空格;
所有其他长度函数都计算末尾的空格。
# null 处理
NOT NULL数据约束要求字段必须接收一个数据值;
不允许指定NULL而不是值。
这个约束不阻止使用空字符串值。
`SELECT`语句的`WHERE`或`HAVING`子句中的`IS NULL`谓词选择空值;
它不选择空字符串值。
`IFNULL`函数计算一个字段值,如果字段值为`NULL`,则返回第二个参数中指定的值。
它不会将空字符串值视为非空值。
`COALESCE`函数从提供的数据中选择第一个非空值。
它将空字符串值视为非空值。
当`CONCAT`函数或`concenate`操作符(`||`)连接一个字符串和一个`NULL`时,结果是`NULL`。
如下面的例子所示:
```sql
SELECT {fn CONCAT('fred',NULL)} AS FuncCat, -- returns
'fred'||NULL AS OpCat -- returns
```
`AVG、COUNT、MAX、MIN`和`SUM`聚合函数在执行操作时忽略`NULL`值。
(`COUNT *`统计所有行,因为不可能有一个所有字段都为空值的记录。)
`SELECT`语句的`DISTINCT`关键字在其操作中包含`NULL`;
如果指定的字段有空值,`DISTINCT`返回一个空行.
`AVG`、`COUNT`和`MIN`、聚合函数受空字符串值的影响。
`MIN`函数将空字符串视为最小值,即使存在值为0的行。
`MAX`和`SUM`聚合函数不受空字符串值的影响。
## null 表达式
对大多数SQL函数提供`NULL`作为操作数将返回`NULL`。
任何以NULL作为操作数的SQL算术操作都返回`NULL`值。
因此,7 +零=零。
这包括二元运算加法(`+`)、减法(`-`)、乘法(`*`)、除法(`/`)、整数除法(`\`)和取模(`#`),以及一元符号运算符加号(`+`)和减号(`-`)。
算术操作中指定的空字符串将被视为0(零)值。
除法(`/`),整数除法(`\`),或对空字符串(`6/ "`)取模(`#`)会导致``错误。
## NULL的长度
在SQL中,`NULL`的长度是没有定义的(它返回`< NULL >`)。
然而,空字符串的长度被定义为长度为0。
如下面的例子所示:
```sql
SELECT LENGTH(NULL) AS NullLen, -- returns
LENGTH('') AS EmpStrLen -- returns 0
```
如本例所示,SQL `LENGTH`函数返回SQL长度。
可以使用`ASCII`函数将SQL的零长度字符串转换为`NULL`,示例如下:
```sql
SELECT LENGTH(NULL) AS NullLen, -- returns
LENGTH({fn ASCII('')}) AS AsciiEmpStrLen, -- returns
LENGTH('') AS EmpStrLen -- returns 0
```
但是,对标准`SQL`的某些系统间IRIS扩展对`NULL`和空字符串的长度的处理是不同的。
$LENGTH函数返回这些值的InterSystems IRIS内部表示:`NULL`表示为长度为0的已定义值,SQL空字符串表示为长度为0的字符串。
该功能与ObjectScript兼容。
```sql
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的字符串。
如下面的例子所示:
```sql
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。
```sql
/// 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
}
```
```sql
DHC-APP>d ##class(PHA.TEST.SQL).Null()
NULL length: 0
empty string length: 1
```
在ObjectScript中,没有值通常用空字符串(`""`)表示。
当这个值被传递到嵌入式SQL中时,它会被视为空值,如下面的例子所示:
```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"
}
```
```sql
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的字符串。
如下面的例子所示:
```sql
/// 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
}
```
```sql
DHC-APP>d ##class(PHA.TEST.SQL).Null2()
The length of NULL is: 0
The length of empty string is: 1
```
在下面的例子中,SQL的空字符串加上一个空格被传递为长度为2的字符串:
```sql
/// d ##class(PHA.TEST.SQL).Null3()
ClassMethod Null3()
{
&sql(SELECT %SQLUPPER('')
INTO :y )
WRITE !,"SQL empty string length: ",$LENGTH(y)
}
```
```sql
DHC-APP> d ##class(PHA.TEST.SQL).Null3()
SQL empty string length: 2
``` good, mark Thank you! It's very useful for us while using InterSystems SQL. 学习了,谢谢大佬 很实用!感谢总结! 大佬,已被圈粉,长期追踪学习!
文章
姚 鑫 · 八月 5, 2022
# 第十八章 源代码文件 REST API 教程(三)
# 编译文件
`Compile` 方法编译传入 `JSON` 数组中名称指定的源代码文件。例如,要编译 `xyz.mac`,请发布以下内容:
```java
http://localhost:52773/api/atelier/v1/INVENTORY/action/compile
```
使用以下 `JSON` 消息:
```java
["xyz.mac"]
```
该方法返回:
```java
{
"status": {
"errors": [],
"summary": ""
},
"console": [
"",
"Compilation started on 08/14/2016 15:25:20 with qualifiers 'cuk'",
"xyz.int is up to date. Compile of this item skipped.",
"Compilation finished successfully in 0.008s."
],
"result": {
"content": []
}
}
```
对于一些源代码文件,例如类,`Compile` 在返回的内容中返回存储信息。
# 删除文件
`DeleteDoc` 方法删除 `URL` 中指定的文件。 `DeleteDoc` 方法与 `GetDoc` 方法具有相同的 `URL`,只是使用 `HTTP Delete` 方法而不是 `Get` 方法。要删除 `xyz.mac`,请使用以下 `URL` 发出 `HTTP DELETE` 请求:
```java
http://localhost:52773/api/atelier/v1/INVENTORY/doc/xyz.mac
```
`Delete` 方法返回以下 `JSON` 消息:
```java
{
"status": {
"errors": [],
"summary": ""
},
"console": [],
"result": {
"name": "xyz.mac",
"db": "INVENTORYR",
"ts": "",
"cat": "RTN",
"status": "",
"enc": false,
"flags": 0,
"content": []
}
}
```
删除文件后,时间戳 `ts` 的值为 `""`(空字符串)。
# 执行 SQL 查询
`Query` 方法对任何 `IRIS` 数据库执行 `SQL` 查询。例如,如果应用程序想要向用户显示一个 `IRIS` 角色列表,它可以通过以下调用发现它们:
```java
POST http://localhost:52773/api/atelier/v1/%25SYS/action/query
```
使用传入 `JSON` 消息中指定的 `SQL` 查询:
```java
{"query": "SELECT ID,Description FROM Security.Roles"}
```
此调用在结果内容元素中以 `JSON` 形式返回 `SQL` 查询的结果。
```java
{
"status": {
"errors": [],
"summary": ""
},
"console": [],
"result": {
"content": [
{
"ID": "%all",
"Description": "The Super-User Role"
},
{
"ID": "%db_%default",
"Description": "R/W access for this resource"
},
...
{
"ID": "%sqltunetable",
"Description": "Role for use by tunetable to sample tables irrespective of row level security"
}
]
}
}
```
可以使用 `Query` 方法来查询 中的任何表。例如,以下调用在名为 `SAMPLES` 的命名空间中查询名为 `Sample.Person` 的表。
```java
POST http://localhost:52773/api/atelier/v1/SAMPLES/action/query
{"query": "SELECT Age,SSN,Home_City,Name FROM Sample.Person WHERE Age = 25"}
```
此调用返回:
```java
{
"status": {
"errors": [],
"summary": ""
},
"console": [],
"result": {
"content": [
{
"Age": 25,
"SSN": "230-78-7696",
"Home_City": "Larchmont",
"Name": "DeLillo,Jose F."
},
{
"Age": 25,
"SSN": "546-73-7513",
"Home_City": "Gansevoort",
"Name": "Klingman,Thelma H."
}
]
}
}
```
文章
Louis Lu · 十月 19, 2023
对于经常进行插入、删除操作的表,位图索引的存储往往会变得不那么高效。
例如,下面定义的表,经常进行大数量的删除操作 (TRUNCATE TABLE)
Class MyWork.MonthData Extends (%Persistent, %Populate)
{
/// Level of satisfaction
Property Satisfaction As %String(VALUELIST = ",満足,やや満足,やや不満,不満,");
/// Age
Property Age As %Integer(MAXVAL = 70, MINVAL = 20);
Index AgeIdx On Age [ Type = bitmap ];
}
对该表进行插入操作后,索引表存储的内容为:
【INSERT】
^MyWork.MonthDataI("AgeIdx",20,1) = $zwc(401,120,4,75,102,10,<omit> 958)/*$bit(5,76,103,107・・・
^MyWork.MonthDataI("AgeIdx",21,1) = $zwc(407,121,29,178,251,2<omit>,732,772,898,960)/*$bit(3・・・
^MyWork.MonthDataI("AgeIdx",22,1) = $zwc(402,96,5,57,74,164,<omit>,0,4)/*$bit(20,63,77,92,10・・・
^MyWork.MonthDataI("AgeIdx",23,1) = $zwc(133,116)_$c(0,0,8,0<omit>,64,0,4)/*$bit(20,63,77,92・・・
^MyWork.MonthDataI("AgeIdx",25,1) = $zwc(404,119,105,155,235<omit>,947)/*$bit(106,156,236,30・・・
^MyWork.MonthDataI("AgeIdx",26,1) = $zwc(128,119)_$c(0,0,0,2,<omit>,0,128)/*$bit(26,80,115,1・・・
<omit the following>
如果你使用 TURNCATE TABLE 删除表中的所有数据,记录的数据将会消失,但是一部分位图索引的内容依然存在
【TRUNCATE】
^MyWork.MonthDataI("AgeIdx",20,1) = $zwc(145,120)/*$bit()*/
^MyWork.MonthDataI("AgeIdx",21,1) = $zwc(151,121)/*$bit()*/
^MyWork.MonthDataI("AgeIdx",22,1) = $zwc(146,96)/*$bit()*/
^MyWork.MonthDataI("AgeIdx",23,1) = $zwc(133,116)_$c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,・・・
^MyWork.MonthDataI("AgeIdx",24,1) = $zwc(131,125)_$c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,・・・
^MyWork.MonthDataI("AgeIdx",25,1) = $zwc(148,119)/*$bit()*/
^MyWork.MonthDataI("AgeIdx",26,1) = $zwc(128,119)_$c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,・・・
<omit the following>
长此以往,频繁的对该表进行插入、删除操作,位图索引所遗留的内容将会对性能造成影响。
我们可以使用%SYS.Maint.Bitmap 类下的 OneClass()或者Namespace()函数对其进行紧凑/维护。
示例代码如下:
// 第一个参数: 类名
// 第二个参数:: 是否记录在journal中; 1:不记录,0:记录
// 第三个参数:: 是否输出执行结果;1:输出,0:不输出
>set st=##class(%SYS.Maint.Bitmap).OneClass("MyWork.MonthData",1.1)
Class: MyWork.MonthData Start Time: 2017-06-21 15:34:54
Global: ^MyWork.MonthDataI("$MonthData")was compressed: 96.15%
Old Size: 0.000(MB) New Size: 0.000(MB)
Global: ^MyWork.MonthDataI("AgeIdx")was compressed: 61.09%
Old Size: 0.004(MB) New Size: 0.002(MB)
Compression time in seconds: 0
该类下的 namespace()方法可对该命名空间下的所有位图索引进行紧凑/维护操作。
详细该类及其方法说明可以参考文档
%SYS.Maint.Bitmap.Namespace()
%SYS.Maint.Bitmap.OneClass()
文章
姚 鑫 · 三月 6, 2021
# 第五章 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`表示``错误。
- **`_`(下划线):如果模式名的第一个字符为下划线,则该字符将被对应包名中的小写`“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`或限定表名`SQLUser`。
`Employee`将生成类`User.Employee`。
因为`USER`是一个保留字,尝试用`USER`的模式名(或任何SQL保留字)指定限定名会导致`SQLCODE -1`错误。
**要返回当前默认模式名,请调用`$SYSTEM.SQL.DefaultSchema()`方法:**
```java
DHC-APP>WRITE $SYSTEM.SQL.DefaultSchema()
SQLUser
```
或者使用以下预处理器宏:
```java
#Include %occConstant
WRITE $$$DefSchema
```
可以使用以下任意一种方式更改默认模式名:
- 进入管理界面。
在系统管理中,选择Configuration,然后选择SQL和对象设置,然后选择SQL。
在这个屏幕上,可以查看和编辑当前系统范围内的默认模式设置。
这个选项设置系统范围的默认模式名。

这个系统范围的设置可以被当前命名空间的`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_USER`。
`OldTable SQLUser.OldTable`下降。
这是一种方便的方式来限定名称,以显式地指示应该使用系统范围的默认模式。
它在功能上与指定非限定名相同。
此关键字不能在DML语句中使用。
## 模式搜索路径
当访问一个现有的表(或视图,或存储过程)进行DML操作时,将从模式搜索路径中提供一个非限定的名称。
按照指定的顺序搜索模式,并返回第一个匹配项。
如果在搜索路径中没有找到匹配的模式,或者没有搜索路径,则使用默认的模式名。
(注意,`#Import`宏指令使用了不同的搜索策略,不会“失败”到默认的模式名。)
- 在嵌入式SQL中,可以使用`#SQLCompile Path`宏指令或`#Import`宏指令来提供架构搜索路径,系统间IRIS使用该路径来解析非限定名称。
`#SQLCompile Path`根据遇到的第一个匹配项解析不限定的名称。
如果搜索路径中列出的所有模式只有一个匹配项,则`#Import`解析非限定名。
- 下面的示例提供了包含两个模式名的搜索路径:
```java
#SQLCompile Path=Customers,Employees
```
- 在动态SQL中,可以使用`%SchemaPath`属性提供模式搜索路径,系统间IRIS使用该路径解析不限定的表名。
可以直接指定`%SchemaPath`属性,也可以将其指定为`%SQL`的第二个参数。
声明`%new()`方法。
下面的示例提供了包含两个模式名的搜索路径:
```java
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`表的所有行,则生成的查询为:
```java
SELECT * FROM Person
```
**因为InterSystems IRIS将不限定的表名解释为`SQLUser`模式中的表名,所以该语句要么失败,要么从错误的表返回数据。
要纠正这一点,编辑查询(在SQL View选项卡上),显式引用所需的模式。
然后查询应该是:**
```java
SELECT * FROM Sample.Person
```
## List模式
`INFORMATION.SCHEMA`。
`SCHEMATA persistent`类列出当前名称空间中的所有模式。
下面的示例返回当前命名空间中的所有非系统模式名:
```java
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。例如,`序列`。
在持久性类定义中,`IdLocation`存储关键字global(例如,对于持久性类`Sample.Person: ^ Sample.PersonD `)包含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`来将`PatientName`和`SSN`字段的组合值在`(PatientName,SSN)[IdKey];`上。
- 基于字段的`RowID`效率比采用系统分配的连续正整数的`RowId`效率低。
- 在`INSERT`上:为构成`RowId`的字段或字段组合指定的值必须唯一。指定非唯一值将生成`SQLCODE -119`“在插入时唯一性或主键约束唯一性检查失败”。
- 在`UPDATE`上:默认情况下,组成`RowId`的每个字段的值都是不可修改的。尝试修改这些字段之一的值会生成`SQLCODE -107`“无法基于字段更新`RowID`或`RowID`”。
当`RowID`基于多个字段时,`RowID`值是由`||`连接的每个组成字段的值。操作员。例如,`Ross,Betsy || 123-45-6789`。 InterSystems IRIS尝试确定基于多个字段的`RowID`的最大长度。如果无法确定最大长度,则`RowID`长度默认为512。
## 隐藏的RowID?
- 使用`CREATE TABLE`创建表时,默认情况下隐藏`RowID`。 `SELECT *`不会显示隐藏字段,而是`PRIVATE`。创建表时,可以指定`%PUBLICROWID`关键字以使`RowID`不隐藏和公开。可以在`CREATE TABLE`逗号分隔的表元素列表中的任何位置指定此可选的`%PUBLICROWID`关键字。不能在`ALTER TABLE`中指定。
- 创建作为表投影的持久类时,默认情况下不会隐藏`RowID`。它由`SELECT *`显示,并且是`PUBLIC`。可以通过指定类关键字`SqlRowIdPrivate`来定义具有隐藏且为`PRIVATE`的`RowID`的持久类。
用作外键引用的`RowID`必须是公共的。
默认情况下,不能将具有公共`RowID`的表用作源表或目标表,以使用`INSERT INTO Sample.DupTable SELECT * FROM Sample.SrcTable`将数据复制到重复表中。
可以使用Management Portal SQL界面“目录详细信息字段”列出“隐藏”列来显示`RowID`是否被隐藏。
可以使用以下程序返回指定字段(在此示例中为`ID`)是否被隐藏:
```java
/// 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"
}
```
最后一个占位符使用案例很棒!谢谢 总结的很好
文章
Lilian Huang · 七月 13, 2022
InterSystems Native SDK for Python是 InterSystems IRIS APIs 的轻量级接口,曾经只能通过 ObjectScript 使用。
准确地说,我对调用 ObjectScript 方法、类方法的能力特别感兴趣。 它可以工作,而且效果很好,但默认情况下,调用只支持标量参数:字符串、布尔值、整数和浮点数。
但如果你想:
- 传递或返回结构,例如字典或列表
- 传递或返回流
您需要编写一些粘合代码或使用这个project (使用 pip install edpy 安装)。 edpy 包会给你一个简单的签名:
call(iris, class_name, method_name, args)
它允许您调用任何 ObjectScript 方法并返回结果。
像这样导入它:
from edpy import iris
call accepts 4 required arguments:- iris - a reference to an established IRIS object- class_name - IRIS class to call- method_name - IRIS method to call- args - list of 0 or more arguments
参数
每个参数可以是以下其中之一:
string字符串(任意长度,如果大于 $$$MaxStringLength或 3641144 个符号,则会自动转换为流
boolean布尔值
integer整数
float 浮动
dict字典(转换为动态对象)
list or tuple列表或元组(转换为动态数组)
字典、列表和元组参数可以递归地包含其他字典、列表和元组(持续性内存)。
返回值
在返回值,我们期望是动态对象/数组或 JSON 字符串/流。 在这种情况下,edpy 会首先将其转换为 Python 字符串,并在可能的情况下将其解释为 Python 字典或列表。 否则,结果将按原样返回给调用者。
就是这样,但让我给你一些 ObjectScript 方法的例子,以及如何使用这个 Python 函数调用它们。
示例1: Pong
ClassMethod Test(arg1, arg2, arg3) As %DynamicArray{ return [(arg1), (arg2), (arg3)]}
调为:
>>> iris.call(iris_native, "User.Py", "Test", [1, 1.2, "ABC"])[1, 1.2, 'ABC']
这里没有惊喜。 参数被打包回一个数组并返回给调用者。
示例 2: 属性
ClassMethod Test2(arg As %DynamicObject) As %String{ return arg.Prop}
像这样调用:
>>> iris.call(iris_native, "User.Py", "Test2", [{"Prop":123}])123
现在进行更嵌入式的调用:
>>> iris.call(iris_native, "User.Py", "Test2", [{"Prop":{"Prop2":123}}])
{'Prop2': 123}
如果属性太长也没关系 - 流将用于将其发送到 IRIS 和/或返回:
ret = iris.call(iris_native, "User.Py", "Test2", [{"Prop":"A" * 10000000}])
>>> len(ret)
10000000
如果您需要保证InterSystems IRIS 端的流,您可以使用%Get:
set stream = arg.%Get("Prop",,"stream")
如果流是 base64 编码的,您可以使用以下命令自动对其进行解码:
set stream = arg.%Get("Prop",,"stream<base64")
示例 3: 字符串或流
ClassMethod Test3(arg As %Stream.Object) As %String
{
set file = ##class(%Stream.FileCharacter).%New()
set file.TranslateTable = "UTF8"
set filename = ##class(%File).ManagerDirectory() _ "test.txt"
do file.LinkToFile(filename)
if $isObject(arg) {
set sc = file.CopyFromAndSave(arg)
} else {
do file.Write(arg)
set sc = file.%Save()
}
if $$$ISERR(sc) {
set jsonret = {"status":0, "payload":($system.Status.GetErrorText(sc))}
} else {
set jsonret = {"status":1}
}
quit jsonret.%ToJSON()
}
这里我们将字符串或流写入 <mgr>test.txt。
>>> iris.call(iris_native, "User.Py", "Test3", ["😊"])
{'status': 1}
注意:在所有代码示例中输入为“ x1f642;“。
如果我打开文件,我会看到一个 😊 而不是两个 ?? - 所以我们保留编码。
>>> iris.call(iris_native, "User.Py", "Test3", ["🙂" * 10000000])
{'status': 1}
为简便起见,我将省略文件输出,但它就在那里。
最后,通过在内部传递一个动态对象或数组,您可以完全避免字符串/流二分法,即使您不知道该属性是比字符串限制短还是长。 在这种情况下,您始终可以像流一样获取可疑属性。
示例4: 返回流
ClassMethod Test4(arg As %DynamicArray) As %String
{
return arg.%Get(0)
}
看起来是这样:
>>> ret = iris.call(iris_native, "User.Py", "Test4", [["😊" * 10000000]])
>>> len(ret)
10000000
>>> ret[:5]
'😊😊😊😊😊'
还有一件事
还有一个 get_iris(ip="localhost", port=1972, namespace="USER", username="_SYSTEM", password="SYS") 函数可以让您获得一个工作的 IRIS 对象。
所以这里有一个完整的例子,如果你想自己尝试一下:
首先加载 User.Py class 并安装 edpy python 库:
pip install edpy
然后在python调用中:
from edpy import iris
iris_native = iris.get_iris()
iris.call(iris_native, "User.Py", "Test", [1, 1.2, "ABC"])
iris.call(iris_native, "User.Py", "Test2", [{"Prop":123}])
iris.call(iris_native, "User.Py", "Test2", [{"Prop":{"Prop2":123}}])
ret2 = iris.call(iris_native, "User.Py", "Test2", [{"Prop":"A" * 10000000}])
iris.call(iris_native, "User.Py", "Test3", ["😊"])
iris.call(iris_native, "User.Py", "Test3", ["😊" * 10000000])
ret4 = iris.call(iris_native, "User.Py", "Test4", [["😊" * 10000000]])
结论
适用于 Python 的 Native SDK 是一个强大的工具,为您提供对 InterSystems IRIS 的完整且不受限制的访问。 我希望这个项目可以为您节省一些时间来编组 InterSystems IRIS 调用。 是否有一些它不支持的方法参数组合? 如果是这样,请在评论中分享您是如何调用的。
链接:
Native SDK Docs
User.Py class
Repo
原文请参考链接:https://community.intersystems.com/node/521336
文章
姚 鑫 · 八月 23, 2022
# 第十章 配置数据库(二)
# 本地数据库
“本地数据库”页面显示关于系统上的数据库的以下信息:
- `Name`—数据库名称。
- `Mirror`——如果数据库是镜像的,则镜像的名称;
- `Directory` - `IRIS.DAT` 文件的位置。
- `Size` 大小 (MB) — 以 `MB` 为单位的数据库大小。
- `Status` 状态 — 指定数据库是挂载、卸载还是卸载;如果已挂载,则指定它是否具有只读或读写权限。
- `Resource Name`资源名称 — 控制对数据库的访问的数据库资源的名称;
- `Encrypted` — 指定数据库是否加密;
- `Journal` 指定数据库是否被记录;
## 创建本地数据库
要创建本地数据库,请导航到本地数据库页面(系统管理 > 配置 > 系统配置 > 本地数据库)。
1. 单击创建新数据库以打开数据库向导。
2. 在文本框中输入数据库名称。数据库名称必须:
- 尚未在 `IRIS` 实例中使用
- 长度在 `1` 到 `30` 个字符之间
- 以字母字符或下划线开头;其余部分可以包括字母数字字符、破折号或下划线
3. 首次使用特定浏览器在 `IRIS` 实例中创建本地数据库时,必须
- 输入数据库目录的名称,在这种情况下,包含 `IRIS.DAT` 文件的目录在确认后将在 `c:\InterSystems\mgr` 中创建
- 单击文件夹图标浏览到现有目录,在这种情况下,将在该目录中创建 `IRIS.DAT` 文件
此后,默认情况下,将在与先前数据库目录相同的位置创建一个与提供的数据库名称相同的目录,其中包含 `IRIS.DAT` 文件。例如,如果首先在 `c:\InterSystems\mgr` 下的任何目录中创建数据库 `db22`,当再次单击 `Create New Database` 并在 `Enter the name of your database` 框中输入 `db33` 时,`c:\InterSystems\mgr\db33` 会自动填写到数据库目录文本框中。如果将其更改为 `c:\InterSystems\db33` 并创建 `db33`,则下次将填充基本目录 `c:\InterSystems`。
注意:不支持在配置数据库目录时使用符号链接。
4. 单击下一步继续配置数据库。如果指定的目录中已经存在 `IRIS.DAT` 文件,会收到警告,并且可以
- 单击完成以使用现有文件,在这种情况下,所有数据库特征都由 `IRIS.DAT` 文件确定。您通常会在从另一个实例复制或移动数据库时执行此操作,或者在同一系统上临时挂载在另一个实例中创建的数据库时执行此操作。
- 单击 `Back` 指定另一个目录,然后再次单击 `Next` 以在下一步中继续指定新数据库的特征。
5. 在 `Initial Size` 文本框中,键入数据库大小的兆字节数(默认值为 `1 MB`)。
**注意:不能创建或编辑数据库,使其大小大于可用的总磁盘空间。如果指定的大小在磁盘可用空间的 `90%` 以内,会收到警告并且必须确认操作。**
6. 从 `Block size for this database will be` 下拉列表中选择所需的块大小。默认情况下,所有新数据库都使用 `8 KB` 的块大小创建。
注意:请勿从下拉列表中选择 `8 KB` 以外的块大小,除非已阅读并理解大块大小注意事项`/`
7. 从 `Journal globals` 中选择是否要在此数据库中记录全局变量`?`下拉列表。
注意:如果将数据库配置为存储临时全局变量,将 `Journal globals` 属性设置为 `No` 与将临时全局变量存储在 IRSTEMP 中是不同的。
8. 如果激活了加密,可以通过选择是加密数据库来加密这个数据库?。
9. 如果实例是镜像的一部分,可以通过为 `Mirrored Database?` 选择 `Yes` 来将此数据库添加到镜像中。
10. 从此面板开始,可以单击下一步。继续配置数据库或完成以接受剩余的默认值。
11. 选择资源来控制对该数据库的访问:
- 默认值 — `%DB_%DEFAULT`
- 现有 - 从现有数据库资源列表中选择
- 新建 — 创建新的数据库资源(新名称默认为 `%DB_%` 数据库名称)
12. 单击下一步查看数据库属性列表。
13. 单击完成以添加数据库。
现在已准备好配置和管理新数据库。
**注意:为防止意外损坏数据库,不能打开或写入名为 `IRIS.DAT` 的操作系统文件,即使它不是已安装的数据库。**
文章
Qiao Peng · 六月 11, 2023
数据平台一直在进化:从数据中心到数据中台,离散的数据资产得到进一步梳理和整合、按业务封装数据和操作数据的方法,并逐步提供了企业统一的访问、更新、检索、查询等数据服务。
然而市场上不乏听到数据平台的成功案例,却鲜见这些案例得到大规模推广。原因是什么呢?
一. 传统数据平台建设的挑战
传统数据平台的数据模型基于各自厂商的理解,缺乏统一行业数据模型和行业语义。可供参考的国内卫生信息数据元、数据集标准并非完整的行业语义,例如没有业务实体模型和数据元关系定义。传统的数据平台建设通常根据业务域,围绕数据应用需求组织数据。经常看到按业务域划分为CDR(临床数据中心)、ODR(运营数据中心)、RDR(科研数据中心)......
这造成了几个挑战:
1. 按业务域、而非业务实体来划分数据,虽然方便相应的业务域数据分析,但跨业务域重叠的业务实体数据,例如患者,需要跨数据中心同步。这些同步由于数据模型上的差异,往往非全息拷贝。随着同步次数越多,跨数据中心的数据越失真,造成数据资产多源不统一、数据资产一致性问题和时效性问题。
2. 数据平台产品语义表达上参差不齐,业务用户依赖数据工程师对数据理解和操作,无论是统计分析还是机器学习,海量的实施工作无法满足业务敏捷性要求;
3. 数据平台及数据应用建设依赖单一厂商的能力,而建设成果,包括数据工具、分析指标和应用都无法跨数据平台复用。往往项目都在做低水平重复建设。
4. 数据互操作标准化程度低,数据的同步、迁移困难。在缺乏数据层互操作性的情况下,各类数据中心建设的依然是数据孤岛。
5. 由于数据中心往往忽视互操作建设,数据缺乏流动,进入数据平台后,往往成为死水一潭。
二. 如何应对挑战
如何解决这些数据平台建设困境?应该如何建设数据平台?
数据资产不是仅为分析服务的,更重要的是作为生产要素在生产全过程中发挥价值- 这就涉及到数据生成、采集、交换、决策… 在这个全过程链条上的数据互操作能力尤为重要。
HIMSS将互操作定义为4级:基础级、结构级、语义级和组织级,并认为只有到达语义级,才是标准的、才能实现广泛的互操作能力。要达到语义级的互操作,需要进行五位一体的标准化:词汇/术语标准、内容标准、传输标准、隐私和安全标准、标识符标准。
随着我们越来越依赖于机器处理数据、发掘数据背后的知识,对数据资产的开放性和互操作性的要求达到了更高的水平 - 实现机器可以理解的互操作。2016年发表在Scientific Data针对科学数据管理和监管,提出了数据的可发现(Findable)、可访问(Accessible)、可互操作(Interoperable)、可复用(Reusable)的FAIR指导原则。
这些原则的核心是让机器可以理解数据所需的语义层面的要求,尤其是可互操作和可复用两部分提到的语义级要求 - 广泛使用的语言、词汇表、元数据引用、符合相关领域的社区标准...
大家都不约而同地指向了统一行业语义。传统数据中心面临的上述挑战,正是因为缺乏统一的行业语义、缺乏统一的语义级互操作。
那什么是统一语义?
三. 统一语义数据平台
圣经记载人类曾经联合起来兴建能通往天堂的高塔 - 巴别塔、也称通天塔。上帝为了阻止人类的计划,让人类说不同的语言。人类相互之间不能沟通,造塔计划因此失败。
统一语言是数据能够互相理解、并利用数据的前提。
语言包含2个层面:
1. 语义:真实世界事物及其关系的表达方法。例如不同电子病历系统对疑似肺癌的记录,可能记录为以下三种之一:
A。问题: 癌症 身体部位:肺 确定程度:疑似
B。问题: 肺癌 确定程度:疑似
C。问题: 疑似肺癌
这三种语义表达不统一。没有统一的语义就像图里的电源插座,每个国家规格都不同,是不可能互联互通的。
2. 语法:语言的结构规则,包括词法和句法。而词法和句法都可能有歧义,就像图中示例的那样。
行业数据需要通过统一语义达到互联互通。对数据而言,统一语义不仅在数据模型(语义)、也在数据使用方式(语法)上。不仅数据语义是统一的,操作/互操作数据的方法也是统一的,并且需要能避免词法和句法歧义,才能达到语义级互操作能力!
是不是一定要统一语义?要看数据用途:对于特定的、简单的数据任务,简化的数据模型和数据处理方法可能已经足够,但对于复杂的、跨领域的数据任务,如广泛的自然语言处理、知识图谱构建、大规模机器学习等,统一语义是非常有价值的。
显然,对于数据平台这类多用途平台,应该统一数据语义。
四. 如何建设行业统一语义数据平台
数据平台建设向统一语义迈进,而统一的行业语义模型,应该针对行业用户友好:直观、完整、语义简单、没有二义性,易于数据探索与使用。
统一语义是指要统一物理数据模型和操作数据的语言吗?是要限定到特定的技术栈吗?
先看一下数据库的结构化查询语言(SQL):众多的关系型数据库、甚至很多非关系型数据库都支持ANSI SQL语言。SQL定义了自己的语义 - 表、字段、视图、存储过程... 和自己的语法 - 数据定义语言(DDL)、数据操作语言(DML),但它并没有定义任何数据的物理存储方案!也正因如此,任何数据库厂商、任何数据物理存储方案,都可以通过自己的SQL编译器来支持SQL和SQL客户端,从而屏蔽数据库物理层差异,使用相同的SQL语言共同建设SQL生态。这也是SQL生态壮大的原因之一。
SQL的成功告诉我们,统一行业语义是对行业数据的逻辑表达层的要求,它不应对任何数据库技术底层做要求,也就是不应限定任何技术栈。
前面提到统一的数据操作/互操作能力是统一语义的一部分,是要用单一的数据操作方法吗?数据有多种操作方式,每种操作方式都有自己适用的场景,如下:
对同一份数据提供多模型的操作能力,会极大提升语义层的操作/互操作的便捷性,是非常重要的统一语义特性。重要的是可以针对同一份语义数据进行多种模型的操作/互操作,而不是建立针对每种模型的多套语义,并进行数据复制。
也就是说统一语义,并不是数据只能有一种操作/互操作方式,而应提供对同一份统一语义数据的多种操作/互操作方式。
五. InterSystems统一语义数据平台建设
基于上面的建设思路,InterSystems的医疗信息统一语义平台通过对行业语义的理解和其智能数据编织能力,提供医疗信息数据基座。
5.1 行业语义选择 - FHIR
行业语义应具有开放性、成熟性、准确性、完整性、灵活性、简单性、非二义性、可互操作性、机器可理解,并被广泛接受与认可。纵观医疗信息行业,虽然有不少通用数据模型,但目前最满足上述条件的是HL7 FHIR。它的资源模型覆盖面广,不仅是临床、还包括管理、科研等;不仅包括通用数据模型 - FHIR资源模型,还有对其统一的互操作方法 - FHIR API;按80/20原则设计,允许对资源模型和API进行扩展;资源模型和API简单、并有详细的用例指南;FHIR资源模型、API、扩展都可以被计算机理解;FHIR拥有庞大的用例,并且其触角不断扩展到医疗信息应用的各个层面和各个方向。
另外,更重要的是,FHIR的定位就是行业语义标准 - 逻辑层的标准,任何厂商只需要提供自己的FHIR服务器,就可以利用任何技术栈发布统一的FHIR资源和FHIR API,而屏蔽底层不同类型的数据存储方案、数据模型和数据操作方法。因而它是一个强大的生态标准,所有厂商和用户都可以参与其中。
InterSystems的解决方案选择FHIR作为统一语义,在支持FHIR的6种互操作范式的基础上,提供对FHIR资源的SQL投射 - 无需数据拷贝,就可以使用SQL大规模查询FHIR资源,对统计分析、机器学习提供简单易用的数据操作能力。
5.2 利用数据编织技术,无需推倒重来
如果正在规划数据平台,应考虑按统一语义建设。如果已经建设有各类数据中心,并不需要将已有的建设成果推倒重来。InterSystems的解决方案通过数据编织技术,将数据源编织在一起,并建立逻辑上的统一语义层。原有数据中心和其各类应用继续运行,通过统一语义层来支撑新的数据利用和应用创新。
InterSystems利用数据编织技术,提供针对所有数据源、数据模型、互操作标准的接入能力和适配器。现有的数据中心被视为数据源,只需接入而无需推倒现有建设成果。
InterSystems的多模型能力,将这些离散的数据源统一转换、表达,将多数据源的数据,以FHIR资源这个统一语义模型,发布多种数据模型的数据服务:包括FHIR JSON模型、FHIR对象模型、FHIR SQL模型,满足多种应用场景对统一语义数据的最佳操作方式。
InterSystems数据引擎,为统一语义层提供高性能、横向可扩展的持久化层,满足不同规模的数据用户所需的性能和弹性。
InterSystems提供FHIR与互联互通、HL7 V2、CDA等通用模型的开箱即用的转换能力和对用户自定义模型的自定义转换能力,提供全方位的统一语义互操作能力。
问题
water huang · 四月 24, 2021
最近尝试使用 Set Ciphertext=##class(%SYSTEM.Encryption).RSAEncrypt(Plaintext,PublicKeyStr)来加密数据,但是加密失败,参考了以下资料https://community.intersystems.com/post/format-public-key-when-using-rsaencrypt-method-systemencryption-or-systemencryptionrsaencrypt
https://blog.ndpar.com/2017/04/17/p1-p8/
生成的公钥为
-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvl8YRMOJMUOyK5NzWo+8FD8dGR3DuPwn7M13If+rwYp18TEL58NneFdCL+Jjytx4axq+uhPuup5HtmEm22+PQTzFlXuAhXf3oUm4LQl4zgSb14D6gfqac9DqbVhm+aUjDfItFapM35/DH2cvc+rbBhu4Q5Y6kJwcUK0UbRv3swQIDAQAB-----END PUBLIC KEY-----
转换为pkcs1后的内容为
-----BEGIN RSA PUBLIC KEY-----MIGJAoGBANHPwS9+rVB1TJZM1UGLCBan3CY8TIDPkDAftkI504l68vdUWdPlmcN1YZzCGDK4+LvtzdqLXb/XSA3SxsUrA5toWSh45K7/jDzXRcb0AYiUTWGfpeMrHdcGNL07gVT11FM8M+0Jc5Sw6dvMKVXE9wzAxwgaJo0d8zW8Crbx6iI3AgMBAAE=-----END RSA PUBLIC KEY-----
文件保存为utf-8和ansi格式都不行。错误信息为
error:0906D06C:PEM routines:PEM_read_bio:no start line; 2016之后的版本,RSAEncrypt可以接收X.509证书或RSA公钥,而2016中RSAEncrypt接收证书参数。Ensemble2016上使用RSAEncrypt,如果拿不到证书,仅用公钥,请联系InterSystems 销售工程师。 好的,谢谢