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

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

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

现状

上面2个Query的基本使用示例,可能是大家最常用的两种方式。

但是经常写查询或者写报表的同学可能会面临如下几个问题:

  1. 每次写Query都需要定义列头ROWSPEC很麻烦,是否可以自己指定列头ROWSPEC?
  2. 现在很多方法返回的值是JSON,如何将JSON方法快速转成Query?
  3. 是否可以写一个通用Query,只需要写Execute主要逻辑即可?
  1. 是否可以优化现在的模版,例如^CacheTemp替换成^||CacheTemp?

以上的问题,都是可以解决的,请继续阅读下面文章部分。

方案

如果想实现通用Query还得需要知道一个回调方法QueryNameGetInfo。

ClassMethod Json2QueryGetInfo(ByRef colinfo As %List, ByRef parminfo As %List, ByRef idinfo As %List, ByRef qHandle As %Binary, extoption As %Integer = 0, extinfo As %List) As %Status
{
  q $$$OK
}

其中:

  • colinfo - 此参数最关键用于定义ROWSPEC列头部分。为在 ROWSPEC 中声明的每一列包含一个列表元素。形式为 name:exttype:caption 。
  • name - 为列头名称。
  • exttype - 为数据类型。
  • caption - 为描述说明。
  • colinfo 类型必须是%Library.List,定义的列头的类型也是%Library.List。

例如:

ClassMethod QueryPersonByAgeGetInfo(ByRef colinfo As %List, ByRef parminfo As %List, ByRef idinfo As %List, ByRef %qHandle As %Binary, extoption As %Integer = 0, extinfo As %List) As %Status
{
  s colinfo = $lb($lb("id", "%Integer", "ID"), $lb("age", "%String", ""), $lb("MT_Name", "%String", "name"), $lb("no", "%String", ""))
  s parminfo = ""
  s idinfo = ""
  q $$$OK
}

说明:Query执行顺序 Execute -> GetInfo -> Fetch(n) -> Close。

下面分别描述以下几种解决方案:

  • 通过Json数据或方法动态生成Query
  • 通过Select Sql语句动态生成Query
  • 通过Query动态生成Query
  • 支持传统的Query并通过参数形式生成Query列
  • 定义通用Query,只需要实现Exceute方法

通过Json数据或方法动态生成Query

定义Json方法

  • Json方法可任意定义,此示例仅为了测试使用。如下方法:查询当前电脑盘符以Json结果输出。
/// desc:查询盘符
ClassMethod QueryDrives(fullyQualified = 1, type = "D")
{
  s array = []
  s rs = ##class(%ResultSet).%New()
  s rs.ClassName = "%File"
  s rs.QueryName = "DriveList"
  d rs.Execute(fullyQualified)
  while (rs.Next()) {
    s drive = rs.Get("Drive")
    s drive = $zcvt(drive, "U")
    s obj = {}
    s obj.type = "D"
    continue:(type '= "D")
    s obj.drive = drive
    d array.%Push(obj)
  }
  q array
}

运行:

USER> w ##class(M.Query).QueryDrives().%ToJSON()
[{"type":"D","drive":"C:\\"},{"type":"D","drive":"D:\\"},{"type":"D","drive":"E:\\"},{"type":"D","drive":"F:\\"},{"type":"D","drive":"G:\\"}]

定义QueryName

Query Json2Query(className As %String, methodName As %String, arg...) As %Query
{
}

其中:

  • className - 类名。
  • methodName - 需要执行的Json方法名称。
  • arg... - 需要执行的方法参数。

定义QueryNameExecute

ClassMethod Json2QueryExecute(ByRef qHandle As %Binary, className As %String, methodName As %String, arg...) As %Status
{
  s array = $classmethod(className, methodName, arg...) // 注释1
  if ('$isobject(array)) { // 注释2
    s array = [].%FromJSON(array)
  }
  q:('array.%IsA("%Library.DynamicArray")) $$$ERROR($$$GeneralError, "不是数组对象") // 注释3
  q:(array.%Size() = 0) $$$ERROR($$$GeneralError, "没有数据") // 注释4
    s qHandle = array // 注释5
    q $$$OK
}
  • 注释1代码,利用反射机制调用目标方法并获取返回值。
  • 注释2代码,判断如果返回的字符串则转成Json对象。
  • 注释3代码,判断该对象不是%Library.DynamicArray抛出错误信息。
  • 注释4代码,Json数组长度为0抛出错误信息。
  • 注释5代码,获取数组对象。

定义QueryNameGetInfo

ClassMethod Json2QueryGetInfo(ByRef colinfo As %List, ByRef parminfo As %List, ByRef idinfo As %List, ByRef qHandle As %Binary, extoption As %Integer = 0, extinfo As %List) As %Status
{
  s colinfo = $lb() // 注释1
  s count = 1 
  s obj = qHandle.%GetIterator()
  if obj.%GetNext(.key, .value) { 
    s obj = value.%GetIterator() 
    while obj.%GetNext(.objKey, .objValue) { // 注释2
      s $li(colinfo, count) = $lb(objKey) 
      s count = $i(count) 
    }
  } 
  s parminfo = "" // 注释3
  s idinfo = "" // 注释4
  s qHandle = qHandle.%GetIterator() // 注释5
  q $$$OK
}
  • 注释1代码,初始化colinfo数组,将obj赋值qHandle.%GetIterator()迭代器对象。
  • 注释2代码,遍历Json对象获取Key,并通过$li给colinfo赋值。
  • 注释3代码,初始化parminfo,否则报错。
  • 注释4代码,初始化idinfo,否则报错。
  • 注释5代码,获取的迭代器对象

定义QueryNameFetch

ClassMethod Json2QueryFetch(ByRef qHandle As %Binary, ByRef row As %List, ByRef end As %Integer = 0) As %Status [ PlaceAfter = Json2QueryExecute ]
{
    s iter = qHandle
    q:($g(iter) = "") $$$OK
    if iter.%GetNext(.key, .value) { // 注释1
    s row = ""
      s obj = value.%GetIterator()
      while obj.%GetNext(.objKey, .objValue) { // 注释2
      if ( $g(row) = "" ) {
        s row = $lb(objValue)
      } else {
        s row = row _ $lb(objValue)
      }
      }
      s end = 0
    } else {
    s row = "" 
    s end = 1 // 注释3
  }
    q $$$OK
}
  • 注释1代码,获取当前迭代器Json数据行。
  • 注释2代码,遍历当前Json对象并把value与row进行$lb串联。
  • 注释3代码,如果没有数据设置end为1表示遍历结束。

定义QueryNameClose

ClassMethod Json2QueryClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = Json2QueryFetch ]
{
    s qHandle = "" // 注释1
    q $$$OK
}
  • 注释1代码,将对象qHandle清空。

注:其实M有相关回收机制,实际上Close方法不声明也可以。


调用Json2Query方法

USER>d ##class(%ResultSet).RunQuery("M.Query","Json2Query","M.Query","QueryDrives","0","D")
 
type:drive:
D:D::
D:E::
D:F::
D:G::

USER>d ##class(%ResultSet).RunQuery("M.Query","Json2Query","M.Query","QueryDrives","1","D")
 
type:drive:
D:D:\:
D:E:\:
D:F:\:
D:G:\:

通过Select Sql语句动态生成Query


定义QueryName

Query Sql2Query(sql As %String, mode As %String = 1) As %Query
{
}
  • sql - 表述需要写入SQL语句的变量。
  • mode- 显示数据格式类型。
  • 0 - 逻辑格式
  • 1 - OBDC 格式
  • 2 - 显示格式

定义QueryNameExecute

ClassMethod Sql2QueryExecute(ByRef qHandle As %Binary, sql As %String, mode As %String = 1) As %Status
{
  s sqlStatement = ##class(%SQL.Statement).%New()
    s sqlStatement.%SelectMode = mode // 注释1
    s sqlStatus = sqlStatement.%Prepare(.sql) // 注释2
    q:$$$ISERR(sqlStatus) sqlStatus
    s sqlResult = sqlStatement.%Execute() 
  s stateType = sqlStatement.%Metadata.statementType
  q:('stateType = 1 ) $$$ERROR($$$GeneralError, "不是select语句") // 注释3
  s qHandle = {}
  s qHandle.sqlResult = sqlResult // 注释4
  s qHandle.sqlStatement = sqlStatement 
    q $$$OK
}
  • 注释1代码,设置SQL的数据显示格式。
  • 注释2代码,传入SQL语句得到sqlStatement与sqlResult对象。
  • 注释3代码,传入的SQL非Select语句,抛出错误信息。
  • 注释4代码,将qHandle传入两个对象分别是sqlResult、sqlStatement。
  • sqlResult用于遍历数据使用。
  • sqlStatement用于得到数据列头信息。

定义QueryNameGetInfo

ClassMethod Sql2QueryGetInfo(ByRef colinfo As %List, ByRef parminfo As %List, ByRef idinfo As %List, ByRef qHandle As %Binary, extoption As %Integer = 0, extinfo As %List) As %Status
{
  s colinfo = $lb()
  s sqlStatement = qHandle.sqlStatement // 注释1
  s count = 1
    for i = 1 : 1 : sqlStatement.%Metadata.columnCount {  
    s data = sqlStatement.%Metadata.columns.GetAt(i).label
    s $li(colinfo, count) = $lb(data) // 注释2
    s count = $i(count)
  }
  s parminfo = ""
  s idinfo = ""
  q $$$OK
}
  • 注释1代码,通过qHandle得到sqlStatement对象。
  • 注释2代码,给colinfo列表进行循环赋值列头信息,

定义QueryNameFetch

ClassMethod Sql2QueryFetch(ByRef qHandle As %Binary, ByRef row As %List, ByRef end As %Integer = 0) As %Status [ PlaceAfter = Sql2QueryExecute ]
{
  s sqlStatement = qHandle.sqlStatement // 注释1
  s sqlResult =  qHandle.sqlResult 
  s colCount = sqlResult.%ResultColumnCount // 注释2
    if (sqlResult.%Next()) {
        for i = 1 : 1 : colCount{
            s val = sqlResult.%GetData(i)
      if ( $g(row) = "" ) { // 注释3
        s row = $lb(val)
      } else {
        s row = row _ $lb(val)
      }
        }
        s end = 0 
    } else {
     s row = ""
     s end = 1
  }
  s qHandle.sqlResult = sqlResult // 注释4
    q $$$OK
}
  • 注释1代码,通过qHandle得到sqlStatement、sqlResult对象。
  • 注释2代码,得到列数,相当于得到一行数据有多少项。
  • 注释3代码,遍历数据给row赋值。
  • 注释4代码,将qHandle.sqlResult对象,赋值给循环当前对象。

定义QueryNameClose

此处省略。

注:其实M有相关回收机制,实际上Close方法不声明也可以。


调用Sql2Query方法

USER>d ##class(%ResultSet).RunQuery("M.Query","Sql2Query","select * from M_T.Person", 1)
 
id:MT_Age:MT_Name:MT_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:
...
100:24:Nathanson,Jocelyn A.:147578:
USER>d ##class(%ResultSet).RunQuery("M.Query","Sql2Query","select ID,MT_Name from M_T.Person")
 
id:MT_Name:
1:yaoxin:
2:yx:
3:Umansky,Josephine Q.:
4:Pape,Ted F.:
5:Russell,Howard T.:
6:Xenia,Ashley U.:
7:Rotterman,Martin O.:
...
100:Nathanson,Jocelyn A.:
USER>d ##class(%ResultSet).RunQuery("M.Query","Sql2Query","select top 10 ID as id from M_T.Person")
 
id:
1:
2:
3:
4:
5:
6:
7:
8:
9:
11:

通过Query生成动态Query


定义QueryName

Query Query2Query(className As %String, queryName As %String, arg...) As %Query
{
}
  • className - 类名。
  • queryName - 需要执行的Query方法名称。
  • arg... - 需要执行的Query方法参数。

定义QueryNameExecute

ClassMethod Query2QueryExecute(ByRef qHandle As %Binary, className As %String, queryName As %String, arg...) As %Status
{
  s sqlStatement = ##class(%SQL.Statement).%New()
  s sqlStatus = sqlStatement.%PrepareClassQuery(className, queryName)
    q:$$$ISERR(sqlStatus) sqlStatus
    s sqlResult = sqlStatement.%Execute() 
  s qHandle = {}
  s qHandle.sqlResult = sqlResult
  s qHandle.sqlStatement = sqlStatement
    q $$$OK
}
  • 与Sql2Query类似。

定义QueryNameGetInfo

ClassMethod Query2QueryGetInfo(ByRef colinfo As %List, ByRef parminfo As %List, ByRef idinfo As %List, ByRef qHandle As %Binary, extoption As %Integer = 0, extinfo As %List) As %Status
{
  s colinfo = $lb()
  s sqlStatement = qHandle.sqlStatement
  s count = 1
    s column = ""
    for {
    s column = $o(sqlStatement.%Metadata.columnIndex(column)) 
    q:(column = "")
    s data = sqlStatement.%Metadata.columnIndex(column)
    s $li(colinfo, count) = $lb($lg(data, 2))
    s count = $i(count)
  }
  s parminfo = ""
  s idinfo = ""
  q $$$OK
}
  • 与Sql2Query类似。

定义QueryNameFetch

ClassMethod Query2QueryFetch(ByRef qHandle As %Binary, ByRef row As %List, ByRef end As %Integer = 0) As %Status [ PlaceAfter = Query2QueryExecute ]
{
  s sqlStatement = qHandle.sqlStatement
  s sqlResult =  qHandle.sqlResult
  s colCount = sqlResult.%ResultColumnCount
    if (sqlResult.%Next()) {
        for i = 1 : 1 : colCount{
            s val = sqlResult.%GetData(i)
      if ( $g(row) = "" ) {
        s row = $lb(val)
      } else {
        s row = row _ $lb(val)
      }
        }
        s end = 0 
    } else {
     s row = ""
     s end = 1
  }
  s qHandle.sqlResult = sqlResult
    q $$$OK
}
  • 与Sql2Query类似。

调用Query2Query

USER>d ##class(%ResultSet).RunQuery("M.Query","Query2Query","M.Query","QueryPersonByName")
 
age:id:MT_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`解决方案(下):https://developer.aliyun.com/article/1516552

相关文章
|
3月前
|
机器学习/深度学习 Web App开发 编解码
2026 年 8 月大模型的三重跃迁
8月1—3日,国产大模型密集突破:通义千问Qwen3.8-Max以2.4T稀疏MoE+1M上下文实现高效推理;MiniMax开源全模态视频模型H3,支持2K/15秒带声视频生成;DeepSeek V4-Flash显著提升Agent能力。三大进展分别指向参数效率、长程自治与多模态生产,标志着大模型正从“辅助工具”迈向“端到端自主交付”。
2644 1
2026 年 8 月大模型的三重跃迁
|
机器学习/深度学习 人工智能 自然语言处理
图解机器学习 | GBDT模型详解
GBDT是一种迭代的决策树算法,将决策树与集成思想进行了有效的结合。本文讲解GBDT算法的Boosting核心思想、训练过程、优缺点、与随机森林的对比、以及Python代码实现。
10116 2
图解机器学习 | GBDT模型详解
|
4月前
|
人工智能 前端开发 小程序
AI 编程工具排名 2026:7 款主流横评(国产 + 海外实测)
AI 编程工具有哪些?哪个 AI 写代码最强?2026 年 AI 编程工具排名横评:Cursor、Bolt.new、Lovable、v0、秒悟 Meoo、通义灵码。从场景适配度、价格、商用合规、中文支持 6 个维度实测。
12629 0
|
3月前
|
架构师 Cloud Native Devops
软考架构师历年真题合集与备考指南_260801
本资料汇集2009–2024年软考系统架构师全科真题(综合知识+案例+论文)及详细解析,PDF/Word混合格式。涵盖职称评定、技能提升、求职加分等实用价值,附备考策略与刷题建议,助力高效通关。(238字)
656 0
|
5月前
|
人工智能 自然语言处理 安全
QoderWork使用全解:零基础上手到高阶应用,打造专属AI工作助手
QoderWork是一款运行在本地桌面的AI智能体助手,由阿里云旗下Qoder团队打造,核心定位是替代传统聊天式AI,以自主执行多步骤任务的方式,成为用户身边的“AI实习生”,覆盖文件管理、数据处理、文档生成、跨应用协作等全场景工作需求。从零基础入门到深度定制,再到打造专属工作流,这套指南将带你全面掌握QoderWork,让它从简单工具升级为全能工作搭档。
771 4
|
10月前
|
传感器 运维 算法
数字孪生项目的开发
数字孪生项目融合物理世界与虚拟空间,涵盖需求规划、高精度建模、数据集成、智能分析及部署运维五大阶段,结合三维引擎与实时数据技术,实现设备、工厂乃至城市的可视化监控、预测性维护与智能决策,推动工业与城市数字化转型。#数字孪生 #WebGL开发 #软件外包公司
|
4月前
|
缓存 安全 网络安全
Codex 的 config.toml 为什么“语法正确但不生效”:配置来源与项目级限制排查
Codex 的 config.toml 语法正确却不生效,常见原因不是缓存,而是配置来源、运行环境、profile 或项目级字段限制。本文用故障矩阵和最小对照实验定位问题,并给出安全回滚顺序。
979 0
|
7月前
|
JSON API PHP
天气预报-获取全国天气预警数据API接口教程
该接口由接口盒子提供,免费获取全国实时气象局天气预警数据(暴雨、大风、雷电等),支持分页查询、完整行政区划及多语言调用示例,含详细字段说明与安全授权机制。
2609 0
|
11月前
|
人工智能 安全 算法
【云故事探索】NO.18:易点天下:以全栈AI营销能力引领全球增长新周期,阿里云“全球一张网”筑牢中国企业出海底座
位于西安的易点天下,以算法与数据驱动,助力中国品牌出海。自2011年成立以来,业务覆盖全球220+国家,通过AIGC、Agentic AI等技术,携手阿里云构建智能营销全链路,推动跨境电商、新能源等领域全球化布局,成为中国企业走向世界的重要推手。
|
UED
【HarmonyOS——ArkTS语言】计算器的实现【合集】
【ArkTS语言-HarmonyOS】计算器的实现【合集】组件,点击等号后计算函数高效解析表达式并给出准确结果,达成核心功能要求。错误提示不够详尽,难以助力用户快速定位输入错误;响应式设计不足,在不同屏幕规格下适配性差。总体而言,本次实验已成功构建起基本功能框架,后续将针对上述问题深入探究优化方案,不断打磨细节,在完善计算器功能与提升用户体验的道路上持续精进,进而提升自身编程与应用开发的综合能力水平。利用按钮组件顺利完成布局设计,数字、运算符及功能按钮排列有序,操作逻辑清晰直观。
902 2