通用`Query`解决方案(上)

简介: 通用`Query`解决方案

通用Query解决方案

简介

什么是Query

Query是一种查询方法,用于查找满足条件的数据,将结果以数据集的形式展现出来。

Query类别

  • SQL Query,使用类 %SQLQuerySQL SELECT 语句。
  • 自定义Query,使用类 %Query 和自定义逻辑生成查询数据。

说明:在讲通用Query解决方案之前,我们先了解一下Query的基础和基础使用,有助于理解实现原理。如果读者了解Query基本使用,可跳过此章节,直接阅读“现状”。

Query基本使用

SQL Query基本使用

Query QueryPersonByName(name As %String = "") As %SQLQuery(COMPILEMODE = "IMMEDIATE", CONTAINID = 1, ROWSPEC = "id:%Integer:ID,MT_Name:%String:name,age:%String,no:%String", SELECTMODE = "RUNTIME") [ SqlName = QueryPersonByName, SqlProc ]
{
  SELECT top 10 ID, MT_Age, MT_Name, MT_No
  FROM M_T.Person
  WHERE (MT_Name %STARTSWITH :name)
  ORDER BY id
}

说明:

  • Query - 声明Query方法关键字
  • QueryPersonByName - Query方法的名称。
  • name As %String = "" - Query方法的参数。
  • %SQLQuery-Query类型为%SQLQuery
  • %SQLQuery%Query的子类,使用Query的简单的形式,可在方法体内直接编写Select SQL语句。
  • COMPILEMODE- 为%SQLQuery的参数,表示编译方式。
  • IMMEDIATE - 立即编译,当检测当前SQL语句是否正确。
  • DYNAMIC - 动态编译 ,在运行时在编译SQL语句。
  • CONTAINID - 置为返回 ID 的列的编号。
  • 1 - 返回ID列。
  • 0 - 不返回。
  • SELECTMODE- 表示显示方式。
  • RUNTIME - 无
  • ODBC - 以ODBC方式显示数据。
  • DISPLAY - 以显示方式显示数据。
  • LOGICAL - 以逻辑方式显示数据。
  • ROWSPEC - 提供数据列名称、数据类型、描述。用引号和逗号分隔的变量名和数据类型列表。格式如下:
ROWSPEC = "id:%Integer:ID,age:%String,MT_Name:%String:name,no:%String"
  • id - 表示数据列名称。
  • %Integer - 表示数据类型。
  • ID - 数据描述。
  • SqlProc - 表示该方法可作为存储过程调用。
  • SqlName - 调用的存储过程名称。
  • 无声明调用方式 - call M.Query_QueryPersonByName()
  • 声明调用方式 - call M.QueryPersonByName()

  • 运行Query方法 - d ##class(%ResultSet).RunQuery(className, queryName, arg...)
USER>d ##class(%ResultSet).RunQuery("M.Query", "QueryPersonByName")
 
ID:age:name:no:
1:21:yaoxin:314629:
2:29:yx:685381:
3:18:Umansky,Josephine Q.:419268:
4:27:Pape,Ted F.:241661:
5:25:Russell,Howard T.:873214:
6:30:Xenia,Ashley U.:420471:
7:24:Rotterman,Martin O.:578867:
8:18:Drabek,Hannah X.:662167:
9:19:Eno,Mark U.:913628:
11:18:Tsatsulin,Dan Z.:920134:

自定义Query基本使用

在使用自定义Query时,一般都遵循固定的模版。在同一个类中定义以下类方法:

  • QueryName - 在Query方法类型指定 %Query
  • QueryNameExecute — 此方法主要编写获取数据的业务逻辑,得到数据集。
  • QueryNameFetch — 此方法遍历数据集。
  • QueryNameClose — 此方法删除临时数据或对象。

说明:下面示例展示常用“套路”的自定义Query模版,此模版仅仅是常用的一种,并非是固定写法。


定义QueryName

Query QueryPersonByAge(pAge As %String = "", count As %Integer = "10") As %Query(ROWSPEC = "id:%Integer:ID,MT_Name:%String:name,age:%String,no:%String")
{
}

定义名为QueryPersonByAgeQuery类型指定为%Query。并将查询定义的主体留空。


定义QueryNameExecute

ClassMethod QueryPersonByAgeExecute(ByRef qHandle As %Binary, pAge As %String = "", count As %Integer = "10") As %Status
{
  s pid = $i(^CacheTemp) // 注释1
  s qHandle = $lb(0, pid, 0) // 注释2
  s index = 1 // 注释3
  
  /* 业务逻辑代码 注释4 */ 
  s id = ""
  for {
    s id = $o(^M.T.PersonD(id))
    q:(id = "")
    q:(id > count)
    s data = ^M.T.PersonD(id)
    s i = 1
    s name = $lg(data, $i(i))
    s age = $lg(data, $i(i))
    continue:(age < pAge)
    s no = $lg(data, $i(i))
    d output
  } 
  /* 业务逻辑代码 */

  q $$$OK
  
output
  s ^CacheTemp(pid, index) = $lb(id, age, name, no) // 注释6 
  s index = index + 1 // 注释7
}

QueryNameExecute() 方法提供所有需要的业务逻辑。方法的名称必须是 QueryNameExecute() ,其中 QueryName是定义Query的名称。

其中:

  • qHandle - 用于与实现此查询的其他方法进行通信。qHandle 可以为任何类型。默认为%Binary
  • pAge As %String = "", count As %Integer = "10"Query传入参数,可作为业务逻辑的条件使用。
  • 注释1处代码,s pid = $i(^CacheTemp) - 获取pid
  • 注释2处代码,s qHandle = $lb(0, pid, 0) - 数组内第一个元素0表示循环的开始,第二个元素pid用于获取^CacheTemp数据,第三个元素0用于遍历^CacheTemp起始节点。
  • 业务逻辑代码 - 为获取数据集的主要实现逻辑。
  • 注释3处代码与注释7处代码,为^CacheTemp增加索引节点。

注释6处代码,s ^CacheTemp(pid, index) = $lb(id, name, age, no) - 为^CacheTemp赋值为后续遍历使用。

  • 这里数据格式为%Library.List形式,这样Fetch方法就不用转类型了,否则Fetch方法还需要将数据转为内部列表格式。

定义QueryNameFetch

ClassMethod QueryPersonByAgeFetch(ByRef qHandle As %Binary, ByRef row As %List, ByRef end As %Integer = 0) As %Status [ PlaceAfter = QueryPersonByAgeExecute ]
{
  s end = $li(qHandle, 1) // 注释1
  s pid = $li(qHandle, 2)
  s index = $li(qHandle, 3)
  s index = $o(^CacheTemp(pid, index)) // 注释2
  if index = "" {  // 注释3
    s end = 1
    s row = ""
  } else { 
    s row = ^CacheTemp(pid, index)
  }
  s qHandle = $lb(end, pid, index) // 注释4
  q $$$OK
}

QueryNameFetch() 方法必须以 %Library.List 格式返回单行数据。方法的名称必须是 QueryNameFetch,其中 QueryName是定义Query的名称。

其中:

  • qHandle - 用于与实现此查询的其他方法进行通信。它的值应该是Execute定义的值。
  • row - 表示要返回的一行数据的值类型为 %Library.List,如果没有返回数据则为空字符串。
  • end - 当到达最后一行数据时,end必须为 1。如果不指定为1,则会无限循环。
  • PlaceAfter - PlaceAfter方法关键字控制此方法在生成代码中顺序。这里表示在方法QueryPersonByAgeExecute生成之后在生成QueryPersonByAgeFetch方法。
  • 注释1处代码, 1~3 行,解析qHandle数组的值获取endpidindex
  • 注释2处代码,s index = $o(^CacheTemp(pid, index)) 根据解析到的pidindex开始遍历。
  • 注释3处代码,将遍历的^CacheTemp(pid, index)每行属于赋值给row,如果index为空,则一定要将end赋值为1
  • 注释4处代码,s qHandle = $lb(end, pid, index)将取到的endindex重新复制给qHandle为取下一行数据做准备。

注:Fetch方法为多次执行,有多少行数据就遍历多少遍。ExecuteClose方法为一次执行。


定义QueryNameClose

ClassMethod QueryPersonByAgeClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = QueryPersonByAgeExecute ]
{
  s pid = $li(qHandle, 2) // 注释1
  k ^CacheTemp(pid) // 注释2
  q $$$OK
}

QueryNameClose() 方法在数据检索完成后删除清理临时数据或对象等结束收尾工作。方法的名称必须是 QueryNameClose() ,其中 QueryName是定义Query的名称。

  • qHandle - 用于与实现此查询的其他方法进行通信。
  • 注释1处代码,获取qHandle 保存的pid
  • 注释2处代码,清除临时生成的^CacheTemp

调用自定义Query

USER> d ##class(%ResultSet).RunQuery("M.Query", "QueryPersonByAge","20")
 
ID:name:age:no:
1:yaoxin:21:314629:
2:yx:29:685381:
4:Pape,Ted F.:27:241661:
5:Russell,Howard T.:25:873214:
6:Xenia,Ashley U.:30:420471:
7:Rotterman,Martin O.:24:578867:
  • 这里查询是年龄大于20岁并且id小于10的所有人员信息。

使用Query

使用%SQL.Statement对象调用Query

可以在如下示例代码中使用类查询:

ClassMethod UseStatement()
{
  s statement = ##class(%SQL.Statement).%New()
  s sc = statement.%PrepareClassQuery("M.Query", "QueryPersonByName")
  if $$$ISERR(sc) { 
    q $system.Status.GetErrorText(sc)
  }
  s rs = statement.%Execute("Y")
  while rs.%Next() {
    w rs.%Get("MT_Name"),!
  }
  q $$$OK
}

USER>w ##class(M.Query).UseStatement()
Young,Ralph P.
Yang,Thelma A.
Yang,Aviel X.
Yu,Brendan G.
Yezek,Terry K.
Yezek,Barbara L.
Yoders,Christine D.
Yezek,Debra I.
Yeats,Patrick J.
Yancik,Debra R.
1


  1. 使用%New()创建%SQL.Statement的对象。
  2. 调用该对象的%PrepareClassQuery(pClassName As %String = "", pQueryName As %String = "") As %Library.Status方法。
  • pClassName - 定义要使用的Query类的全限定名称。
  • pQueryName - 该类中Query名称。
  • 此方法返回%Status值。

调用%SQL.Statement实例的%Execute(%parm...) As %SQL.StatementResult方法,

  • %parm... - 定义Query的参数,该参数为可变参数。
  • 此方法返回%SQL.StatementResult对象。
  1. 使用%SQL.StatementResult的方法从结果集中检索数据。

使用%ResultSet对象调用Query

可以在如下示例代码中使用类查询:

ClassMethod UseResultSet()
{
  s rs = ##class(%ResultSet).%New()
  s rs.ClassName = "M.Query"
  s rs.QueryName = "QueryPersonByName"
  d rs.Execute("X")
  while (rs.Next()) {
    w rs.%Get("MT_Name"),!
  }
  q $$$OK
}
USER>w ##class(M.Query).UseResultSet()
Xenia,Fred H.
Ximines,Alfred F.
Xerxes,Ted S.
Ximines,Debra R.
Xander,Mary I.
Ximines,Terry B.
Xenia,Yan J.
Xerxes,Rhonda C.
Ximines,Sally B.
Xander,Howard T.
1
  1. 使用%New()创建%ResultSet的对象。
  • 可以在%New(pClassName _ "||" _ pQueryName )方法传入类的全限定名称与Query名称。
  1. 设置该对象的ClassName属性为类的全限定名称。
  1. 设置该对象的QueryName属性为类的Query名称。
  2. 调用%ResultSet实例的Execute(args...) As %Status 方法,
  • args... - 定义Query的参数,该参数为可变参数。
  1. Execute执行成功后根据%ResultSet对象检索数据。

注:%ResultSet方式使用QueryIRIS中被废弃,不再推荐使用。

通用`Query`解决方案(中):https://developer.aliyun.com/article/1516551

相关文章
|
23天前
|
SQL JSON BI
通用`Query`解决方案(中)
通用`Query`解决方案
21 0
|
23天前
|
JSON 数据格式
通用`Query`解决方案(下)
通用`Query`解决方案
18 0
通用`Query`解决方案(下)
|
1月前
|
数据库
stream-query开源合规
stream-query开源合规
18 0
|
1月前
|
SQL
SQL标准的四大分类
SQL标准的四大分类。
11 2
|
1月前
|
存储 编译器 C语言
【C++基础】 --- C++在C的基础上对一些语法的增强
【C++基础】 --- C++在C的基础上对一些语法的增强
18 3
|
6月前
|
Java 数据处理 数据库
stream-query加入dromara开源组织
stream-query加入dromara开源组织
50 1
|
11月前
|
SQL 消息中间件 缓存
12种接口优化的通用方案
12种接口优化的通用方案
160 0
|
11月前
|
前端开发 Java 数据库连接
JPA-querydsl增强工具,query-dsl-plus,现在已开源并推送到mvnrepository
使用JPA,随着需求的变更,数据查询条件也会越来越复杂,往往前端改动了,后端还需要做调整,很是麻烦,想着将查询条件封装成string,随时可以更改,一个查询接口就能完成绝大多数条件查询。
107 0
ts重点学习91-分布式条件类型
ts重点学习91-分布式条件类型
78 0
ts重点学习91-分布式条件类型
|
SQL 弹性计算 关系型数据库
PostgreSQL 12 preview - CTE 增强,支持用户语法层控制 materialized 优化
标签 PostgreSQL , CTE , materialized , not materialized , push down 背景 PostgreSQL with 语法,能跑非常复杂的SQL逻辑,包括递归,多语句物化计算等。 在12以前的版本中,WITH中的每一个CTE(common table express),都是直接进行物化的,也就是说外层的条件不会推到CTE(物化节点)里
856 0

热门文章

最新文章